From 8a29c5293aa7a0bb3c69cd91affd7083f40b5f43 Mon Sep 17 00:00:00 2001 From: jzxc95 <907297917@qq.com> Date: Thu, 8 Dec 2022 14:00:51 +0800 Subject: [PATCH] Import Upstream version 3.20.1.17 --- AUTHORS | 1 + COPYING | 674 +++++ README.md | 189 ++ debian/changelog | 1162 +++++++++ debian/compat | 1 + debian/control | 48 + debian/copyright | 25 + debian/kylin-nm.manpages | 1 + debian/kylin-nm.postinst | 14 + debian/kylin-nm.preinst | 9 + debian/rules | 34 + debian/source/format | 1 + debian/watch | 2 + kylin-nm.pro | 14 + man/kylin-nm.1 | 20 + nmqrc.qrc | 133 + plugins/component/AddBtn/addnetbtn.cpp | 110 + plugins/component/AddBtn/addnetbtn.h | 46 + plugins/component/AddBtn/grayinfobutton.cpp | 33 + plugins/component/AddBtn/grayinfobutton.h | 34 + plugins/component/DrownLabel/drownlabel.cpp | 55 + plugins/component/DrownLabel/drownlabel.h | 46 + plugins/component/InfoButton/infobutton.cpp | 124 + plugins/component/InfoButton/infobutton.h | 54 + .../component/SwitchButton/switchbutton.cpp | 327 +++ plugins/component/SwitchButton/switchbutton.h | 121 + plugins/component/addbtn.pri | 11 + plugins/component/drownlabel.pri | 9 + plugins/component/infobutton.pri | 9 + plugins/component/switchbutton.pri | 8 + plugins/mobilehotspot/blacklistitem.cpp | 70 + plugins/mobilehotspot/blacklistitem.h | 52 + plugins/mobilehotspot/blacklistpage.cpp | 200 ++ plugins/mobilehotspot/blacklistpage.h | 73 + plugins/mobilehotspot/connectdevlistitem.cpp | 70 + plugins/mobilehotspot/connectdevlistitem.h | 52 + plugins/mobilehotspot/connectdevpage.cpp | 191 ++ plugins/mobilehotspot/connectdevpage.h | 81 + plugins/mobilehotspot/mobilehotspot.cpp | 155 ++ plugins/mobilehotspot/mobilehotspot.h | 78 + plugins/mobilehotspot/mobilehotspot.pro | 52 + plugins/mobilehotspot/mobilehotspotwidget.cpp | 888 +++++++ plugins/mobilehotspot/mobilehotspotwidget.h | 163 ++ plugins/mobilehotspot/translations/bo.qm | 1 + plugins/mobilehotspot/translations/bo.ts | 136 + plugins/mobilehotspot/translations/bo_CN.qm | Bin 0 -> 2616 bytes plugins/mobilehotspot/translations/bo_CN.ts | 140 + plugins/mobilehotspot/translations/tr.qm | 1 + plugins/mobilehotspot/translations/tr.ts | 136 + plugins/mobilehotspot/translations/zh_CN.qm | Bin 0 -> 1698 bytes plugins/mobilehotspot/translations/zh_CN.ts | 140 + plugins/netconnect/deviceframe.cpp | 72 + plugins/netconnect/deviceframe.h | 58 + plugins/netconnect/itemframe.cpp | 61 + plugins/netconnect/itemframe.h | 51 + plugins/netconnect/lanitem.cpp | 106 + plugins/netconnect/lanitem.h | 71 + plugins/netconnect/netconnect.cpp | 898 +++++++ plugins/netconnect/netconnect.h | 159 ++ plugins/netconnect/netconnect.pro | 54 + plugins/netconnect/netconnect.ui | 244 ++ plugins/netconnect/translations/bo.qm | 1 + plugins/netconnect/translations/bo.ts | 66 + plugins/netconnect/translations/bo_CN.qm | Bin 0 -> 1089 bytes plugins/netconnect/translations/bo_CN.ts | 66 + plugins/netconnect/translations/tr.qm | 1 + plugins/netconnect/translations/tr.ts | 66 + plugins/netconnect/translations/zh_CN.qm | Bin 0 -> 661 bytes plugins/netconnect/translations/zh_CN.ts | 66 + plugins/plugin.pro | 6 + plugins/proxy/applistwidget.cpp | 138 + plugins/proxy/applistwidget.h | 60 + plugins/proxy/aptinfo.h | 32 + plugins/proxy/aptproxydialog.cpp | 127 + plugins/proxy/aptproxydialog.h | 38 + plugins/proxy/certificationdialog.h | 31 + plugins/proxy/certificationdialog.ui | 342 +++ plugins/proxy/proxy.cpp | 1367 ++++++++++ plugins/proxy/proxy.h | 285 ++ plugins/proxy/proxy.pro | 52 + plugins/proxy/translations/bo_CN.qm | Bin 0 -> 3755 bytes plugins/proxy/translations/bo_CN.ts | 227 ++ plugins/proxy/translations/tr.ts | 215 ++ plugins/proxy/translations/zh_CN.qm | Bin 0 -> 2357 bytes plugins/proxy/translations/zh_CN.ts | 215 ++ plugins/wlanconnect/deviceframe.cpp | 67 + plugins/wlanconnect/deviceframe.h | 49 + plugins/wlanconnect/itemframe.cpp | 82 + plugins/wlanconnect/itemframe.h | 54 + plugins/wlanconnect/translations/bo.qm | 1 + plugins/wlanconnect/translations/bo.ts | 73 + plugins/wlanconnect/translations/bo_CN.qm | Bin 0 -> 1046 bytes plugins/wlanconnect/translations/bo_CN.ts | 73 + plugins/wlanconnect/translations/tr.qm | 1 + plugins/wlanconnect/translations/tr.ts | 73 + plugins/wlanconnect/translations/zh_CN.qm | Bin 0 -> 664 bytes plugins/wlanconnect/translations/zh_CN.ts | 73 + plugins/wlanconnect/wlanconnect.cpp | 1101 ++++++++ plugins/wlanconnect/wlanconnect.h | 195 ++ plugins/wlanconnect/wlanconnect.pro | 54 + plugins/wlanconnect/wlanconnect.ui | 192 ++ plugins/wlanconnect/wlanitem.cpp | 129 + plugins/wlanconnect/wlanitem.h | 72 + res.qrc | 1 + res/g/close_black.png | Bin 0 -> 205 bytes res/g/close_white.png | Bin 0 -> 152 bytes res/g/down_arrow.png | Bin 0 -> 113 bytes res/h/hide-pwd.png | Bin 0 -> 1452 bytes res/h/no-pwd-wifi.png | Bin 0 -> 1643 bytes res/h/right-pwd.png | Bin 0 -> 1398 bytes res/h/show-pwd.png | Bin 0 -> 1289 bytes res/hw/wifi-full-pwd.png | Bin 0 -> 1806 bytes res/hw/wifi-full.png | Bin 0 -> 557 bytes res/hw/wifi-high-pwd.png | Bin 0 -> 682 bytes res/hw/wifi-high.png | Bin 0 -> 605 bytes res/hw/wifi-low-pwd.png | Bin 0 -> 651 bytes res/hw/wifi-low.png | Bin 0 -> 589 bytes res/hw/wifi-medium-pwd.png | Bin 0 -> 663 bytes res/hw/wifi-medium.png | Bin 0 -> 606 bytes res/hw/wifi-none-pwd.png | Bin 0 -> 634 bytes res/hw/wifi-none.png | Bin 0 -> 565 bytes res/hw/wifi6+-full-pwd.png | Bin 0 -> 737 bytes res/hw/wifi6+-full.png | Bin 0 -> 665 bytes res/hw/wifi6+-high-pwd.png | Bin 0 -> 781 bytes res/hw/wifi6+-high.png | Bin 0 -> 705 bytes res/hw/wifi6+-low-pwd.png | Bin 0 -> 780 bytes res/hw/wifi6+-low.png | Bin 0 -> 704 bytes res/hw/wifi6+-medium-pwd.png | Bin 0 -> 781 bytes res/hw/wifi6+-medium.png | Bin 0 -> 712 bytes res/hw/wifi6+-none-pwd.png | Bin 0 -> 765 bytes res/hw/wifi6+-none.png | Bin 0 -> 690 bytes res/hw/wifi6-full-pwd.png | Bin 0 -> 762 bytes res/hw/wifi6-full.png | Bin 0 -> 690 bytes res/hw/wifi6-high-pwd.png | Bin 0 -> 803 bytes res/hw/wifi6-high.png | Bin 0 -> 733 bytes res/hw/wifi6-low-pwd.png | Bin 0 -> 806 bytes res/hw/wifi6-low.png | Bin 0 -> 755 bytes res/hw/wifi6-medium-pwd.png | Bin 0 -> 812 bytes res/hw/wifi6-medium.png | Bin 0 -> 742 bytes res/hw/wifi6-none-pwd.png | Bin 0 -> 789 bytes res/hw/wifi6-none.png | Bin 0 -> 718 bytes res/l/network-offline.png | Bin 0 -> 506 bytes res/l/network-offline.svg | 23 + res/l/network-online.png | Bin 0 -> 406 bytes res/l/network-online.svg | 1 + res/s/conning-a/1.png | Bin 0 -> 351 bytes res/s/conning-a/2.png | Bin 0 -> 3170 bytes res/s/conning-a/3.png | Bin 0 -> 349 bytes res/s/conning-a/4.png | Bin 0 -> 3180 bytes res/s/conning-a/5.png | Bin 0 -> 355 bytes res/s/conning-a/6.png | Bin 0 -> 3173 bytes res/s/conning-a/7.png | Bin 0 -> 359 bytes res/s/conning-a/8.png | Bin 0 -> 3201 bytes res/s/conning-b/1.png | Bin 0 -> 7242 bytes res/s/conning-b/10.png | Bin 0 -> 7873 bytes res/s/conning-b/11.png | Bin 0 -> 7879 bytes res/s/conning-b/12.png | Bin 0 -> 7847 bytes res/s/conning-b/2.png | Bin 0 -> 7844 bytes res/s/conning-b/3.png | Bin 0 -> 7820 bytes res/s/conning-b/4.png | Bin 0 -> 7887 bytes res/s/conning-b/5.png | Bin 0 -> 7927 bytes res/s/conning-b/6.png | Bin 0 -> 7850 bytes res/s/conning-b/7.png | Bin 0 -> 7340 bytes res/s/conning-b/8.png | Bin 0 -> 7833 bytes res/s/conning-b/9.png | Bin 0 -> 7867 bytes res/s/conning-s/1.png | Bin 0 -> 652 bytes res/s/conning-s/10.png | Bin 0 -> 627 bytes res/s/conning-s/11.png | Bin 0 -> 646 bytes res/s/conning-s/12.png | Bin 0 -> 623 bytes res/s/conning-s/1x/1.png | Bin 0 -> 354 bytes res/s/conning-s/1x/10.png | Bin 0 -> 355 bytes res/s/conning-s/1x/11.png | Bin 0 -> 345 bytes res/s/conning-s/1x/12.png | Bin 0 -> 364 bytes res/s/conning-s/1x/2.png | Bin 0 -> 376 bytes res/s/conning-s/1x/3.png | Bin 0 -> 367 bytes res/s/conning-s/1x/4.png | Bin 0 -> 405 bytes res/s/conning-s/1x/5.png | Bin 0 -> 411 bytes res/s/conning-s/1x/6.png | Bin 0 -> 406 bytes res/s/conning-s/1x/7.png | Bin 0 -> 381 bytes res/s/conning-s/1x/8.png | Bin 0 -> 362 bytes res/s/conning-s/1x/9.png | Bin 0 -> 354 bytes res/s/conning-s/2.png | Bin 0 -> 709 bytes res/s/conning-s/3.png | Bin 0 -> 686 bytes res/s/conning-s/4.png | Bin 0 -> 769 bytes res/s/conning-s/5.png | Bin 0 -> 787 bytes res/s/conning-s/6.png | Bin 0 -> 673 bytes res/s/conning-s/7.png | Bin 0 -> 736 bytes res/s/conning-s/8.png | Bin 0 -> 664 bytes res/s/conning-s/9.png | Bin 0 -> 613 bytes res/s/rescan/1.png | Bin 0 -> 15281 bytes res/s/rescan/10.png | Bin 0 -> 15390 bytes res/s/rescan/11.png | Bin 0 -> 15383 bytes res/s/rescan/12.png | Bin 0 -> 15316 bytes res/s/rescan/2.png | Bin 0 -> 15386 bytes res/s/rescan/3.png | Bin 0 -> 15391 bytes res/s/rescan/4.png | Bin 0 -> 15397 bytes res/s/rescan/5.png | Bin 0 -> 15381 bytes res/s/rescan/6.png | Bin 0 -> 15393 bytes res/s/rescan/7.png | Bin 0 -> 15271 bytes res/s/rescan/8.png | Bin 0 -> 15309 bytes res/s/rescan/9.png | Bin 0 -> 15391 bytes res/w/wifi-full-pwd.png | Bin 0 -> 1806 bytes res/w/wifi-full.png | Bin 0 -> 557 bytes res/w/wifi-high-pwd.png | Bin 0 -> 682 bytes res/w/wifi-high.png | Bin 0 -> 605 bytes res/w/wifi-low-pwd.png | Bin 0 -> 651 bytes res/w/wifi-low.png | Bin 0 -> 589 bytes res/w/wifi-medium-pwd.png | Bin 0 -> 663 bytes res/w/wifi-medium.png | Bin 0 -> 606 bytes res/w/wifi-none-pwd.png | Bin 0 -> 634 bytes res/w/wifi-none.png | Bin 0 -> 565 bytes res/w/wifi6+-full-pwd.png | Bin 0 -> 784 bytes res/w/wifi6+-full.png | Bin 0 -> 732 bytes res/w/wifi6+-high-pwd.png | Bin 0 -> 830 bytes res/w/wifi6+-high.png | Bin 0 -> 787 bytes res/w/wifi6+-low-pwd.png | Bin 0 -> 806 bytes res/w/wifi6+-low.png | Bin 0 -> 775 bytes res/w/wifi6+-medium-pwd.png | Bin 0 -> 833 bytes res/w/wifi6+-medium.png | Bin 0 -> 787 bytes res/w/wifi6+-meidum-pwd.png | Bin 0 -> 828 bytes res/w/wifi6+-none.png | Bin 0 -> 759 bytes res/w/wifi6-full-pwd.png | Bin 0 -> 761 bytes res/w/wifi6-full.png | Bin 0 -> 711 bytes res/w/wifi6-high-pwd.png | Bin 0 -> 812 bytes res/w/wifi6-high.png | Bin 0 -> 765 bytes res/w/wifi6-low-pwd.png | Bin 0 -> 804 bytes res/w/wifi6-low.png | Bin 0 -> 755 bytes res/w/wifi6-medium-pwd.png | Bin 0 -> 814 bytes res/w/wifi6-medium.png | Bin 0 -> 765 bytes res/w/wifi6-none-pwd.png | Bin 0 -> 783 bytes res/w/wifi6-none.png | Bin 0 -> 738 bytes res/x/control.svg | 15 + res/x/fly-mode-off.svg | 19 + res/x/fly-mode-on.svg | 14 + res/x/hot-spot-off.svg | 22 + res/x/hot-spot-on.svg | 17 + res/x/load-down.png | Bin 0 -> 192 bytes res/x/load-up.png | Bin 0 -> 194 bytes res/x/net-list-bg.svg | 16 + res/x/setup.png | Bin 0 -> 2152 bytes res/x/wifi-list-bg.svg | 15 + src/backend/backend.pri | 22 + src/backend/dbus-interface/dbus-interface.pri | 46 + .../dbus-interface/gsystem-local-alloc.h | 207 ++ .../kyenterpricesettinginfo.cpp | 195 ++ .../dbus-interface/kyenterpricesettinginfo.h | 165 ++ .../kylinactiveconnectresource.cpp | 749 ++++++ .../kylinactiveconnectresource.h | 94 + src/backend/dbus-interface/kylinagent.c | 836 ++++++ src/backend/dbus-interface/kylinagent.h | 79 + .../dbus-interface/kylinagentinterface.c | 428 +++ .../dbus-interface/kylinagentinterface.h | 29 + .../dbus-interface/kylinapconnectitem.cpp | 38 + .../dbus-interface/kylinapconnectitem.h | 44 + .../kylinbluetoothconnectitem.cpp | 48 + .../kylinbluetoothconnectitem.h | 52 + .../dbus-interface/kylinconnectitem.cpp | 54 + src/backend/dbus-interface/kylinconnectitem.h | 50 + .../dbus-interface/kylinconnectoperation.cpp | 248 ++ .../dbus-interface/kylinconnectoperation.h | 63 + .../dbus-interface/kylinconnectresource.cpp | 827 ++++++ .../dbus-interface/kylinconnectresource.h | 91 + .../dbus-interface/kylinconnectsetting.cpp | 133 + .../dbus-interface/kylinconnectsetting.h | 72 + .../kylinnetworkdeviceresource.cpp | 430 +++ .../kylinnetworkdeviceresource.h | 83 + .../kylinnetworkresourcemanager.cpp | 1088 ++++++++ .../kylinnetworkresourcemanager.h | 218 ++ src/backend/dbus-interface/kylinutil.cpp | 219 ++ src/backend/dbus-interface/kylinutil.h | 42 + .../dbus-interface/kylinvpnconnectitem.cpp | 42 + .../dbus-interface/kylinvpnconnectitem.h | 49 + src/backend/dbus-interface/kylinvpnrequest.c | 762 ++++++ src/backend/dbus-interface/kylinvpnrequest.h | 49 + .../kylinwiredconnectoperation.cpp | 316 +++ .../kylinwiredconnectoperation.h | 62 + .../kywirelessconnectoperation.cpp | 1077 ++++++++ .../kywirelessconnectoperation.h | 159 ++ .../dbus-interface/kywirelessnetitem.cpp | 223 ++ .../dbus-interface/kywirelessnetitem.h | 67 + .../dbus-interface/kywirelessnetresource.cpp | 784 ++++++ .../dbus-interface/kywirelessnetresource.h | 96 + .../dbus-interface/nm-macros-internal.h | 1310 ++++++++++ src/backend/dbusadaptor.cpp | 279 ++ src/backend/dbusadaptor.h | 128 + src/backend/hotspot/dlghotspotcreate.cpp | 153 ++ src/backend/hotspot/dlghotspotcreate.h | 69 + src/backend/hotspot/dlghotspotcreate.ui | 169 ++ src/backend/hotspot/hotspot.pri | 11 + src/backend/kylinarping.h | 120 + src/backend/kylinipv4arping.cpp | 451 ++++ src/backend/kylinipv4arping.h | 107 + src/backend/kylinipv6arping.cpp | 424 +++ src/backend/kylinipv6arping.h | 128 + src/backend/sysdbusregister.cpp | 83 + src/backend/sysdbusregister.h | 57 + src/backend/utils.cpp | 151 ++ src/backend/utils.h | 112 + src/backend/wifi-auth-thread.cpp | 72 + src/backend/wifi-auth-thread.h | 44 + src/frontend/customstyle.cpp | 171 ++ src/frontend/customstyle.h | 66 + .../enterprise-wlan/enterprise-wlan.pri | 9 + .../enterprise-wlan/enterprisewlandialog.cpp | 291 +++ .../enterprise-wlan/enterprisewlandialog.h | 92 + src/frontend/frontend.pri | 24 + src/frontend/list-items/lanlistitem.cpp | 281 ++ src/frontend/list-items/lanlistitem.h | 71 + src/frontend/list-items/list-items.pri | 18 + src/frontend/list-items/listitem.cpp | 315 +++ src/frontend/list-items/listitem.h | 126 + src/frontend/list-items/oneconnform.ui | 302 +++ src/frontend/list-items/onelancform.ui | 254 ++ src/frontend/list-items/wlanlistitem.cpp | 725 +++++ src/frontend/list-items/wlanlistitem.h | 142 + src/frontend/list-items/wlanmoreitem.cpp | 45 + src/frontend/list-items/wlanmoreitem.h | 45 + src/frontend/mainwindow.cpp | 902 +++++++ src/frontend/mainwindow.h | 217 ++ src/frontend/netdetails/configpage.cpp | 124 + src/frontend/netdetails/configpage.h | 66 + src/frontend/netdetails/coninfo.h | 264 ++ src/frontend/netdetails/creatnetpage.cpp | 246 ++ src/frontend/netdetails/creatnetpage.h | 81 + src/frontend/netdetails/customtabstyle.cpp | 92 + src/frontend/netdetails/customtabstyle.h | 38 + src/frontend/netdetails/detailpage.cpp | 376 +++ src/frontend/netdetails/detailpage.h | 123 + src/frontend/netdetails/detailwidget.cpp | 107 + src/frontend/netdetails/detailwidget.h | 63 + src/frontend/netdetails/ipv4page.cpp | 460 ++++ src/frontend/netdetails/ipv4page.h | 111 + src/frontend/netdetails/ipv6page.cpp | 435 +++ src/frontend/netdetails/ipv6page.h | 111 + .../netdetails/joinhiddenwifipage.cpp | 274 ++ src/frontend/netdetails/joinhiddenwifipage.h | 95 + src/frontend/netdetails/netdetail.cpp | 1210 +++++++++ src/frontend/netdetails/netdetail.h | 206 ++ src/frontend/netdetails/netdetails.pri | 26 + src/frontend/netdetails/securitypage.cpp | 914 +++++++ src/frontend/netdetails/securitypage.h | 146 ++ src/frontend/networkmode/firewalldialog.cpp | 128 + src/frontend/networkmode/firewalldialog.h | 74 + src/frontend/networkmode/networkmode.pri | 10 + .../networkmode/networkmodeconfig.cpp | 90 + src/frontend/networkmode/networkmodeconfig.h | 46 + src/frontend/tab-pages/lanpage.cpp | 1294 +++++++++ src/frontend/tab-pages/lanpage.h | 158 ++ src/frontend/tab-pages/tab-pages.pri | 12 + src/frontend/tab-pages/tabpage.cpp | 458 ++++ src/frontend/tab-pages/tabpage.h | 174 ++ src/frontend/tab-pages/wlanpage.cpp | 1578 +++++++++++ src/frontend/tab-pages/wlanpage.h | 237 ++ src/frontend/tools/divider.cpp | 42 + src/frontend/tools/divider.h | 34 + src/frontend/tools/infobutton.cpp | 119 + src/frontend/tools/infobutton.h | 50 + src/frontend/tools/kylable.cpp | 117 + src/frontend/tools/kylable.h | 52 + src/frontend/tools/loadingdiv.cpp | 78 + src/frontend/tools/loadingdiv.h | 51 + src/frontend/tools/radioitembutton.cpp | 285 ++ src/frontend/tools/radioitembutton.h | 82 + src/frontend/tools/switchbutton.cpp | 171 ++ src/frontend/tools/switchbutton.h | 59 + src/frontend/tools/tools.pri | 18 + src/frontend/wificonfigdialog.cpp | 218 ++ src/frontend/wificonfigdialog.h | 72 + src/frontend/wificonfigdialog.ui | 140 + src/frontend/xatom/xatom-helper.cpp | 210 ++ src/frontend/xatom/xatom-helper.h | 110 + src/frontend/xatom/xatom.pri | 7 + src/kylin-nm.desktop | 18 + src/main.cpp | 175 ++ src/org.ukui.kylin-nm.switch.gschema.xml | 14 + src/singleapplication/qt-local-peer.cpp | 205 ++ src/singleapplication/qt-local-peer.h | 80 + src/singleapplication/qt-locked-file-unix.cpp | 113 + src/singleapplication/qt-locked-file.cpp | 189 ++ src/singleapplication/qt-locked-file.h | 97 + .../qt-single-application.cpp | 353 +++ src/singleapplication/qt-single-application.h | 109 + .../qt-single-application.pri | 27 + src/src.pro | 69 + src/translations/kylin-nm_bo.qm | 1 + src/translations/kylin-nm_tr.qm | Bin 0 -> 21755 bytes translations/kylin-nm_bo.qm | 1 + translations/kylin-nm_bo.ts | 962 +++++++ translations/kylin-nm_bo_CN.qm | Bin 0 -> 17666 bytes translations/kylin-nm_bo_CN.ts | 1468 +++++++++++ translations/kylin-nm_tr.qm | Bin 0 -> 2010 bytes translations/kylin-nm_tr.ts | 2324 +++++++++++++++++ translations/kylin-nm_zh_CN.qm | Bin 0 -> 11040 bytes translations/kylin-nm_zh_CN.ts | 1468 +++++++++++ 394 files changed, 51316 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 README.md create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/kylin-nm.manpages create mode 100755 debian/kylin-nm.postinst create mode 100755 debian/kylin-nm.preinst create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100644 debian/watch create mode 100644 kylin-nm.pro create mode 100644 man/kylin-nm.1 create mode 100644 nmqrc.qrc create mode 100644 plugins/component/AddBtn/addnetbtn.cpp create mode 100644 plugins/component/AddBtn/addnetbtn.h create mode 100644 plugins/component/AddBtn/grayinfobutton.cpp create mode 100644 plugins/component/AddBtn/grayinfobutton.h create mode 100644 plugins/component/DrownLabel/drownlabel.cpp create mode 100644 plugins/component/DrownLabel/drownlabel.h create mode 100644 plugins/component/InfoButton/infobutton.cpp create mode 100644 plugins/component/InfoButton/infobutton.h create mode 100644 plugins/component/SwitchButton/switchbutton.cpp create mode 100644 plugins/component/SwitchButton/switchbutton.h create mode 100644 plugins/component/addbtn.pri create mode 100644 plugins/component/drownlabel.pri create mode 100644 plugins/component/infobutton.pri create mode 100644 plugins/component/switchbutton.pri create mode 100644 plugins/mobilehotspot/blacklistitem.cpp create mode 100644 plugins/mobilehotspot/blacklistitem.h create mode 100644 plugins/mobilehotspot/blacklistpage.cpp create mode 100644 plugins/mobilehotspot/blacklistpage.h create mode 100644 plugins/mobilehotspot/connectdevlistitem.cpp create mode 100644 plugins/mobilehotspot/connectdevlistitem.h create mode 100644 plugins/mobilehotspot/connectdevpage.cpp create mode 100644 plugins/mobilehotspot/connectdevpage.h create mode 100644 plugins/mobilehotspot/mobilehotspot.cpp create mode 100644 plugins/mobilehotspot/mobilehotspot.h create mode 100644 plugins/mobilehotspot/mobilehotspot.pro create mode 100644 plugins/mobilehotspot/mobilehotspotwidget.cpp create mode 100644 plugins/mobilehotspot/mobilehotspotwidget.h create mode 100644 plugins/mobilehotspot/translations/bo.qm create mode 100644 plugins/mobilehotspot/translations/bo.ts create mode 100644 plugins/mobilehotspot/translations/bo_CN.qm create mode 100644 plugins/mobilehotspot/translations/bo_CN.ts create mode 100644 plugins/mobilehotspot/translations/tr.qm create mode 100644 plugins/mobilehotspot/translations/tr.ts create mode 100644 plugins/mobilehotspot/translations/zh_CN.qm create mode 100644 plugins/mobilehotspot/translations/zh_CN.ts create mode 100644 plugins/netconnect/deviceframe.cpp create mode 100644 plugins/netconnect/deviceframe.h create mode 100644 plugins/netconnect/itemframe.cpp create mode 100644 plugins/netconnect/itemframe.h create mode 100644 plugins/netconnect/lanitem.cpp create mode 100644 plugins/netconnect/lanitem.h create mode 100644 plugins/netconnect/netconnect.cpp create mode 100644 plugins/netconnect/netconnect.h create mode 100644 plugins/netconnect/netconnect.pro create mode 100644 plugins/netconnect/netconnect.ui create mode 100644 plugins/netconnect/translations/bo.qm create mode 100644 plugins/netconnect/translations/bo.ts create mode 100644 plugins/netconnect/translations/bo_CN.qm create mode 100644 plugins/netconnect/translations/bo_CN.ts create mode 100644 plugins/netconnect/translations/tr.qm create mode 100644 plugins/netconnect/translations/tr.ts create mode 100644 plugins/netconnect/translations/zh_CN.qm create mode 100644 plugins/netconnect/translations/zh_CN.ts create mode 100644 plugins/plugin.pro create mode 100644 plugins/proxy/applistwidget.cpp create mode 100644 plugins/proxy/applistwidget.h create mode 100644 plugins/proxy/aptinfo.h create mode 100644 plugins/proxy/aptproxydialog.cpp create mode 100644 plugins/proxy/aptproxydialog.h create mode 100644 plugins/proxy/certificationdialog.h create mode 100644 plugins/proxy/certificationdialog.ui create mode 100644 plugins/proxy/proxy.cpp create mode 100644 plugins/proxy/proxy.h create mode 100644 plugins/proxy/proxy.pro create mode 100644 plugins/proxy/translations/bo_CN.qm create mode 100644 plugins/proxy/translations/bo_CN.ts create mode 100644 plugins/proxy/translations/tr.ts create mode 100644 plugins/proxy/translations/zh_CN.qm create mode 100644 plugins/proxy/translations/zh_CN.ts create mode 100644 plugins/wlanconnect/deviceframe.cpp create mode 100644 plugins/wlanconnect/deviceframe.h create mode 100644 plugins/wlanconnect/itemframe.cpp create mode 100644 plugins/wlanconnect/itemframe.h create mode 100644 plugins/wlanconnect/translations/bo.qm create mode 100644 plugins/wlanconnect/translations/bo.ts create mode 100644 plugins/wlanconnect/translations/bo_CN.qm create mode 100644 plugins/wlanconnect/translations/bo_CN.ts create mode 100644 plugins/wlanconnect/translations/tr.qm create mode 100644 plugins/wlanconnect/translations/tr.ts create mode 100644 plugins/wlanconnect/translations/zh_CN.qm create mode 100644 plugins/wlanconnect/translations/zh_CN.ts create mode 100644 plugins/wlanconnect/wlanconnect.cpp create mode 100644 plugins/wlanconnect/wlanconnect.h create mode 100644 plugins/wlanconnect/wlanconnect.pro create mode 100644 plugins/wlanconnect/wlanconnect.ui create mode 100644 plugins/wlanconnect/wlanitem.cpp create mode 100644 plugins/wlanconnect/wlanitem.h create mode 100644 res.qrc create mode 100644 res/g/close_black.png create mode 100644 res/g/close_white.png create mode 100644 res/g/down_arrow.png create mode 100644 res/h/hide-pwd.png create mode 100644 res/h/no-pwd-wifi.png create mode 100644 res/h/right-pwd.png create mode 100644 res/h/show-pwd.png create mode 100644 res/hw/wifi-full-pwd.png create mode 100644 res/hw/wifi-full.png create mode 100644 res/hw/wifi-high-pwd.png create mode 100644 res/hw/wifi-high.png create mode 100644 res/hw/wifi-low-pwd.png create mode 100644 res/hw/wifi-low.png create mode 100644 res/hw/wifi-medium-pwd.png create mode 100644 res/hw/wifi-medium.png create mode 100644 res/hw/wifi-none-pwd.png create mode 100644 res/hw/wifi-none.png create mode 100644 res/hw/wifi6+-full-pwd.png create mode 100644 res/hw/wifi6+-full.png create mode 100644 res/hw/wifi6+-high-pwd.png create mode 100644 res/hw/wifi6+-high.png create mode 100644 res/hw/wifi6+-low-pwd.png create mode 100644 res/hw/wifi6+-low.png create mode 100644 res/hw/wifi6+-medium-pwd.png create mode 100644 res/hw/wifi6+-medium.png create mode 100644 res/hw/wifi6+-none-pwd.png create mode 100644 res/hw/wifi6+-none.png create mode 100644 res/hw/wifi6-full-pwd.png create mode 100644 res/hw/wifi6-full.png create mode 100644 res/hw/wifi6-high-pwd.png create mode 100644 res/hw/wifi6-high.png create mode 100644 res/hw/wifi6-low-pwd.png create mode 100644 res/hw/wifi6-low.png create mode 100644 res/hw/wifi6-medium-pwd.png create mode 100644 res/hw/wifi6-medium.png create mode 100644 res/hw/wifi6-none-pwd.png create mode 100644 res/hw/wifi6-none.png create mode 100644 res/l/network-offline.png create mode 100644 res/l/network-offline.svg create mode 100644 res/l/network-online.png create mode 100644 res/l/network-online.svg create mode 100644 res/s/conning-a/1.png create mode 100644 res/s/conning-a/2.png create mode 100644 res/s/conning-a/3.png create mode 100644 res/s/conning-a/4.png create mode 100644 res/s/conning-a/5.png create mode 100644 res/s/conning-a/6.png create mode 100644 res/s/conning-a/7.png create mode 100644 res/s/conning-a/8.png create mode 100644 res/s/conning-b/1.png create mode 100644 res/s/conning-b/10.png create mode 100644 res/s/conning-b/11.png create mode 100644 res/s/conning-b/12.png create mode 100644 res/s/conning-b/2.png create mode 100644 res/s/conning-b/3.png create mode 100644 res/s/conning-b/4.png create mode 100644 res/s/conning-b/5.png create mode 100644 res/s/conning-b/6.png create mode 100644 res/s/conning-b/7.png create mode 100644 res/s/conning-b/8.png create mode 100644 res/s/conning-b/9.png create mode 100644 res/s/conning-s/1.png create mode 100644 res/s/conning-s/10.png create mode 100644 res/s/conning-s/11.png create mode 100644 res/s/conning-s/12.png create mode 100644 res/s/conning-s/1x/1.png create mode 100644 res/s/conning-s/1x/10.png create mode 100644 res/s/conning-s/1x/11.png create mode 100644 res/s/conning-s/1x/12.png create mode 100644 res/s/conning-s/1x/2.png create mode 100644 res/s/conning-s/1x/3.png create mode 100644 res/s/conning-s/1x/4.png create mode 100644 res/s/conning-s/1x/5.png create mode 100644 res/s/conning-s/1x/6.png create mode 100644 res/s/conning-s/1x/7.png create mode 100644 res/s/conning-s/1x/8.png create mode 100644 res/s/conning-s/1x/9.png create mode 100644 res/s/conning-s/2.png create mode 100644 res/s/conning-s/3.png create mode 100644 res/s/conning-s/4.png create mode 100644 res/s/conning-s/5.png create mode 100644 res/s/conning-s/6.png create mode 100644 res/s/conning-s/7.png create mode 100644 res/s/conning-s/8.png create mode 100644 res/s/conning-s/9.png create mode 100644 res/s/rescan/1.png create mode 100644 res/s/rescan/10.png create mode 100644 res/s/rescan/11.png create mode 100644 res/s/rescan/12.png create mode 100644 res/s/rescan/2.png create mode 100644 res/s/rescan/3.png create mode 100644 res/s/rescan/4.png create mode 100644 res/s/rescan/5.png create mode 100644 res/s/rescan/6.png create mode 100644 res/s/rescan/7.png create mode 100644 res/s/rescan/8.png create mode 100644 res/s/rescan/9.png create mode 100644 res/w/wifi-full-pwd.png create mode 100644 res/w/wifi-full.png create mode 100644 res/w/wifi-high-pwd.png create mode 100644 res/w/wifi-high.png create mode 100644 res/w/wifi-low-pwd.png create mode 100644 res/w/wifi-low.png create mode 100644 res/w/wifi-medium-pwd.png create mode 100644 res/w/wifi-medium.png create mode 100644 res/w/wifi-none-pwd.png create mode 100644 res/w/wifi-none.png create mode 100644 res/w/wifi6+-full-pwd.png create mode 100644 res/w/wifi6+-full.png create mode 100644 res/w/wifi6+-high-pwd.png create mode 100644 res/w/wifi6+-high.png create mode 100644 res/w/wifi6+-low-pwd.png create mode 100644 res/w/wifi6+-low.png create mode 100644 res/w/wifi6+-medium-pwd.png create mode 100644 res/w/wifi6+-medium.png create mode 100644 res/w/wifi6+-meidum-pwd.png create mode 100644 res/w/wifi6+-none.png create mode 100644 res/w/wifi6-full-pwd.png create mode 100644 res/w/wifi6-full.png create mode 100644 res/w/wifi6-high-pwd.png create mode 100644 res/w/wifi6-high.png create mode 100644 res/w/wifi6-low-pwd.png create mode 100644 res/w/wifi6-low.png create mode 100644 res/w/wifi6-medium-pwd.png create mode 100644 res/w/wifi6-medium.png create mode 100644 res/w/wifi6-none-pwd.png create mode 100644 res/w/wifi6-none.png create mode 100644 res/x/control.svg create mode 100644 res/x/fly-mode-off.svg create mode 100644 res/x/fly-mode-on.svg create mode 100644 res/x/hot-spot-off.svg create mode 100644 res/x/hot-spot-on.svg create mode 100644 res/x/load-down.png create mode 100644 res/x/load-up.png create mode 100644 res/x/net-list-bg.svg create mode 100644 res/x/setup.png create mode 100644 res/x/wifi-list-bg.svg create mode 100644 src/backend/backend.pri create mode 100644 src/backend/dbus-interface/dbus-interface.pri create mode 100644 src/backend/dbus-interface/gsystem-local-alloc.h create mode 100644 src/backend/dbus-interface/kyenterpricesettinginfo.cpp create mode 100644 src/backend/dbus-interface/kyenterpricesettinginfo.h create mode 100644 src/backend/dbus-interface/kylinactiveconnectresource.cpp create mode 100644 src/backend/dbus-interface/kylinactiveconnectresource.h create mode 100644 src/backend/dbus-interface/kylinagent.c create mode 100644 src/backend/dbus-interface/kylinagent.h create mode 100644 src/backend/dbus-interface/kylinagentinterface.c create mode 100644 src/backend/dbus-interface/kylinagentinterface.h create mode 100644 src/backend/dbus-interface/kylinapconnectitem.cpp create mode 100644 src/backend/dbus-interface/kylinapconnectitem.h create mode 100644 src/backend/dbus-interface/kylinbluetoothconnectitem.cpp create mode 100644 src/backend/dbus-interface/kylinbluetoothconnectitem.h create mode 100644 src/backend/dbus-interface/kylinconnectitem.cpp create mode 100644 src/backend/dbus-interface/kylinconnectitem.h create mode 100644 src/backend/dbus-interface/kylinconnectoperation.cpp create mode 100644 src/backend/dbus-interface/kylinconnectoperation.h create mode 100644 src/backend/dbus-interface/kylinconnectresource.cpp create mode 100644 src/backend/dbus-interface/kylinconnectresource.h create mode 100644 src/backend/dbus-interface/kylinconnectsetting.cpp create mode 100644 src/backend/dbus-interface/kylinconnectsetting.h create mode 100644 src/backend/dbus-interface/kylinnetworkdeviceresource.cpp create mode 100644 src/backend/dbus-interface/kylinnetworkdeviceresource.h create mode 100644 src/backend/dbus-interface/kylinnetworkresourcemanager.cpp create mode 100644 src/backend/dbus-interface/kylinnetworkresourcemanager.h create mode 100644 src/backend/dbus-interface/kylinutil.cpp create mode 100644 src/backend/dbus-interface/kylinutil.h create mode 100644 src/backend/dbus-interface/kylinvpnconnectitem.cpp create mode 100644 src/backend/dbus-interface/kylinvpnconnectitem.h create mode 100644 src/backend/dbus-interface/kylinvpnrequest.c create mode 100644 src/backend/dbus-interface/kylinvpnrequest.h create mode 100644 src/backend/dbus-interface/kylinwiredconnectoperation.cpp create mode 100644 src/backend/dbus-interface/kylinwiredconnectoperation.h create mode 100644 src/backend/dbus-interface/kywirelessconnectoperation.cpp create mode 100644 src/backend/dbus-interface/kywirelessconnectoperation.h create mode 100644 src/backend/dbus-interface/kywirelessnetitem.cpp create mode 100644 src/backend/dbus-interface/kywirelessnetitem.h create mode 100644 src/backend/dbus-interface/kywirelessnetresource.cpp create mode 100644 src/backend/dbus-interface/kywirelessnetresource.h create mode 100644 src/backend/dbus-interface/nm-macros-internal.h create mode 100644 src/backend/dbusadaptor.cpp create mode 100644 src/backend/dbusadaptor.h create mode 100644 src/backend/hotspot/dlghotspotcreate.cpp create mode 100644 src/backend/hotspot/dlghotspotcreate.h create mode 100644 src/backend/hotspot/dlghotspotcreate.ui create mode 100644 src/backend/hotspot/hotspot.pri create mode 100644 src/backend/kylinarping.h create mode 100644 src/backend/kylinipv4arping.cpp create mode 100644 src/backend/kylinipv4arping.h create mode 100644 src/backend/kylinipv6arping.cpp create mode 100644 src/backend/kylinipv6arping.h create mode 100644 src/backend/sysdbusregister.cpp create mode 100644 src/backend/sysdbusregister.h create mode 100644 src/backend/utils.cpp create mode 100644 src/backend/utils.h create mode 100644 src/backend/wifi-auth-thread.cpp create mode 100644 src/backend/wifi-auth-thread.h create mode 100644 src/frontend/customstyle.cpp create mode 100644 src/frontend/customstyle.h create mode 100644 src/frontend/enterprise-wlan/enterprise-wlan.pri create mode 100644 src/frontend/enterprise-wlan/enterprisewlandialog.cpp create mode 100644 src/frontend/enterprise-wlan/enterprisewlandialog.h create mode 100644 src/frontend/frontend.pri create mode 100644 src/frontend/list-items/lanlistitem.cpp create mode 100644 src/frontend/list-items/lanlistitem.h create mode 100644 src/frontend/list-items/list-items.pri create mode 100644 src/frontend/list-items/listitem.cpp create mode 100644 src/frontend/list-items/listitem.h create mode 100644 src/frontend/list-items/oneconnform.ui create mode 100644 src/frontend/list-items/onelancform.ui create mode 100644 src/frontend/list-items/wlanlistitem.cpp create mode 100644 src/frontend/list-items/wlanlistitem.h create mode 100644 src/frontend/list-items/wlanmoreitem.cpp create mode 100644 src/frontend/list-items/wlanmoreitem.h create mode 100644 src/frontend/mainwindow.cpp create mode 100644 src/frontend/mainwindow.h create mode 100644 src/frontend/netdetails/configpage.cpp create mode 100644 src/frontend/netdetails/configpage.h create mode 100644 src/frontend/netdetails/coninfo.h create mode 100644 src/frontend/netdetails/creatnetpage.cpp create mode 100644 src/frontend/netdetails/creatnetpage.h create mode 100644 src/frontend/netdetails/customtabstyle.cpp create mode 100644 src/frontend/netdetails/customtabstyle.h create mode 100644 src/frontend/netdetails/detailpage.cpp create mode 100644 src/frontend/netdetails/detailpage.h create mode 100644 src/frontend/netdetails/detailwidget.cpp create mode 100644 src/frontend/netdetails/detailwidget.h create mode 100644 src/frontend/netdetails/ipv4page.cpp create mode 100644 src/frontend/netdetails/ipv4page.h create mode 100644 src/frontend/netdetails/ipv6page.cpp create mode 100644 src/frontend/netdetails/ipv6page.h create mode 100644 src/frontend/netdetails/joinhiddenwifipage.cpp create mode 100644 src/frontend/netdetails/joinhiddenwifipage.h create mode 100644 src/frontend/netdetails/netdetail.cpp create mode 100644 src/frontend/netdetails/netdetail.h create mode 100644 src/frontend/netdetails/netdetails.pri create mode 100644 src/frontend/netdetails/securitypage.cpp create mode 100644 src/frontend/netdetails/securitypage.h create mode 100644 src/frontend/networkmode/firewalldialog.cpp create mode 100644 src/frontend/networkmode/firewalldialog.h create mode 100644 src/frontend/networkmode/networkmode.pri create mode 100644 src/frontend/networkmode/networkmodeconfig.cpp create mode 100644 src/frontend/networkmode/networkmodeconfig.h create mode 100644 src/frontend/tab-pages/lanpage.cpp create mode 100644 src/frontend/tab-pages/lanpage.h create mode 100644 src/frontend/tab-pages/tab-pages.pri create mode 100644 src/frontend/tab-pages/tabpage.cpp create mode 100644 src/frontend/tab-pages/tabpage.h create mode 100644 src/frontend/tab-pages/wlanpage.cpp create mode 100644 src/frontend/tab-pages/wlanpage.h create mode 100644 src/frontend/tools/divider.cpp create mode 100644 src/frontend/tools/divider.h create mode 100644 src/frontend/tools/infobutton.cpp create mode 100644 src/frontend/tools/infobutton.h create mode 100644 src/frontend/tools/kylable.cpp create mode 100644 src/frontend/tools/kylable.h create mode 100644 src/frontend/tools/loadingdiv.cpp create mode 100644 src/frontend/tools/loadingdiv.h create mode 100644 src/frontend/tools/radioitembutton.cpp create mode 100644 src/frontend/tools/radioitembutton.h create mode 100644 src/frontend/tools/switchbutton.cpp create mode 100644 src/frontend/tools/switchbutton.h create mode 100644 src/frontend/tools/tools.pri create mode 100644 src/frontend/wificonfigdialog.cpp create mode 100644 src/frontend/wificonfigdialog.h create mode 100644 src/frontend/wificonfigdialog.ui create mode 100644 src/frontend/xatom/xatom-helper.cpp create mode 100644 src/frontend/xatom/xatom-helper.h create mode 100644 src/frontend/xatom/xatom.pri create mode 100644 src/kylin-nm.desktop create mode 100644 src/main.cpp create mode 100644 src/org.ukui.kylin-nm.switch.gschema.xml create mode 100644 src/singleapplication/qt-local-peer.cpp create mode 100644 src/singleapplication/qt-local-peer.h create mode 100644 src/singleapplication/qt-locked-file-unix.cpp create mode 100644 src/singleapplication/qt-locked-file.cpp create mode 100644 src/singleapplication/qt-locked-file.h create mode 100644 src/singleapplication/qt-single-application.cpp create mode 100644 src/singleapplication/qt-single-application.h create mode 100644 src/singleapplication/qt-single-application.pri create mode 100644 src/src.pro create mode 100644 src/translations/kylin-nm_bo.qm create mode 100644 src/translations/kylin-nm_tr.qm create mode 100644 translations/kylin-nm_bo.qm create mode 100644 translations/kylin-nm_bo.ts create mode 100644 translations/kylin-nm_bo_CN.qm create mode 100644 translations/kylin-nm_bo_CN.ts create mode 100644 translations/kylin-nm_tr.qm create mode 100644 translations/kylin-nm_tr.ts create mode 100644 translations/kylin-nm_zh_CN.qm create mode 100644 translations/kylin-nm_zh_CN.ts diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..a8b57e7b --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +shine diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 00000000..9b77fa00 --- /dev/null +++ b/README.md @@ -0,0 +1,189 @@ +## kylin-nm介绍 +### 简介 + 麒麟网络工具(kylin-network-manager,简称kylin-nm)是操作系统的网络前端,其主要功能有: + 1、托盘栏图标及右键菜单 + 查看当前网络状态 + 左键点击托盘网络图标显示kylin-nm主界面 + 右键点击托盘网络图标显示右键菜单 + 2、对有线网络的管理 + 有线网络界面管理 + 连接/断开网络 + 网线拔插 + 多有线网卡支持 + 打开或关闭有线开关 + 查看或修改无线网络基本信息 + 3、对无线网络的管理 + 切换及刷新无线界面 + 查看无线网络列表 + 连接/断开无需密码的无线网 + 连接/断开有密码类型的无线网 + 无线网卡插拔 + 多无线网卡支持 + 打开或关闭无线开关 + 查看或修改无线网络基本信息 + 4、连接隐藏无线网络 + 连接无安全性的无线网络 + 连接WPA及WPA2个人安全性的无线网络 + 连接WPA及WPA2企业安全性的无线网络 + 连接WPA3个人安全性的无线网络 + 5、窗口样式调节 + 深色与浅色窗口样式切换 + 调节网络工具窗口透明度 + 普通窗口与具有毛玻璃效果的窗口的切换 +### 运行 + 麒麟网络工具的进程为kylin-nm,默认开机自启,依赖NetworkManger +### 命令行和dbus接口 + + kylin-nm进程的命令行如下: + Usage: kylin-nm + +#### dbus接口: + DBUS类型:SESSION BUS + DBUS名称:com.kylin.network + OBJECT路径:/ + 接口名称:com.kylin.network + +#### dbus方法 + getWirelessList + 参数:无 + 返回值:QMap> + 键:网卡名称 + 值:无线网络的集合(第一项为已连接网络信息,若无连接则为"--",否则为"名称/信号强度/加密类型/Uuid/是否为本机开放热点";其余为未连接的网络信息,为"名称/信号强度/加密类型/是否为本机开放热点" + 功能:获取无线列表及每个对应无线网络的信号强度、加密类型等信息。 + + getWiredList + 参数:无 + 返回值:QMap> + 键:网卡名称 + 值:有线网络的集合("名称/UUID/对应DBUS路径"),若无已连接网络则第一项默认为"--" + 功能:获取有线列表及每个对应的有线网络的uuid及dbus路径 + + setWiredSwitchEnable(bool enable) + 参数:(bool)开启有线总开关(true)关闭有线总开关(false) + 返回值:无 + 功能:打开或关闭有线总开关 + + setWirelessSwitchEnable(bool enable) + 参数:(bool)开启无线总开关(true)关闭无线总开关(false) + 返回值:无 + 功能:打开或关闭无线总开关 + + setDeviceEnable(QString devName, bool enable) + 参数:(QString)devName 设备名称,(bool) enable 开启/关闭 + 返回值:无 + 功能:打开或关闭单个有线网卡开关 + + activateConnect(int type, QString devName, QString ssid) + 参数:根据网卡类型 参数1 0:lan 1:wlan 参数2:网卡名称 参数3:uuid/ssid + 返回值:无 + 功能:激活一个网络连接 + + deActivateConnect(int type, QString devName, QString ssid) + 参数:根据网卡类型 参数1 0:lan 1:wlan 参数2:网卡名称 参数3:uuid/ssid + 返回值:无 + 功能:断开一个网络连接 + + getDeviceListAndEnabled(int devType) + 参数:int devType 0:lan 1:wlan + 返回值:QMap + 键:设备名称 + 值:bool 开启(true)关闭 (false) + 功能:获取设备列表和启用/禁用状态 + + getWirelessDeviceCap + 返回值:QMap + 键:设备名称 + 值:int 0:不支持热点 3:支持2.4GHz 7:支持5GHz&&2.4Ghz + 功能:获取无线设备能力(2.4G/5G) + + showPropertyWidget(QString devName, QString ssid) + 参数:QString devName 设备名称 QString ssid 根据网卡类型 有线为uuid/无线为ssid + 返回值:无 + 功能:唤起对应网络连接的属性页,可以对基础信息的显示或修改 + + showCreateWiredConnectWidget(QString devName) + 参数:QString devName 有线网卡名称 + 返回值:无 + 功能:唤起新建有线连接界面 + + activeWirelessAp(const QString apName, + const QString apPassword, + const QString band, + const QString apDevice) + 参数:QString apName 热点名称 + QString apPassword 热点密码 + QString band 频带 + QString apDevice + 返回值:无 + 功能:开启移动热点 + + deactiveWirelessAp(const QString apName, const QString uuid) + 参数:QStringList(名称/密码/设备名称/状态/UUID/频带) + 返回值:无 + 功能: 断开移动热点 + + getStoredApInfo + 参数:QStringList(名称/密码/设备名称/状态/UUID/频带) + 返回值:无 + 功能:获取已保存的移动热点信息 + + getApInfoBySsid(QString devName, QString ssid) + 参数:QString devName 设备名称 QString ssid + 返回值:无 + 功能:通过名称获取已保存的移动热点信息 + + reScan() + 参数:无 + 返回值:无 + 功能:申请重新进行无线扫描 + + keyRingInit() + 参数:QString apName 热点名称 QString uuid + 返回值:无 + 功能:断开移动热点 + + keyRingClear() + 参数:无 + 返回值:无 + 功能: 断开移动热点 + + +### 原理与主要使用的技术 + kylin-nm主要与NetworkManager进行交互,通过对应的dbus信号驱动UI界面的更新。并通过提供的dbus方法来进行网络相关功能的调用。 + + 麒麟网络工具按照功能划分成两层:UI层和逻辑层。UI层实现网络资源的显示,以及用户的交互,逻辑层通过NetworkManager提供的Dbus接口,完成网络资源的管理及其配置。 +### 配置文件 + kylin-nm的配置文件保存在如下路径: + ~/.config/ukui/kylin-nm.conf 有线无线开关状态 设备状态 + org.ukui.kylin-nm.switch 对应的gsetting值 (有线无线开关状态) +### 编译 + cd kylin-nm + mkdir build + cd build + qmake .. + make + sudo make install  +### 运行命令 + ./kylin-nm +### 调试 + kylin-nm目前并采用ukui-log4qt模块的日志功能。日志默认保存在~/.log/kylin-nm.log中 + + + + + + + + + + + + + + + + + + + + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..8302371f --- /dev/null +++ b/debian/changelog @@ -0,0 +1,1162 @@ +kylin-nm (3.20.1.17-0k0.2) v101; urgency=medium + + * BUG号: + - #148578 【移动热点】开启移动热点失败 + - #147019 【安全中心】切换或者关闭无线网络后,安全中心的防火墙显示正在使用的网络不正确 + * 需求号:无 + * 其他改动: + * 影响域:安全中心防火墙显示 移动热点桌面提示信息 + + -- cxc Wed, 23 Nov 2022 14:15:54 +0800 + +kylin-nm (3.20.1.17-0k0.1) v101; urgency=medium + + * BUG号: + - #148719 【rc8走查】【托盘】【网络】loading图标不正确 + * 需求号:无 + * 其他改动: + * 影响域:托盘loading图标 + + -- zhaoshixu Fri, 18 Nov 2022 10:36:15 +0800 + +kylin-nm (3.20.1.17) v101; urgency=medium + + * BUG号: + - #145965 【hwe-base2】【HP Pro SFF 280 G9】【控制面板】移动热点界面显示异常,无法开启移动热点 + * 需求号:无 + * 其他改动:配合后端修改添加、删除黑名单接口 + * 影响域:控制面板热点管控界面 + + -- cxc Wed, 09 Nov 2022 15:09:23 +0800 + +kylin-nm (3.20.1.16) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:设计稿调整 + * 影响域:主界面UI交互 + + -- cxc Tue, 08 Nov 2022 09:09:05 +0800 + +kylin-nm (3.20.1.15) v101; urgency=medium + + * BUG号: + -#146072 【2107离线升级2209-RC8】【有线网络】升级前有线网络为打开,升级后为关闭状态 + * 需求号:无 + * 其他改动:无 + * 影响域:2107升级 + + -- zhaoshixu Mon, 07 Nov 2022 17:16:07 +0800 + +kylin-nm (3.20.1.14) v101; urgency=medium + + * BUG号: 无 + * 需求号:无 + * 其他改动:任务:主界面交互逻辑修改 + * 影响域:主界面ui交互 + + -- zhaoshixu Mon, 07 Nov 2022 09:24:17 +0800 + +kylin-nm (3.20.1.13) v101; urgency=medium + + * BUG号: 无 + * 需求号:无 + * 其他改动:任务:主界面交互逻辑修改 + * 影响域:主界面ui交互 + + -- zhaoshixu Sat, 05 Nov 2022 19:36:33 +0800 + +kylin-nm (3.20.1.12) v101; urgency=medium + + * BUG号: + -#145443 【rc8走查】【网络】半透明控件适配 + * 需求号:无 + * 其他改动:无 + * 影响域:主界面ui + + -- zhaoshixu Wed, 26 Oct 2022 16:22:32 +0800 + +kylin-nm (3.20.1.11) v101; urgency=medium + + * BUG号: + * 需求号:无 + * 其他改动:上个版本代码漏传 + * 影响域:主题深浅模式ui 控制面板网络代理翻译 + + -- zhaoshixu Mon, 24 Oct 2022 10:29:55 +0800 + +kylin-nm (3.20.1.10) v101; urgency=medium + + * BUG号: + -#144127 【设计】【网络连接】网络连接其他网络界面外观不一致 + -#140561 【网络代理】切换藏文后,APT代理未藏化,仍为英文 + * 需求号:无 + * 其他改动: + * 影响域:主题深浅模式ui 控制面板网络代理翻译 + + -- zhaoshixu Mon, 24 Oct 2022 10:09:31 +0800 + +kylin-nm (3.20.1.9) v101; urgency=medium + + * BUG号: + -#125714 【UKUI 3.20 走查】【网络】快捷键支持不完整 + * 需求号:无 + * 其他改动: + * 影响域:win+k快捷键 强调色适配 + + -- zhaoshixu Fri, 21 Oct 2022 18:51:58 +0800 + +kylin-nm (3.20.1.8) v101; urgency=medium + + * BUG号: + -#144126 【设计】【网络连接】网络属性界面寻光主题下显示外观不符 + * 需求号:无 + * 其他改动: + * 影响域:主题深浅模式ui + + -- zhaoshixu Fri, 21 Oct 2022 10:55:39 +0800 + +kylin-nm (3.20.1.7) v101; urgency=medium + + * BUG号: + -#132105 【设计】网络属性界面字体最大时显示与设计预期不符 + -#140441 【rc6走查】【托盘】【网络】弹窗页tab控件未居中对齐 + -#141204 【rc6走查】【托盘】【网络】网络项间距待调整 + -#143412 【设计】【控制面板】有线、无线网络边距布局未按规范 + -#143422 【设计】【控制面板】移动热点通知弹窗调用图标错误 + -#143023 【设计】【控制面板】有线网络连接属性界面无删除此网络功能 + * 需求号:无 + * 其他改动: + 任务-#112767 应用代理功能开发 + * 影响域:属性页面UI 消息通知 控制面板应用代理 + + -- zhaoshixu Thu, 13 Oct 2022 16:27:57 +0800 + +kylin-nm (3.20.1.6) v101; urgency=medium + + * BUG号: + -#132105 【设计】网络属性界面字体最大时显示与设计预期不符 + -#143023 【设计】【控制面板】有线网络连接属性界面无删除此网络功能 + * 需求号:无 + * 其他改动: + * 影响域: 网络连接属性界面 + + -- zhaoshixu Tue, 11 Oct 2022 09:38:20 +0800 + +kylin-nm (3.20.1.5) v101; urgency=medium + + * BUG号: + -#140403 【HWE-Base1】【网络连接】【用例-391923】连接有线网络后,更改ip后保存,此时有线连接一直显示连接中状态,此时网络已经可用 + -#125714 【UKUI 3.20 走查】【网络】快捷键支持不完整 + -#123342 【ukui3.20】【设计】移动热点通知弹窗优化 + -#141661 【网络】网络名称长度最大时,网络详情界面名称显示不全 + * 需求号:无 + * 其他改动:修改关键字,解决编译不过问题 + * 影响域: 已连接有线更改ip usd快捷键 移动热点开关 详情页网络名称 + + -- zhaoshixu Wed, 28 Sep 2022 10:11:31 +0800 + +kylin-nm (3.20.1.4) v101; urgency=medium + + * BUG号: + - #141204 【rc6走查】【托盘】【网络】网络项间距待调整 + - #103843 【个性化|主题】【网络】切换主题,添加网络或者网络详情左上角的网络图标没有变化 + - #100325 【登录】【网络】在系统内关闭有线网络的开关后,注销到登录界面,有线网络仍然可以连接(但实际没有连接) + - #140629 【藏文】【无线局域网】未藏文化:任务栏打开无线局域网,加入其他网络,”记住该网络“显示为英文 + - #140550 【网络配置】以太网连接确认窗口选择允许其他设备发现这台设备后,防火墙类型没有配置为办公网络 + - #140545 【HWE-Base1】【网络连接】忘记WiFi后,仍会显示WiFi连接状态,此时实际已经断连(必现) + - #140442 【rc6走查】【托盘】【网络】离任务栏的间距和设计稿不符 + - #140441 【rc6走查】【托盘】【网络】弹窗页tab控件未居中对齐 + - #140440 【rc6走查】【托盘】【网络】左右间距不符合设计稿 + - #140438 【rc6走查】【托盘】【网络】设置按钮未符合设计稿 + - #140401 【HWE-Base1】【网络连接】连接无线网络时,弹窗提示“是否允许此网络在其他设备...”,显示在屏幕右下方,未显示在屏幕中央(必现) + - #122742 【reopen】【x100】【通有】【卓怡NF14-ODM】【wifi】路由器设置WiFi从不加密到加密后,测试机点击连接该WiFi,没有弹出密码框,一直转圈 + * 需求号:无 + * 其他改动:修改关键字,解决编译不过问题 + * 影响域: 网络主界面,详情页图标,翻译 + + -- chenxuechao Mon, 26 Sep 2022 09:33:31 +0800 + +kylin-nm (3.20.1.3) v101; urgency=medium + + * BUG号: + - #103974 【无线网络】使用ip link set down dev wlan0关闭无线设备后,无线开关仍然是打开状态,无无线列表 + - #126700 【WIFI】在网络高级设置中连接无线网络后,断开该无线网络,任务栏无线列表该无线网络仍然处于断开加载状态 + - #122742 【wifi】路由器设置WiFi从不加密到加密后,测试机点击连接该WiFi,没有弹出密码框,一直转圈 + - #134326 【网络】网络项长度不一致 + + -- zhaoshixu Fri, 26 Aug 2022 13:47:31 +0800 + +kylin-nm (3.20.1.2) v101; urgency=medium + + * BUG号: + - #125058 【任务栏】【托盘】英文模式下网络工具插件名称悬浮显示不正确 + - #125703 【UKUI 3.20 走查】【托盘-网络】任务栏显示图标和默认弹出界面不一致 + - #126830 【ukui3.20】【设计】手动修改IP冲突提示优化 + - #131910 网络模式选择弹窗可以重复弹出 + - #132105 【设计】网络属性界面字体最大时显示与设计预期不符 + - #132350 【设计】连接企业wifi验证密码弹窗与设计不符 + - #133072 【防火墙】【网络模式配置】关闭专用和公用模式,首次连接网络,提示信息与选择内容错误 + - #133311 【防火墙】开机后连接默认网络,防火墙网络模式不显示正在使用的网络 + - #132228 【设计】首次连接网络提示弹窗版面间隔与设计不相符 + - #133299 【PTOF】【防火墙规则】【安全通知】匹配到阻止的入站规则,重启机器后,阻止规则失效 + + * 需求号:无 + * 其他改动: + * 影响域: 托盘图标tooltip 详情页 ip冲突检测 网络模式选择 + + -- zhaoshixu Fri, 12 Aug 2022 10:48:46 +0800 + +kylin-nm (3.20.1.1) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:删除多余头文件,解决编包不过的BUG + * 影响域:移动热点界面 藏文翻译 网络模式选择 网络配置界面 + + -- chenxuechao Mon, 25 Jul 2022 11:05:08 +0800 + +kylin-nm (3.20.1.0) v101; urgency=medium + + * BUG号: + - #126640 【WiFi】输入密码后,连接过程中,右键忘记网络后,密码信息仍然保存在输入框,建议删除 + - #116373 【设计】网络-加入其他网络弹窗样式与设计稿不一致 + * 需求号: + - #14264 网络模式选择 + * 其他改动: + -任务#94645 前端界面开发 + * 影响域:移动热点界面 藏文翻译 网络模式选择 网络配置界面 + + -- chenxuechao Mon, 25 Jul 2022 10:16:17 +0800 + +kylin-nm (3.20.0.6) v101; urgency=medium + + * BUG号: + - #126640 【WiFi】输入密码后,连接过程中,右键忘记网络后,密码信息仍然保存在输入框,建议删除 + - #116373 【设计】网络-加入其他网络弹窗样式与设计稿不一致 + * 需求号: + - #14264 网络模式选择 + * 其他改动: + -任务#94645 前端界面开发 + * 影响域:移动热点界面 藏文翻译 网络模式选择 网络配置界面 + + -- chenxuechao Fri, 22 Jul 2022 18:23:34 +0800 + +kylin-nm (3.1.1-2021+1230) v101; urgency=medium + + * BUG号: #93795 切换动画效果生硬 + * #97962 界面内间距未按照蓝湖效果图的规范设置 + * #98652 任务栏有线网络无线网络的开关没有switch的三态效果 + * #99710 【PTOF】【无线网络】无线网络密码输入框中的明暗文看不清 + * #99711 【企业WiFi】企业WiFi的链接弹窗没有适配浅深色主题 + * #99942 【反馈回归】【企业WiFi】加入企业WiFi界面或者链接企业WiFi界面,点击密码输入框中的眼睛图案存在边框 + * #100020 【SP2 UI走查】【任务栏】【网络】图标底色待优化 + * #100740 【SP2 UI走查】【任务栏】【网络】网络项长度不一致 + * #100742 【SP2 UI走查】【任务栏】【网络】网络设置缺少三态 + * #100833 【移动热点】打开无线开关,拔掉无线网卡,热点的开关样式样式错误 + * 需求号:无 + * 其他改动:已连接、未连接文案改动 + + -- zhaoshixu Thu, 30 Dec 2021 10:13:26 +0800 + +kylin-nm (3.1.1-2021+1221) v101; urgency=medium + + * BUG号: #98052 【控制面板】控制面板有线网络和无线网络的开关无效 + * #97047 【移动热点】【3a5000】点击移动热点开启|关闭按钮,响应缓慢卡顿 + * #86820 【无线网络】连接有线和无线,切换有线和无线界面,kylin-nm崩溃(2/5) + * #91150 存在两个用户的情况下,来回切换,切换后点击有线或者无线的详情按钮,kylin-nm崩溃(3/10) + * #96758 【网络连接】在编辑网络时按esc退出,点击网络界面的!无法进入网络编辑界面 + * #97277 【控制面板】添加有线网络界面标题不正确 + * #97315 【网络连接】在设置有线网络名称很长时网络连接界面显示不全且无提示 + * #97721 【详情页】点击任务栏未连接的有线网络或者无线网络的详情按钮,详情页面显示异常,显示黑白框体;右键点击详情页的输入框,右键菜单显示为黑色 + * #98908 【任务栏】【网络】标题颜色需按照新设计规范设置 + * #97419 【网络连接】点击有线连接详情后,在打开的窗口修改IP后回车会闪现黑框 + * #97818 【无线网络】企业WiFi弹窗布局异常,顶部名称显示kylin-nm,且存在两个关闭按钮 + * #93906 【有线网络】新建有线网络时,输入IP地址与子网掩码确认按钮置灰 + * 需求号:无 + * 其他改动:增加keyring开关dbus接口,供其他组件调用 + + -- zhaoshixu Tue, 21 Dec 2021 13:57:51 +0800 + +kylin-nm (3.1.1-2021+1213) v101; urgency=medium + + * BUG号: #90711 【网络】多网卡的情况下(有线和无线均可),点击切换网卡的下拉框,框体显示纯黑不美观 + * #93043 使用USB接口扩展坞连接网线,任务栏有线网络没有显示新的有线连接,控制面板显示新的有线连接 + * #94130 【网络连接】“连接企业网”弹窗、网络连接详情打开时,任务栏没有对应的图标显示 + * #93769 【有线网卡】系统配置两张有线网卡,设置相同的IP地址,没有提示IP地址冲突 + * #93664 【网络连接】将鼠标悬浮在任务栏网络图标处,显示麒麟关键字 + * #91118 【控制面板】【无线投屏】停止投射会影响投射端网络连接,弹出提示“有线网络已断开” + * #93798 【网络连接】插入网线连接有线连接,关掉有线网络,拔掉网线,再开启有线网络后,有线连接自动连接 + * #92578 【需求-有线网络-9078】有线网络开关关闭后,拔掉网线,重启机器,重新插入网线,后台显示有线网络已连接 + * #93825 【网络连接】关闭有线开关,重启电脑后有线连接显示关闭,但是任务栏图标显示已连接 + * #96106 网络界面的一级标题的颜色与效果图不一致 + * #92800 【网络连接】点击任务栏网络图标,查看网络详情,在输入框右击,右键菜单未汉化 + * #86306 开启移动热点后,任务栏以及控制面板该热点的信号强度均为0 + * #92178 【SP2 UI走查】【需求-网络-9078】【任务栏】【网络】网络的三态未符合主题框架的规律,如tab页不需要三态等,网络信号三态颜色不合适等 + * #92160 【SP2 UI走查】【需求-网络-9078】【任务栏】【网络】网络界面的透明度不会跟随系统设置的透明度变化 + * 需求号:无 + * 其他改动:默认模式的亮调色板改为3.1样式 + -- zhaoshixu Mon, 13 Dec 2021 13:57:14 +0800 + +kylin-nm (3.1.1-2021+1206) v101; urgency=medium + + * BUG号: #92751 【网络连接】未连接网络时,有线网络图标未反白 + * #94291 【网络连接】右键网络连接列表滚轮条,弹出菜单未汉化 + * #95667 【网络】网络包版本集成错误 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Mon, 06 Dec 2021 15:36:03 +0800 + +kylin-nm (3.1.1-2021+1203) v101; urgency=medium + + * BUG号: #91275 输入“热点名称”超过限制长度,创建热点异常 + * #92131 网卡关闭情况下新增有线连接失败 + * #90268 多个用户同时登录时,断开无线网络会存在3s左右的卡顿 + * #86473 在控制面板关闭无线网络的开关,点击任务栏网络图标,在开关完全关闭后才能打开界面,首次打开缓慢 + * #81153 无线网络开关打开(关闭)后,网络连接界面卡顿 + * #92578 有线网络开关关闭后,拔掉网线,重启机器,重新插入网线,后台显示有线网络已连接 + * #92118 WiFi密码输入框可以输入中文 + * #92235 分割线的颜色跟蓝湖效果图不符合 + * #92242 任务栏和界面上调用的图标不一致,例如任务栏有线图标存在两根天线,网络链接界面不存在 + * #92246 任务栏点击一个未连接的无线网络,密码弹框中的明暗文图框存在黑色边框,根据UI设计应该不存在 + * #92309 点击一个未连接的无线网络,无线名称会向上移动一点距离 + * #92675 将所有的有线网络全部删除后,任务栏图标仍然显示有线网络已连接的样式 + * #93818 在网络配置界面输入过程中按回车会进入详情界面 + * #93755 移动热点窗口拖动到四周,界面显示不完全 + * #93731 打开控制面板有线网络界面,多次点击添加网络,添加网络界面可以显示多个 + * #92427 连接不支持开热点的网卡,控制面板还是会出现移动热点的选项,且可以打开 + * #91794 移动热点】每行内容行距应为60px + * #91791 移动热点-内容跟窗口最右距离应为40px + * #91510 移动热点左侧文案没有和标题对齐 + * #91322 插入第二张网卡,网络连接2的连接状态和任务栏图标状态不一致 + * #91800 【控制面板】添加有限网络头部图标调用错误,地址栏应改为ipv4地址 + * #91818 任务栏点击一个未连接的无线网络,弹出的是自动链接。根据UI是"自动加入该网络" + * #92028 英文模式、11-15号字体下,任务栏网络连接的‘Settings’显示不全 + * #93787 界面内间距未按照蓝湖效果图的规范设置 + * #90875 通过kylin-nm无法调起任务栏网络主界面,建议增加该功能 + * #93840 网络界面的一级标题的颜色与效果图不一致 + * #93779 有限网络和无线网络的详情页没有使用窗管 + * #93733 无线网络的表格布局不是一体 + * #93703 有线网络的表格布局不是一体 + * #92800 点击任务栏网络图标,查看网络详情,在输入框右击,右键菜单未汉化 + * #89944 任务栏无线网络界面列表排列和控制面板无线网络界面顺序排列不统一 + * #89405 添加有线网络界面主题应该跟随系统,而不是默认黑色主题 + * #87430 详情页一直为深色主题,根据设计,默认为浅色,切跟随系统主题 + * #94123 同一个企业WiFi,可以同时打开多个连接窗口 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Wed, 01 Dec 2021 11:17:55 +0800 + +kylin-nm (3.1.1-2021+1118) v101; urgency=medium + + * BUG号: #91112 #90703 #91068 #91011 #90704 # 90701 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Wed, 17 Nov 2021 15:55:51 +0800 + +kylin-nm (3.1.1-2021+1112) v101; urgency=medium + + * BUG号: #89026 #90722 #83326 #90333 #89707 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Fri, 12 Nov 2021 11:20:44 +0800 + +kylin-nm (3.1.1-2021+1110) v101; urgency=medium + + * BUG号: #89591 #89399 #87476 #89286 #88441 #88652 #83326 #87649 #89001 + #89592 #89143 #88353 #87734 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Wed, 10 Nov 2021 13:49:25 +0800 + +kylin-nm (3.1.1-2021+1104) v101; urgency=medium + + * BUG号:#87742 #87734 #87675 #86526 #88674 #85711 #85597 #83335 #87727 + #87711 #87476 #88675 #88601 #87481 + * 需求号:无 + * 其他改动:无 + + -- zhaoshixu Thu, 04 Nov 2021 09:49:53 +0800 + +kylin-nm (3.1.1-2021+1029.2) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:增加libsecret-1 libgtk-3-dev依赖 + + -- zhaoshixu Fri, 29 Oct 2021 10:28:03 +0800 + +kylin-nm (3.1.1-2021+1029.1) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:增加libnma-dev依赖 + + -- zhaoshixu Fri, 29 Oct 2021 09:59:49 +0800 + +kylin-nm (3.1.1-2021+1029) v101; urgency=medium + + * BUG号:无 + * 其他改动:全新基于3.1设计的重构版本 + * 影响域:任务栏网络+控制面板网络插件全部功能 + + -- zhaoshixu Fri, 29 Oct 2021 08:59:01 +0800 + +kylin-nm (3.0.1-1kylin54) v101; urgency=medium + + * BUG号:#57502 #61141 #61356 + * 需求号:无 + * 其他改动:将kylin-nm在桌面通知和侧边栏的通知改为麒麟网络设置工具 + + -- chenlelin Wed, 30 Jun 2021 21:45:42 +0800 + +kylin-nm (3.0.1-1kylin53) v101; urgency=medium + + * BUG号:#58766 #61534 #61628 + * 需求号:无 + * 其他改动:修复远程连接用户桌面无kylin-nm问题 + + -- chenlelin Wed, 23 Jun 2021 11:00:42 +0800 + +kylin-nm (3.0.1-1kylin52) v101; urgency=medium + + * BUG号:#58755 #61924 #61509 #61783 + * 需求号:无 + * 其他改动:无 + + -- zhangjiaping Tue, 22 Jun 2021 15:17:42 +0800 + +kylin-nm (3.0.1-1kylin52) v101; urgency=medium + + * BUG号:#58755 #61924 #61509 #61783 + * 需求号:无 + * 其他改动:无 + + -- zhangjiaping Tue, 22 Jun 2021 15:17:42 +0800 + +kylin-nm (3.0.1-1kylin51) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:修改主程序启动方式为两段式启动,开机仅进行一级启动,五秒/点击托盘图标后进行二级启动 + + -- zhangjiaping Tue, 08 Jun 2021 16:49:12 +0800 + + +kylin-nm (3.0.1-1kylin50) v101; urgency=medium + + * BUG号:无 + * 需求号:无 + * 其他改动:增加维测日志,优化WiFi刷新触发底层扫描,优化WiFi密码错误提醒,优化WiFi刷新dbus信号发送流程 + + -- zhangjiaping Mon, 07 Jun 2021 19:54:21 +0800 + +kylin-nm (3.0.1-1kylin50) v101; urgency=medium + + * BUG号:无 + * 需求号:#33373 #33309 #33960 + * 其他改动:无 + + -- zhangjiaping Mon, 07 Jun 2021 16:17:18 +0800 + +kylin-nm (3.0.1-1kylin49hw1) v101; urgency=medium + + * BUG号:#56269 #54745 #54354 #50457 + * 需求号:无 + * 其他改动:无 + + -- zhangjiaping Sat, 05 Jun 2021 14:43:32 +0800 + +kylin-nm (3.0.1-1kylin49) v101; urgency=medium + + * BUG号:无 + * 需求号:#33308 + * 其他改动:无 + + -- zhangjiaping Wed, 02 Jun 2021 17:53:12 +0800 + +kylin-nm (3.0.1-1kylin48hw1) v101.hw; urgency=medium + + * BUG号:#54745 #53735 #54354 #58278 #56567 + * 需求号:无 + * 其他改动:无 + + -- zhangjiaping Wed, 02 Jun 2021 15:59:23 +0800 + +kylin-nm (3.0.1-1kylin47hw1) v101.hw; urgency=medium + + * BUG号:#57475 #56581 + * 需求号:无 + * 其他改动:无 + + -- chenlelin Sun, 30 May 2021 17:03:02 +0800 + +kylin-nm (3.0.1-1kylin42) v101; urgency=medium + + * fail to compile version kylin41, change control file then upload + + -- chenlelin Thu, 20 May 2021 16:28:02 +0800 + +kylin-nm (3.0.1-1kylin41) v101; urgency=medium + + * 解决bug如下 + - 37076, 有线连接名称设置为空格时,连接后显示有误. + - 37485, 建立有线网络的名称为空格后,界面显示异常. + + -- chenlelin Thu, 20 May 2021 9:28:02 +0800 + +kylin-nm (3.0.1-1kylin40) v101; urgency=medium + + * 解决bug如下 + - 51571, 网络工具在侧边栏消息提示描述里显示为麒麟网络工具. + + -- chenlelin Mon, 17 May 2021 20:28:02 +0800 + +kylin-nm (3.0.1-1kylin39) v101; urgency=medium + + * 解决bug如下 + - 53732, 通过DBUS获取SSID, 避免ssid存在空格时,识别错误的问题. + - 50612, 点击桌面右下角网络图标处,开启无线网,并成功接入网络,然后点击属性无法查看网络信息. + + -- chenlelin Fri, 14 May 2021 11:12:02 +0800 + +kylin-nm (3.0.1-1kylin38) v101; urgency=medium + + * 解决bug如下 + - 50612, 点击桌面右下角网络图标处,开启无线网,并成功接入网络,然后点击属性无法查看网络信息. + + -- chenlelin Mon, 10 May 2021 19:12:02 +0800 + +kylin-nm (3.0.1-1kylin37) v101; urgency=medium + + * 解决bug如下 + - 自测bug,在连接wpa2 personal 安全类型的隐藏wifi后没有自动刷新界面. + + -- chenlelin Sat, 08 May 2021 10:12:02 +0800 + +kylin-nm (3.0.1-1kylin36) v101; urgency=medium + + * 将9a0的wifi6与wifi6+的代码内容合并入主分支 + * 解决bug如下 + - 43477,有线连接名称为一个空格,修改为两个空格后,连接空格有线网络,界面显示异常. + - 43492,WiFi名称与有线名称相同时,修改有线连接ip设置,wifi的ip设置也一起修改. + - 43625,密码策略为:每次询问这个密码类型的wifi,点击连接,该窗口置于各个角落后可全屏显示. + - 43622,密码策略为:每次询问这个密码类型的wifi,点击连接,该窗口名称未汉化. + - 43538,ip冲突时,会出现两次ip冲突提示. + - 43550,编辑wifi连接-wifi界面,模式选项存在冒号,与其他不统一. + + -- chenlelin Wed, 21 Apr 2021 10:12:02 +0800 + +kylin-nm (3.0.1-1kylin35) v101; urgency=medium + + * 解决bug如下 + - 请确认wifi密码或无线设备的通知重复弹出(禅道45783). + - 通过命令down掉无线网口后再恢复,图形化界面未显示“可用无线网络列表”​(禅道43771). + - 中文系统下出现英文通知​(禅道45861). + - 检测IP地址冲突的消息在侧边栏显示“未知来源”​(禅道45860). + + -- chenlelin Mon, 12 Apr 2021 20:30:02 +0800 + +kylin-nm (3.0.1-1kylin34) v101; urgency=medium + + * 合并代码,主线没有改动 + + -- chenlelin Wed, 31 Mar 2021 20:30:02 +0800 + +kylin-nm (3.0.1-1kylin33) v101; urgency=medium + + * 解决bug如下 + - WiFi-加入网络功能,输入特殊字符、字母、数字组合的名称,点击连接后kylin-nm闪退(禅道43670). + + -- chenlelin Sat, 27 Mar 2021 15:19:02 +0800 + +kylin-nm (3.0.1-1kylin32) v101; urgency=medium + + * 去掉gnome-shell重新传代码 + + -- chenlelin Fri, 26 Mar 2021 19:39:02 +0800 + +kylin-nm (3.0.1-1kylin31) v101; urgency=medium + + * 解决中文环境右上角桌面通知显示英文的问题 + + -- chenlelin Fri, 26 Mar 2021 16:52:02 +0800 + +kylin-nm (3.0.1-1kylin30) v101; urgency=medium + + * 合并代码,生成与华为990的兼容代码 + + -- chenlelin Thu, 25 Mar 2021 22:17:02 +0800 + +kylin-nm (3.0.1-1kylin29) v101; urgency=medium + + * 解决bug如下 + - 已连接WiFi后,点击其他WiFi,不输入密码按下enter键,网络状态会显示断开,4秒左右恢复正常(禅道42279). + - 检测IP地址冲突的消息在侧边栏显示“未知来源(禅道40848). + + -- chenlelin Fri, 19 Mar 2021 11:10:02 +0800 + +kylin-nm (3.0.1-1kylin28) v101; urgency=medium + + * 解决bug如下 + - WiFi的SSID过长时,存在显示不全(禅道42130). + - 实时流量监控显示与系统监视器中网络历史显示不同​(禅道39073). + - WiFi多次连接/取消连接,连接/断开连接后,点击连接无反应​(禅道42156). + + -- chenlelin Mon, 15 Mar 2021 9:54:02 +0800 + +kylin-nm (3.0.1-1kylin27) v101; urgency=medium + + * 解决bug如下 + - 修复设置ipv4地址后wifi不会自动重连的bug(禅道36571). + - 解决在新建wifi时,选择每次询问密码后,点击保存后wifi无法自动连接的问题​(禅道37735). + + -- chenlelin Thu, 11 Mar 2021 14:41:02 +0800 + +kylin-nm (3.0.1-1kylin26) v101; urgency=medium + + * 解决bug如下 + - 拔掉网线,无网络断开提示(禅道39021). + - 添加网络时,光标异常显示​(禅道40360). + - 编辑有线网络连接-修改连接名称无效(禅道41427). + - WiFi-加入网络功能,输入特殊字符、字母、数字组合的名称,点击连接后kylin-nm闪退(禅道41156). + - WiF连接前后强度显示不同(禅道41200). + - WiFi-加入网络功能,输入特殊字符、字母、数字组合的名称,点击连接后kylin-nm闪退(禅道41156). + - 英文模式下,编辑有线网络界面中设置ipv6显示不全(禅道41778). + - 新建/编辑网络连接-右键ipv6地址设置未翻译(禅道39004). + + -- chenlelin Tue, 9 Mar 2021 10:38:02 +0800 + +kylin-nm (3.0.1-1kylin25) v101; urgency=medium + + * 解决bug如下 + - 新建vpn类型网络,存在未汉化选项(禅道28635, 37516). + - 在右下角直接添加没有设置DNS的网络,无法保存​(禅道40323). + - 打开网络连接1编辑框,通过设置修改网络连接1的DNS,导致kylin-nm闪退(禅道40219, 39889). + - 开启特效模式后,透明度为最高时,WiFi断开按钮突兀(禅道39889). + - 右键任务栏网络图标,设置网络的图标异常(禅道37631). + - 已连接有线网络1,再次连接有线网络2并快速点击取消,导致有线连接1连接断开(禅道38888). + - WiFi会显示强度为0的WiFi信号(禅道38861). + - 有线网络A不设置DNS不能保存,切换至有存在DNS的有线网络B再切换回来后可以保存(禅道38880). + + -- chenlelin Thu, 4 Mar 2021 10:36:02 +0800 + +kylin-nm (3.0.1-1kylin24) v101; urgency=medium + + * 合并master分支和990分支,产生兼容代码。 + + -- chenlelin Fri, 26 Feb 2021 10:23:02 +0800 + +kylin-nm (3.0.1-1kylin23) v101; urgency=medium + + * 解决在nm-connection-editor中修改wifi连接名称后,wifi列表顶部已连接wifi处显示空白的问题。 + + -- chenlelin Thu, 25 Feb 2021 19:30:02 +0800 + +kylin-nm (3.0.1-1kylin22) v101; urgency=medium + + * 解决bug如下 + - 存在热点类型的WiFi后,网络管理器-加入网络-多次切换网络类型,kylin-nm闪退(禅道38340). + - 控制面板-网络-可用网络-网络连接,点击后任务栏闪烁一下(禅道38321). + - 有线网络A不设置DNS不能保存,切换至有存在DNS的有线网络B再切换回来后可以保存(禅道38280). + - 开启特效模式后,透明度为最高时,WiFi断开按钮突兀(禅道31245). + - 点击任务栏-有线网络-选择任意有线网络-编辑,编辑窗口最小化后,点击任务栏网络管理图标无效(禅道38362). + - 修复设置ipv6地址失败的Bug(禅道38287). + - 网络管理器-连接热点WiFi后手动将被测机器拉入WiFi黑名单,网络管理状态显示异常(禅道30061). + - 两台机器直连测试时,network-manager报错,网络自动断开(禅道38218). + + -- chenlelin Mon, 8 Feb 2021 16:06:02 +0800 + +kylin-nm (3.0.1-1kylin21) v101; urgency=medium + + * 解决bug如下 + - 有线连接名称设置为空格时,连接后显示有误(禅道37076,37485). + - 解决右键菜单设置图标显示错误的问题. + - 在有线网络A连接时,快速点击连接有线网络B,提示网络连接失败,但最后可以成功连接网络(禅道37067). + - 修复wifi安全性变更后无法正常连接的bug(禅道34664). + - 修复连接vpn时有线网断开的bug(禅道34639). + + -- chenlelin Fri, 5 Feb 2021 15:26:02 +0800 + +kylin-nm (3.0.1-1kylin20) v101; urgency=medium + + * 解决bug如下 + - 解决连接的一个手机的热点,在休眠后手机关闭热点,再次唤醒后这个网络工具界面依然长时间显示这个热点连接的状态. + - 自研的网络设置界面,加入隐藏WiFi界面网络名称建议增加字符数限制(禅道36507). + - 有线连接名称设置为空格时,连接后显示有误(禅道37076). + + -- chenlelin Sat, 30 Jan 2021 11:46:02 +0800 + +kylin-nm (3.0.1-1kylin19) v101; urgency=medium + + * 解决bug如下 + - 无线网络再次连接时,没有显示网络名称(禅道36082). + - 通过任务栏网络编辑设置界面,修改WiFi的IP地址获取方式不生效(禅道36581). + - 解决点击wifi连接,直接弹出“请确认wifi密码或无线设备”的提示. + + -- chenlelin Thu, 28 Jan 2021 11:32:02 +0800 + +kylin-nm (3.0.1-1kylin18) v101; urgency=medium + + * 解决bug如下 + - 无线网络再次连接时,没有显示网络名称(禅道36082). + - 修复侧边栏中kylin-nm的消息通知,左边没有图标的问题. + - WiFi-加入网络-安全性气候为企业WiFi后,WiFi安全性未汉化(禅道35916). + - 取消网络连接时提示更人性化(禅道35847). + - 已打开网络设置消息窗口,如果有其他界面将其覆盖,再次点击网络设置按钮消息窗口不会切换到最上方(禅道27762). + - 修复ipv6地址设置项缺失的问题(禅道19885). + - 任务栏打开/关闭飞行模式,网络状态显示异常(禅道35669). + - 修复wifi密码策略为当前用户存储时连接失败(禅道31154). + + -- chenlelin Wed, 27 Jan 2021 8:55:02 +0800 + +kylin-nm (3.0.1-1kylin17) v101; urgency=medium + + * 解决bug如下 + - 点击网络管理-加入网络-加入企业WiFi,连接成功后,点击其他企业WiFi连接后,kylin-nm闪退(禅道30062). + - WiFi-加入网络界面,设置WiFi安全性为企业WiFi后,切换EAP方式为非PEAP后,子验证方式不会发生改变(禅道34372). + - WiFi-加入网络界面,设置WiFi安全性为企业WiFi后,无法切换回无安全性(禅道34362). + - 蓝牙连接手机,本地服务中网络设置勾选“网络连接点”,有线网络界面中连接手机网络,连接失败,无法上网(禅道26026). + - 开源工具新建WiFi类型网络成功后,kylin-nm无法自动连接(禅道31134). + - 麒麟网络工具右键菜单设置图标不正确. + + -- chenlelin Thu, 21 Jan 2021 19:09:02 +0800 + +kylin-nm (3.0.1-1kylin16) v101; urgency=medium + + * 删掉用户手册 + - kylin-nm-guide.wps + + -- chenlelin Tue, 19 Jan 2021 11:15:02 +0800 + +kylin-nm (3.0.1-1kylin15) v101; urgency=medium + + * 解决bug如下 + - 已经连接过的热点,修改热点密码后,再次连接时的处理逻辑不正常(禅道23827). + - 连接加密WiFi时输入6位数错误的密码后,再输入8位数错误密码,无侧边栏提示(禅道31111). + - 通过命令行连接wifi不成功(禅道19033). + - 刷新wifi时,无法点击有线连接标签(禅道11957). + - 连接后和连接前的信号显示有偏差(禅道23882). + - 手动关闭热点/路由器时,断开WiFi无提示(禅道31168). + - 设置有线网络不生效,断开重连后才会生效(禅道33130). + - 双网卡情况下,点击已连接的网卡1,再点击未连接网络后,网卡2已连接网络显示错误(禅道33580). + - 任务栏点击-wifi图标-设置-ipv4/ipv6设置,添加/删除图标不一致(禅道26445). + - 任务栏点击-wifi图标-设置-代理设置,存在语义不清晰(禅道26450). + * 添加用户手册 + - kylin-nm-guide.wps + + -- chenlelin Sat, 16 Jan 2021 11:40:02 +0800 + +kylin-nm (3.0.1-1kylin14) v101; urgency=medium + + * 优化获取有线列表和无线列表部分的代码. + * 解决进行网络插拔交替网线连接,概率性出现有线连接界面异常的问题(禅道32687)。 + + -- chenlelin Mon, 11 Jan 2021 18:55:02 +0800 + +kylin-nm (3.0.1-1kylin13) v101; urgency=medium + + * 修复是否询问密码设置与NetwordManager不互通的bug(禅道27649). + * 修复连接企业wifi显示未提供密码的bug(禅道31120). + * 解决双网卡情况下,切换网络连接卡顿的问题(禅道32525). + * 添加取消连接功能. + + -- chenlelin Sat, 09 Jan 2021 15:54:02 +0800 + +kylin-nm (3.0.1-1kylin12) v101; urgency=medium + + * 修改有线网络设置窗口放大后概率性无法复原的问题. + * 解决传递到侧边栏的网络信息部分为汉化的问题. + + -- chenlelin Fri, 08 Jan 2021 14:14:02 +0800 + +kylin-nm (3.0.1-1kylin11) v101; urgency=medium + + * 添加支持vnc功能. + * 修复选择加入的wifi无法被扫描到的时候wifi列表显示错误的问题. + * 修复修改ip或dns后网络循环连接的问题. + + -- chenlelin Fri, 08 Feb 2021 09:08:02 +0800 + +kylin-nm (3.0.1-1kylin10) v101; urgency=medium + + * 把连接隐藏wifi过程放入线程中. + * 解决启动kylin-nm的时候,正在加载wifi列表,此时又遇到wifi列表更新,导致程序崩溃的问题. + * 解决因使用char*,导致在网络名字很长时越界导致程序崩溃的问题. + * 解决rfkill block all 控制面板wifi开关不同步的问题. + * 开机后,从无线网络列表切换到有线网络列表,有线网络列表顶部为空. + + -- chenlelin Wed, 06 Feb 2021 14:49:02 +0800 + +kylin-nm (3.0.1-1kylin9) v101; urgency=medium + + * 解决托盘打开网络管理面板,选择WiFi->加入网络,弹出的加入WiFi窗口未汉化的问题(禅道26906). + * 解决有时连接一个已经连接的隐藏wifi不生效的问题(禅道19017). + + -- chenlelin Thu, 31 Dec 2020 21:27:02 +0800 + +kylin-nm (3.0.1-1kylin8) v101; urgency=medium + + * 修复因文本框较短导致无法显示完全较长的wifi名称. + * 修复任务栏隐藏的情况下,点击托盘图标无法正确显示主窗口位置的问题. + * 解决点击正在进行等待动画的托盘图标,导致程序退出的问题. + * 解决输错两次wifi密码后,导致wifi变为每次连接需要输入密码的类型的问题. + + -- chenlelin Wed, 30 Dec 2020 19:21:02 +0800 + +kylin-nm (3.0.1-1kylin7) v101; urgency=medium + + * 在连接有线网时,断开与这个有线网同一个网卡的已经连接的有线网络. + * 修复点击加入个人wifi后点击企业Wifi弹窗有误的问题. + * 修改连接企业wifi的超时时间以保证有足够的时间验证密码. + + -- chenlelin Mon, 21 Dec 2020 17:23:02 +0800 + +kylin-nm (3.0.1-1kylin6) v101; urgency=medium + + * 在有多个有线连接同时被激活的情况下,有线界面将所有已连接网络显示出来. + + -- chenlelin Mon, 21 Dec 2020 9:10:02 +0800 + +kylin-nm (3.0.1-1kylin5) v101; urgency=medium + + * 调整主窗口到屏幕边沿的距离. + + -- chenlelin Fri, 18 Dec 2020 17:00:02 +0800 + +kylin-nm (3.0.1-1kylin4) v101; urgency=medium + + * 解决点击任务栏窗口退回,导致无法点击屏幕键盘输入密码的问题. + + -- chenlelin Wed, 16 Dec 2020 20:52:02 +0800 + +kylin-nm (3.0.1-1kylin3) v101; urgency=medium + + * 利用有线网的UUID连接断开网络,以及配置修改网络参数. + * 解决有线网因QProcess执行问题导致获取有线列表为空的问题. + * 修复wifi频率图标显示不准确的问题. + + -- chenlelin Tue, 15 Dec 2020 20:52:02 +0800 + +kylin-nm (3.0.1-1kylin2) v101; urgency=medium + + * 修复企业WIFI名称错误的bug + * 修复企业WIFI无法连接的bug + * 添加是否每次询问密码的选项 + + -- zhangjiaping Sat, 12 Dec 2020 14:16:24 +0800 + +kylin-nm (3.0.1-1kylin1) v101; urgency=medium + + * 添加连接企业wifi的功能. + * 添加5G wifi优先连接功能. + + -- chenlelin Thu, 10 Dec 2020 18:46:02 +0800 + +kylin-nm (1.2.3-1kylin31) v101; urgency=medium + + * 解决因添加判断网络IP或DNS修改功能而导致连接wifi时会自动切换到有线界面的问题。 + + -- chenlelin Fri, 4 Dec 2020 13:29:02 +0800 + +kylin-nm (1.2.3-1kylin30) v101; urgency=medium + + * 解决修改网络中已经连接网络的DNS保存后,要重启系统才能生效的问题(禅道#20081)。 + * 解决在拔出网线后,删除所有有线网络,再插入网线后没有自动新建有线网络的问题。 + + -- chenlelin Thu, 3 Dec 2020 16:49:02 +0800 + +kylin-nm (1.2.3-1kylin29) v101; urgency=medium + + * 解决网络工具桌面通知和侧边栏通知时消息左侧无图标显示的问题(禅道#20282)。 + * 解决在nm-connection-editor中配置好网络参数后,需要重新连接才能生效的问题(禅道#26713)。 + * 添加network-manager-gnome运行依赖iputils-arping与libnotify-bin(禅道#18897)。 + + -- chenlelin Wed, 2 Dec 2020 15:56:02 +0800 + +kylin-nm (1.2.3-1kylin28) v101; urgency=medium + + * 托盘打开网络管理面板,选择WiFi->加入网络,弹出的加入WiFi窗口未汉化(禅道#26906)。 + + -- chenlelin Mon, 30 Nov 2020 16:10:02 +0800 + +kylin-nm (1.2.3-1kylin27) v101; urgency=medium + + * 英文模式下新建网络连接,会出现两个同样的连接,断开连接时也需要断开两次(禅道#26881)。 + + -- chenlelin Sat, 28 Nov 2020 16:42:02 +0800 + +kylin-nm (1.2.3-1kylin26) v101; urgency=medium + + * 重新上传。 + + -- chenlelin Fri, 27 Nov 2020 17:22:02 +0800 + +kylin-nm (1.2.3-1kylin25) v101; urgency=medium + + * 解决在中文系统环境下无法断开英文环境创建的有线网络。 + + -- chenlelin Fri, 27 Nov 2020 17:15:02 +0800 + +kylin-nm (1.2.3-1kylin24) v101; urgency=medium + + * 解决对已配置网络参数的有线网络进行重命名,任务栏图标点击无反应的问题(禅道#26683) + + -- chenlelin Fri, 27 Nov 2020 16:24:02 +0800 + +kylin-nm (1.2.3-1kylin23) v101; urgency=medium + + * 编辑网络设置小窗不能更改网络名称(禅道#23843) + + -- chenlelin Fri, 20 Nov 2020 15:49:02 +0800 + +kylin-nm (1.2.3-1kylin22) v101; urgency=medium + + * 网络连接设置窗口的网关地址栏太小了,不能完整显示(禅道#18766) + + -- chenlelin Thu, 19 Nov 2020 18:24:02 +0800 + +kylin-nm (1.2.3-1kylin21) v101; urgency=medium + + * 更改系统字体再恢复默认后,编辑网络设置界面的字体未变回默认(禅道#24515) + * 解决配置相同的IP地址,未提示冲突的问题(禅道#18879) + + -- chenlelin Tue, 17 Nov 2020 18:38:02 +0800 + +kylin-nm (1.2.3-1kylin20) v101; urgency=medium + + * 解决系统在英文环境下名为'有线连接 1'的有线网名称仍然为中文的问题(禅道#18254) + + -- chenlelin Fri, 13 Nov 2020 17:01:02 +0800 + +kylin-nm (1.2.3-1kylin19) v101; urgency=medium + + * 解决修改已经连接的有线网ip等信息后,需要手动断开再连接网络,界面的信息才能刷新(禅道#12034) + + -- chenlelin Thu, 12 Nov 2020 17:01:02 +0800 + +kylin-nm (1.2.3-1kylin18) v101; urgency=medium + + * 解决无法实现每次连接wifi网络都需输入密码的功能(禅道#21235) + + -- chenlelin Wed, 11 Nov 2020 17:01:02 +0800 + +kylin-nm (1.2.3-1kylin17) v101; urgency=medium + + * 解决706FT2000TR4253笔记本安装系统后kylin-nm无法启动的问题(禅道#18634) + * 适配白色主题. + * 解决右键点击任务栏关闭按钮关闭设置窗口,导致整个进程退出的问题(禅道#23712). + * 屏蔽设置窗口的右键菜单. + + -- chenlelin Tue, 10 Nov 2020 9:47:02 +0800 + +kylin-nm (1.2.3-1kylin16) v101; urgency=medium + + * Internationalization of desktop notification. + * Fix bug the network speed is 0 after plug in wireless card. + * Fix bug ipv4 can not refresh sometimes after change the configuration of a connected wired network. + * Fix bug can not show normal window icon in taskbar when show a config window. + + -- chenlelin Thu, 24 Sep 2020 17:13:02 +0800 + +kylin-nm (1.2.3-1kylin15) v101; urgency=medium + + * Fix bug switch state of kylin-nm is different from control-center. + + -- chenlelin Wed, 02 Sep 2020 14:33:02 +0800 + +kylin-nm (1.2.3-1kylin14) v101; urgency=medium + + * Fix bug wait 1 minute when send desktop notify if install KDE desktop environment. + + -- chenlelin Fri, 21 Aug 2020 14:53:02 +0800 + +kylin-nm (1.2.3-1kylin13) v101; urgency=medium + + * Fix bug can not connect wired network sometimes when there more than one wired network adapter. + + -- chenlelin Wed, 19 Aug 2020 09:15:02 +0800 + +kylin-nm (1.2.3-1kylin12) v101; urgency=medium + + * Upload. + + -- chenlelin Fri, 14 Aug 2020 17:20:02 +0800 + +kylin-nm (1.2.3-1kylin11) v101; urgency=medium + + * Fix bug show abnormal desktop notification sometimes when start operation system. + * Fix bug show abnormal UI from wired to wireless after plug in wireless card. + * Fix bug wired config window can not show top when clicking information of this wired net. + + -- chenlelin Fri, 14 Aug 2020 16:55:02 +0800 + +kylin-nm (1.2.3-1kylin10) v101; urgency=medium + + * upload. + + -- chenlelin Sat, 08 Aug 2020 10:09:02 +0800 + +kylin-nm (1.2.3-1kylin9) v101; urgency=medium + + * open ground glass effect by oneself. + * change the style of wifi switch. + + -- chenlelin Sat, 08 Aug 2020 09:01:02 +0800 + +kylin-nm (1.2.3-1kylin8) v101; urgency=medium + + * Fix bug can not show normal in some 2k screen. + * Add more syslog. + + -- chenlelin Mon, 20 Jul 2020 14:13:02 +0800 + +kylin-nm (1.2.3-1kylin7) v101; urgency=medium + + * Add function to change transparency of window by get transparent data from gsettings method. + + -- chenlelin Tue, 30 Jun 2020 09:57:02 +0800 + +kylin-nm (1.2.3-1kylin6) v101; urgency=medium + + * Fix bug program crash when click to configure a wifi if use old version network-manager. + * Fix bug can not show already connected wifi in add hide wifi window if use old version network-manager. + * Fix bug can not create new wired network. + + -- chenlelin Mon, 15 Jun 2020 16:13:02 +0800 + +kylin-nm (1.2.3-1kylin5) v101; urgency=medium + + * Update tray icons, delete code do not need anymore, add more comments. + + -- chenlelin Thu, 28 May 2020 15:13:02 +0800 + +kylin-nm (1.2.3-1kylin4) v101; urgency=medium + + * Fix bug wired list information can not refresh after changing configuration of a wired network. + + -- chenlelin Thu, 21 May 2020 9:26:02 +0800 + +kylin-nm (1.2.3-1kylin3) v101; urgency=medium + + * Fix bug wired network can not connected automatically after wired cable plugin. + * Fix bug can not connect wifi any more if input wrong password at first time. + * Fix bug wifi switch can not show correct state after turning on or off it. + + -- chenlelin Tue, 19 May 2020 20:36:02 +0800 + +kylin-nm (1.2.3-1kylin2) v101; urgency=medium + + * Merge code for UKUI3.0 and v100 and v101. + + -- chenlelin Thu, 19 May 2020 10:36:02 +0800 + +kylin-nm (1.2.3-1kylin1) v101; urgency=medium + + * Rebuild kylin-nm for V10.1. + + -- chenlelin Thu, 07 May 2020 16:57:02 +0800 + +kylin-nm (1.2.3-1) unstable; urgency=medium + + * New upstream bugfix release: + - Fix the error when communicate with ukui-control-center. + - Can't click save button when there is empty entry when configure + network. + - Fix the incorrect position of some buttons. + - Fix the crash when switch the wifi. + - Fix the wrong position between upload icon and download icon. + - Fix the occasional crash when get ipv4 and ipv6. + - Fix the wrong position of right-click menu. + - Fix that can't get normal message from ukui-panel. + - Fix that no notification after modify the configuration. + - Fix the error when state of connection and speed of network + display at the same time. + * debian/control: + - Add libgsettings-qt-dev, libkf5windowsystem-dev to build-depends. + + -- handsome_feng Mon, 06 Apr 2020 23:11:15 +0800 + +kylin-nm (1.2.2.1-1) unstable; urgency=medium + + * Remove the .qmake.stash witch cause the build failed. + + -- handsome_feng Sat, 14 Mar 2020 18:48:03 +0800 + +kylin-nm (1.2.2-1) unstable; urgency=medium + + * New upstream release. + - Fix that the connect button display at wrong place. + - Fix that sometimes failed to switch network type. + - Fix the problem in multiscreen. + - Adjust the style sheet. + - Show configure window when click network info widget. + - Add the function to create new network. + * debian/control: + - Drop libnotify-bin from build-depends. + + -- handsome_feng Sat, 14 Mar 2020 15:15:38 +0800 + +kylin-nm (1.2.1-1) unstable; urgency=medium + + [ lixiang ] + * update kylin-nm.pro and rules. + + -- handsome_feng Wed, 26 Feb 2020 00:21:11 +0800 + +kylin-nm (1.2.0-1) unstable; urgency=medium + + * New upstream release. + * debian/control: + - Bump standards-version to 4.5.0. + + [ lixiang ] + * update kylin-nm.pro and rules. + + * Remove the depend package libnotify-bin. + * User can config network by clicking information button about IP. + * kylin-nm enable create new wired net now. + + -- handsome_feng Tue, 25 Feb 2020 14:12:29 +0800 + +kylin-nm (1.0.4-1) unstable; urgency=medium + + * New upstream release. + * debian/control: + - Bump standards-version to 4.4.1. No changes needed. + * debian/{compat,control}: + - Use debhelper-compat notation. Bump to DH compat level + version 12. + + -- handsome_feng Mon, 02 Dec 2019 09:48:37 +0800 + +kylin-nm (1.0.3-1) unstable; urgency=medium + + * New upstream release: + - Fix that the connect state doesn't update after net cable plug in or + out. (LP: #1831818) + - Add the function to connect to hidden wireless network. (LP: #1829807) + * Debian/control: Bump standards vertion to 4.4.0. + + -- handsome_feng Thu, 26 Sep 2019 19:28:24 +0800 + +kylin-nm (1.0.2-0ubuntu1) eoan; urgency=medium + + * Bug-fix only: + - Fix the wrong connection status. (LP: #1823843) + - Fix that unable to close after turned on the network. + (LP: #1823844) + - Implement singleton pattern. (LP: #1823845) + + -- handsome_feng Tue, 16 Apr 2019 21:16:36 +0800 + +kylin-nm (1.0.0-1) unstable; urgency=medium + + * Initial release. (Closes: #919549) + + -- handsome_feng Thu, 17 Jan 2019 15:49:40 +0800 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..5a461d49 --- /dev/null +++ b/debian/control @@ -0,0 +1,48 @@ +Source: kylin-nm +Section: utils +Priority: optional +Maintainer: Kylin Team +Uploaders: handsome_feng +Build-Depends: debhelper (>=9), + qtbase5-dev, + qt5-qmake, + qtchooser, + qtscript5-dev, + qttools5-dev-tools, + qtbase5-dev-tools, + libqt5x11extras5-dev, + libgsettings-qt-dev, + libkf5windowsystem-dev, + libx11-dev, + libqt5svg5-dev, + libkf5networkmanagerqt-dev (>= 5.36.0), + libnm-dev, + libcap-dev, + libnma-dev, + libsecret-1-dev, + libgtk-3-dev, + libukcc-dev (>= 3.1.1+1217), + libukui-log4qt-dev, + libkysdk-qtwidgets-dev(>= 1.2.0), + libkysdk-sysinfo-dev, + libkysdk-waylandhelper-dev(>= 1.2.0kylin2), + libkysec-dev, +Standards-Version: 4.5.0 +Rules-Requires-Root: no +Homepage: https://github.com/ukui/kylin-nm +Vcs-Git: https://github.com/ukui/kylin-nm.git +Vcs-Browser: https://github.com/ukui/kylin-nm + +Package: kylin-nm +Architecture: any +Depends: network-manager (>= 1.22.10-1kylin29k3.6), + ukui-control-center (>= 3.1.1+1217), + libkysdk-qtwidgets(>= 1.2.0), + libkysdk-waylandhelper(>= 1.2.0kylin2), + libkysdk-sysinfo, + ${shlibs:Depends}, + ${misc:Depends} +Description: Gui Applet tool for display and edit network simply + Kylin NM is a Applet tool for managing network settings simply. + It has beautiful UI and very comfortable to use. + It's better work together with UKUI. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..ab540d0e --- /dev/null +++ b/debian/copyright @@ -0,0 +1,25 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: kylin-nm +Upstream-Contact: Kylin Team +Source: https://github.com/ukui/kylin-nm + +Files: * +Copyright: 2019, Tianjin KYLIN Information Technology Co., Ltd. +License: GPL-3+ + +License: GPL-3+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Genaral Public License for more details. + . + You should have received a copy og the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". diff --git a/debian/kylin-nm.manpages b/debian/kylin-nm.manpages new file mode 100644 index 00000000..9691523b --- /dev/null +++ b/debian/kylin-nm.manpages @@ -0,0 +1 @@ +man/kylin-nm.1 \ No newline at end of file diff --git a/debian/kylin-nm.postinst b/debian/kylin-nm.postinst new file mode 100755 index 00000000..e99563ba --- /dev/null +++ b/debian/kylin-nm.postinst @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +PROGRAM=$(dpkg-divert --truename /usr/bin/kylin-nm) + +if setcap cap_net_raw+ep $PROGRAM; then + chmod u-s $PROGRAM +fi + +echo "kylin nm set cap success" + +exit 0 + diff --git a/debian/kylin-nm.preinst b/debian/kylin-nm.preinst new file mode 100755 index 00000000..8b913081 --- /dev/null +++ b/debian/kylin-nm.preinst @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +path="/usr/lib/`/usr/bin/dpkg-architecture -qDEB_TARGET_MULTIARCH`/ukui-control-center/libnetconnect.so" +dpkg-divert --package kylin-nm --rename --divert "$path"".old" --add $path + +path2="/usr/lib/`/usr/bin/dpkg-architecture -qDEB_TARGET_MULTIARCH`/ukui-control-center/libproxy.so" +dpkg-divert --package kylin-nm --rename --divert "$path2"".old" --add $path2 diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..2da18dca --- /dev/null +++ b/debian/rules @@ -0,0 +1,34 @@ +#!/usr/bin/make -f + +export QT_SELECT=5 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +QMAKE_OPTS = DEFINES+=NO_DEBUG_ON_CONSOLE +MAKE_OPTS = PREFIX=/usr QMAKE=qmake LRELEASE=lrelease QMAKE_OPTS="$(QMAKE_OPTS)" + +override_dh_auto_configure: + QT_SELECT=qt5 dh_auto_configure \ + -- "QMAKE_CXXFLAGS=$(CFLAGS)" \ + kylin-nm.pro + +%: + dh $@ + +override_dh_install: + dh_install + +override_dh_missing: + dh_missing --fail-missing + +override_dh_auto_clean: + [ ! -d .moc ] || $(RM) -r .moc + [ ! -d .obj ] || $(RM) -r .obj + [ ! -d .ui ] || $(RM) -r .ui + [ ! -f Makefile ] || dh_auto_clean + +override_dh_auto_build: + dh_auto_build -- $(MAKE_OPTS) + +override_dh_shlibdeps: + dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info + diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 00000000..89ae9db8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/watch b/debian/watch new file mode 100644 index 00000000..8253cbbc --- /dev/null +++ b/debian/watch @@ -0,0 +1,2 @@ +version=4 +https://github.com/ukui/kylin-nm/releases .*/kylin-nm_(\d\S+)\.orig\.tar\.gz diff --git a/kylin-nm.pro b/kylin-nm.pro new file mode 100644 index 00000000..7b52af76 --- /dev/null +++ b/kylin-nm.pro @@ -0,0 +1,14 @@ +TEMPLATE = subdirs + +CONFIG += ordered \ + qt + +SUBDIRS = \ + plugins/plugin.pro \ + src \ + +TRANSLATIONS += \ + translations/kylin-nm_zh_CN.ts \ + translations/kylin-nm_tr.ts \ + translations/kylin-nm_bo.ts \ + translations/kylin-nm_bo_CN.ts diff --git a/man/kylin-nm.1 b/man/kylin-nm.1 new file mode 100644 index 00000000..846cd7eb --- /dev/null +++ b/man/kylin-nm.1 @@ -0,0 +1,20 @@ +.\" Man page for Kylin-nm +.TH KYLIN-NM 1 "20 September 2019" "UKUI Desktop Environment" +.\" Please adjust this date when revising the manpage. +.\" +.SH "NAME" +kylin-nm \- The tool for the UKUI Desktop Environment +.SH "SYNOPSIS" +.B kylin-nm +.SH "DESCRIPTION" +The \fBkylin-nm\fR program is a part of the ukui-indicators, It provides network manager for the the UKUI Desktop Environment. Detect the system disk automatically, Can pop up and open the device. +.PP +This manual page documents the \fBkylin-nm\fR command. +.P +.SH "BUGS" +.SS Should you encounter any bugs, they may be reported at: +https://github.com/ukui/kylin-nm/issues +.SH "AUTHORS" +.SS This Man Page has been written for the UKUI Desktop Environment by: +shine (2019) +.SH "SEE ALSO" \ No newline at end of file diff --git a/nmqrc.qrc b/nmqrc.qrc new file mode 100644 index 00000000..c379b198 --- /dev/null +++ b/nmqrc.qrc @@ -0,0 +1,133 @@ + + + res/g/down_arrow.png + res/s/rescan/1.png + res/s/rescan/2.png + res/s/rescan/3.png + res/s/rescan/4.png + res/s/rescan/5.png + res/s/rescan/6.png + res/s/rescan/7.png + res/s/rescan/8.png + res/s/rescan/9.png + res/s/rescan/10.png + res/s/rescan/11.png + res/s/rescan/12.png + res/h/hide-pwd.png + res/h/right-pwd.png + res/h/show-pwd.png + res/h/no-pwd-wifi.png + translations/kylin-nm_bo.qm + translations/kylin-nm_tr.qm + translations/kylin-nm_zh_CN.qm + res/x/fly-mode-off.svg + res/x/fly-mode-on.svg + res/x/hot-spot-off.svg + res/x/hot-spot-on.svg + res/x/net-list-bg.svg + res/x/wifi-list-bg.svg + res/x/load-down.png + res/x/load-up.png + res/l/network-offline.png + res/l/network-offline.svg + res/l/network-online.png + res/l/network-online.svg + res/w/wifi-full.png + res/w/wifi-full-pwd.png + res/w/wifi-high.png + res/w/wifi-high-pwd.png + res/w/wifi-low.png + res/w/wifi-low-pwd.png + res/w/wifi-medium.png + res/w/wifi-medium-pwd.png + res/w/wifi-none.png + res/w/wifi-none-pwd.png + res/s/conning-a/1.png + res/s/conning-a/2.png + res/s/conning-a/3.png + res/s/conning-a/4.png + res/s/conning-a/5.png + res/s/conning-a/6.png + res/s/conning-a/7.png + res/s/conning-a/8.png + res/g/close_black.png + res/g/close_white.png + res/s/conning-s/1.png + res/s/conning-s/2.png + res/s/conning-s/3.png + res/s/conning-s/4.png + res/s/conning-s/5.png + res/s/conning-s/6.png + res/s/conning-s/7.png + res/s/conning-s/8.png + res/s/conning-s/9.png + res/s/conning-s/10.png + res/s/conning-s/11.png + res/s/conning-s/12.png + res/x/setup.png + res/x/control.svg + res/w/wifi6-full-pwd.png + res/w/wifi6-full.png + res/w/wifi6-high-pwd.png + res/w/wifi6-high.png + res/w/wifi6-low-pwd.png + res/w/wifi6-low.png + res/w/wifi6-medium-pwd.png + res/w/wifi6-medium.png + res/w/wifi6-none.png + res/w/wifi6+-none.png + res/w/wifi6+-meidum-pwd.png + res/w/wifi6+-medium.png + res/w/wifi6+-medium-pwd.png + res/w/wifi6+-low.png + res/w/wifi6+-low-pwd.png + res/w/wifi6+-high.png + res/w/wifi6+-high-pwd.png + res/w/wifi6+-full.png + res/w/wifi6+-full-pwd.png + res/w/wifi6-none-pwd.png + res/hw/wifi-full-pwd.png + res/hw/wifi-full.png + res/hw/wifi-high-pwd.png + res/hw/wifi-high.png + res/hw/wifi-low-pwd.png + res/hw/wifi-low.png + res/hw/wifi-medium-pwd.png + res/hw/wifi-medium.png + res/hw/wifi-none-pwd.png + res/hw/wifi-none.png + res/hw/wifi6-full-pwd.png + res/hw/wifi6-full.png + res/hw/wifi6-high-pwd.png + res/hw/wifi6-high.png + res/hw/wifi6-low-pwd.png + res/hw/wifi6-low.png + res/hw/wifi6-medium-pwd.png + res/hw/wifi6-medium.png + res/hw/wifi6-none-pwd.png + res/hw/wifi6-none.png + res/hw/wifi6+-full-pwd.png + res/hw/wifi6+-full.png + res/hw/wifi6+-high-pwd.png + res/hw/wifi6+-high.png + res/hw/wifi6+-low-pwd.png + res/hw/wifi6+-low.png + res/hw/wifi6+-medium-pwd.png + res/hw/wifi6+-medium.png + res/hw/wifi6+-none-pwd.png + res/hw/wifi6+-none.png + res/s/conning-b/1.png + res/s/conning-b/2.png + res/s/conning-b/3.png + res/s/conning-b/4.png + res/s/conning-b/5.png + res/s/conning-b/6.png + res/s/conning-b/7.png + res/s/conning-b/8.png + res/s/conning-b/9.png + res/s/conning-b/10.png + res/s/conning-b/11.png + res/s/conning-b/12.png + translations/kylin-nm_bo_CN.qm + + diff --git a/plugins/component/AddBtn/addnetbtn.cpp b/plugins/component/AddBtn/addnetbtn.cpp new file mode 100644 index 00000000..f186a922 --- /dev/null +++ b/plugins/component/AddBtn/addnetbtn.cpp @@ -0,0 +1,110 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "addnetbtn.h" +#include +#include +#include +#include +#include +#include + +#define RADIUS 6.0 + +AddNetBtn::AddNetBtn(bool isWlan, QWidget *parent) : QPushButton(parent) +{ + this->setObjectName("this"); + this->setMinimumSize(QSize(580, 60)); + this->setMaximumSize(QSize(16777215, 60)); + this->setProperty("useButtonPalette", true); + this->setFlat(true); + QPalette pal = this->palette(); + QColor color = pal.color(QPalette::Button); + color.setAlphaF(0.5); + pal.setColor(QPalette::Button, color); + this->setPalette(pal); + QHBoxLayout *addLyt = new QHBoxLayout; + + QLabel *iconLabel = new QLabel(); + QLabel *textLabel = new QLabel(); + + if (isWlan) { + textLabel->setText(tr("Add Others")); + addLyt->addSpacing(8); + addLyt->addWidget(textLabel); + } else { + textLabel->setText(tr("Add WiredNetork")); + QIcon mAddIcon = QIcon::fromTheme("list-add-symbolic"); + iconLabel->setPixmap(mAddIcon.pixmap(mAddIcon.actualSize(QSize(24, 24)))); + iconLabel->setProperty("useIconHighlightEffect", true); + iconLabel->setProperty("iconHighlightEffectMode", 1); + + addLyt->addStretch(); + addLyt->addWidget(iconLabel); + addLyt->addWidget(textLabel); + } + + addLyt->addStretch(); + this->setLayout(addLyt); + +} + +AddNetBtn::~AddNetBtn() +{ + +} + +void AddNetBtn::enterEvent(QEvent *event){ + Q_EMIT enterWidget(); + + QPushButton::enterEvent(event); +} + +void AddNetBtn::leaveEvent(QEvent *event){ + Q_EMIT leaveWidget(); + + QPushButton::leaveEvent(event); +} + +void AddNetBtn::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + painter.setBrush(pal.color(QPalette::Base)); + + QRect rect = this->rect(); + QPainterPath path; + + //设置起点 + path.moveTo(rect.topLeft().x(), rect.topLeft().y()); + path.lineTo(rect.bottomLeft().x(), rect.bottomLeft().y() - RADIUS); + //绘制圆角 圆弧以外切圆的270度位置为起点,逆时针画圆弧运行90度结束 + path.arcTo(QRect(QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 180, 90); + path.lineTo(rect.bottomRight().x() - RADIUS, rect.bottomRight().y()); + //画圆弧 + path.arcTo(QRect(QPoint(rect.bottomRight().x() - (RADIUS * 2), rect.bottomRight().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 270, 90); + path.lineTo(rect.topRight()); + path.lineTo(rect.topLeft()); + + painter.drawPath(path); + QPushButton::paintEvent(event); +} diff --git a/plugins/component/AddBtn/addnetbtn.h b/plugins/component/AddBtn/addnetbtn.h new file mode 100644 index 00000000..959d2d09 --- /dev/null +++ b/plugins/component/AddBtn/addnetbtn.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef ADDNETBTN_H +#define ADDNETBTN_H + +#include +#include +#include +#include +#include + +class AddNetBtn : public QPushButton +{ + Q_OBJECT +public: + AddNetBtn(bool isWlan, QWidget *parent = nullptr); + ~AddNetBtn(); + +protected: + virtual void leaveEvent(QEvent * event); + virtual void enterEvent(QEvent * event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void enterWidget(); + void leaveWidget(); +}; + +#endif // ADDNETBTN_H diff --git a/plugins/component/AddBtn/grayinfobutton.cpp b/plugins/component/AddBtn/grayinfobutton.cpp new file mode 100644 index 00000000..daa4fa1d --- /dev/null +++ b/plugins/component/AddBtn/grayinfobutton.cpp @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "grayinfobutton.h" + +#include + +#define BUTTON_SIZE 36,36 +#define ICON_SIZE 16,16 + +GrayInfoButton::GrayInfoButton(QWidget *parent): QPushButton(parent) +{ + this->setFixedSize(BUTTON_SIZE); + this->setIcon(QIcon::fromTheme("preferences-system-details-symbolic")); + this->setProperty("useButtonPalette", true); + this->setFlat(true); +} diff --git a/plugins/component/AddBtn/grayinfobutton.h b/plugins/component/AddBtn/grayinfobutton.h new file mode 100644 index 00000000..0024f8b7 --- /dev/null +++ b/plugins/component/AddBtn/grayinfobutton.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef GRAYINFOBUTTON_H +#define GRAYINFOBUTTON_H + +#include +#include + +class GrayInfoButton : public QPushButton +{ + Q_OBJECT +public: + explicit GrayInfoButton(QWidget * parent = nullptr); + ~GrayInfoButton() = default; +}; + +#endif // GRAYINFOBUTTON_H diff --git a/plugins/component/DrownLabel/drownlabel.cpp b/plugins/component/DrownLabel/drownlabel.cpp new file mode 100644 index 00000000..356c7d23 --- /dev/null +++ b/plugins/component/DrownLabel/drownlabel.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "drownlabel.h" +#include "deviceframe.h" + +#define ICONSIZE 16,16 +DrownLabel::DrownLabel(QString devName, QWidget * parent) : QLabel(parent) +{ + m_devName = devName; + setFixedSize(36,36); + loadPixmap(isChecked); + this->setProperty("useIconHighlightEffect", 0x2); +} + +DrownLabel::~DrownLabel() +{ + +} +void DrownLabel::setDropDownStatus(bool status) +{ + isChecked = status; + loadPixmap(isChecked); +} + +void DrownLabel::loadPixmap(bool isChecked) +{ + if (isChecked) { + setPixmap(QIcon::fromTheme("ukui-up-symbolic").pixmap(ICONSIZE)); + } else { + setPixmap(QIcon::fromTheme("ukui-down-symbolic").pixmap(ICONSIZE)); + } +} + +void DrownLabel::mouseReleaseEvent(QMouseEvent *event) +{ + emit labelClicked(); + QWidget::mouseReleaseEvent(event); +} diff --git a/plugins/component/DrownLabel/drownlabel.h b/plugins/component/DrownLabel/drownlabel.h new file mode 100644 index 00000000..281af51f --- /dev/null +++ b/plugins/component/DrownLabel/drownlabel.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DROWNLABEL_H +#define DROWNLABEL_H + +#include +#include +#include +#include + +class DrownLabel : public QLabel +{ + Q_OBJECT +public: + explicit DrownLabel(QString devName, QWidget * parent = nullptr); + ~DrownLabel(); + void setDropDownStatus(bool status); + QString m_devName; + bool isChecked = true; +private: + void loadPixmap(bool isChecked); +protected: + virtual void mouseReleaseEvent(QMouseEvent * event); + +Q_SIGNALS: + void labelClicked(); +}; + +#endif // DROWNLABEL_H diff --git a/plugins/component/InfoButton/infobutton.cpp b/plugins/component/InfoButton/infobutton.cpp new file mode 100644 index 00000000..27a33f98 --- /dev/null +++ b/plugins/component/InfoButton/infobutton.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "infobutton.h" +#include +#include +#include +#include + +#define BUTTON_SIZE 36,36 +#define ICON_SIZE 16,16 +#define BACKGROUND_COLOR QColor(0,0,0,0) +#define FOREGROUND_COLOR_NORMAL qApp->palette().text().color() +#define FOREGROUND_COLOR_HOVER QColor(55,144,250,255) +#define FOREGROUND_COLOR_PRESS QColor(36,109,212,255) +#define OUTER_PATH 8,8,16,16 +#define INNER_PATH 9,9,14,14 +#define TEXT_POS 14,5,16,16,0 + +#define BUTTON_SIZE 36,36 + +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" + +InfoButton::InfoButton(QWidget *parent) : QPushButton(parent) +{ + this->setFixedSize(BUTTON_SIZE); + initUI(); + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + m_styleGsettings = new QGSettings(style_id); + connect(m_styleGsettings, &QGSettings::changed, this, &InfoButton::onGSettingChaned); + } else { + qDebug() << "Gsettings interface \"org.ukui.style\" is not exist!"; + } +} + +void InfoButton::initUI() +{ + this->setFixedSize(BUTTON_SIZE); + m_backgroundColor = BACKGROUND_COLOR; + m_foregroundColor = FOREGROUND_COLOR_NORMAL; +} + +void InfoButton::onGSettingChaned(const QString &key) +{ + if (key == COLOR_THEME) { + m_foregroundColor = FOREGROUND_COLOR_NORMAL; + this->repaint(); + } +} + +void InfoButton::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + pal.setColor(QPalette::Base, m_backgroundColor); + pal.setColor(QPalette::Text, m_foregroundColor); + + QPainterPath cPath; + cPath.addRect(0, 0, ICON_SIZE); + cPath.addEllipse(0, 0, ICON_SIZE); + + QPainterPath outerPath; + outerPath.addEllipse(OUTER_PATH); + + QPainterPath innerPath; + innerPath.addEllipse(INNER_PATH); + outerPath -= innerPath; + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + + painter.setBrush(pal.color(QPalette::Base)); + painter.drawPath(cPath); + + painter.fillPath(outerPath, pal.color(QPalette::Text)); + painter.setPen(m_foregroundColor); + QFont font("Noto Sans CJK SC", 11, QFont::Normal, false); + painter.setFont(font); + painter.drawText(TEXT_POS, "i"); +} + +void InfoButton::enterEvent(QEvent *event) +{ + m_foregroundColor = FOREGROUND_COLOR_HOVER; + this->repaint(); +} + +void InfoButton::leaveEvent(QEvent *event) +{ + m_foregroundColor = FOREGROUND_COLOR_NORMAL; + this->repaint(); +} + +void InfoButton::mousePressEvent(QMouseEvent *event) +{ + m_foregroundColor = FOREGROUND_COLOR_PRESS; + this->repaint(); + return QPushButton::mousePressEvent(event); +} + +void InfoButton::mouseReleaseEvent(QMouseEvent *event) +{ + m_foregroundColor = FOREGROUND_COLOR_HOVER; + this->repaint(); + return QPushButton::mouseReleaseEvent(event); +} diff --git a/plugins/component/InfoButton/infobutton.h b/plugins/component/InfoButton/infobutton.h new file mode 100644 index 00000000..f4607ade --- /dev/null +++ b/plugins/component/InfoButton/infobutton.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef INFOBUTTON_H +#define INFOBUTTON_H +#include +#include +#include + +class InfoButton : public QPushButton +{ + Q_OBJECT +public: + explicit InfoButton(QWidget * parent = nullptr); + ~InfoButton() = default; + +protected: + void paintEvent(QPaintEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +private: + void initUI(); + +private: + QColor m_backgroundColor; + QColor m_foregroundColor; + + //监听主题的Gsettings + QGSettings * m_styleGsettings = nullptr; + +private slots: + void onGSettingChaned(const QString &key); +}; + +#endif // INFOBUTTON_H diff --git a/plugins/component/SwitchButton/switchbutton.cpp b/plugins/component/SwitchButton/switchbutton.cpp new file mode 100644 index 00000000..a7e62f65 --- /dev/null +++ b/plugins/component/SwitchButton/switchbutton.cpp @@ -0,0 +1,327 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "switchbutton.h" + +#include +#define THEME_QT_SCHEMA "org.ukui.style" +#define THEME_GTK_SCHEMA "org.mate.interface" +#define TIMER_INTERVAL 5 //每隔5ms动画移动一次 +#define MOVING_STEPS 40 //动画总共移动40次 + +SwitchButton::SwitchButton(QWidget *parent, bool useDisableStyle) : + QWidget(parent) +{ +// this->resize(QSize(52, 24)); + this->setFixedSize(QSize(50, 24)); + + checked = false; + hover = false; + disabled = false; + isMoving = false; + isAnimation = true; + m_useDisableStyle = useDisableStyle; + + space = 4; + rectRadius = height()/2; + + mStep = width()/MOVING_STEPS;//也就是40次动画就可以走完,每次时间间隔是固定的5ms + mStartX = 0; + mEndX= 0; + + mTimer = new QTimer(this); + mTimer->setInterval(TIMER_INTERVAL);//动画更新时间 + connect(mTimer, SIGNAL(timeout()), this, SLOT(updatevalue())); + if(QGSettings::isSchemaInstalled(THEME_GTK_SCHEMA) && QGSettings::isSchemaInstalled(THEME_QT_SCHEMA)) { + QByteArray qtThemeID(THEME_QT_SCHEMA); + QByteArray gtkThemeID(THEME_GTK_SCHEMA); + + m_gtkThemeSetting = new QGSettings(gtkThemeID,QByteArray(),this); + m_qtThemeSetting = new QGSettings(qtThemeID,QByteArray(),this); + + QString style = m_qtThemeSetting->get("styleName").toString(); + changeColor(style); + + connect(m_qtThemeSetting,&QGSettings::changed, [this] (const QString &key) { + QString style = m_qtThemeSetting->get("styleName").toString(); + if (key == "styleName") { + changeColor(style); + } + }); + } +} + +SwitchButton::~SwitchButton() +{ +} + +void SwitchButton::paintEvent(QPaintEvent *){ + + QPainter painter(this); + //启用反锯齿 + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setCompositionMode(QPainter::CompositionMode_Source); + drawBg(&painter); + if(!isAnimation)//动画如果禁用,则圆形滑块isMoving始终为false + isMoving =false; + if(isMoving) + animation(&painter); + drawSlider(&painter); + painter.end(); +} + +void SwitchButton::changeColor(const QString &themes) { + if (hover) { + return ;//在鼠标下,禁止切换颜色鼠标离开时切换颜色 + } + if (themes == "ukui-dark" || themes == "ukui-black") { + bgColorOff = QColor(OFF_BG_DARK_COLOR); + bgColorOn = QColor(ON_BG_DARK_COLOR); + rectColorEnabled = QColor(ENABLE_RECT_DARK_COLOR); + rectColorDisabled = QColor(DISABLE_RECT_DARK_COLOR); + sliderColorDisabled = QColor(DISABLE_RECT_DARK_COLOR); + sliderColorEnabled = QColor(ENABLE_RECT_DARK_COLOR); + bgHoverOnColor = QColor(ON_HOVER_BG_DARK_COLOR); + bgHoverOffColor = QColor(OFF_HOVER_BG_DARK_COLOR); + bgColorDisabled = QColor(DISABLE_DARK_COLOR); + } else { + bgColorOff = QColor(OFF_BG_LIGHT_COLOR); + bgColorOn = QColor(ON_BG_LIGHT_COLOR); + rectColorEnabled = QColor(ENABLE_RECT_LIGHT_COLOR); + rectColorDisabled = QColor(DISABLE_RECT_LIGHT_COLOR); + sliderColorDisabled = QColor(DISABLE_RECT_LIGHT_COLOR); + sliderColorEnabled = QColor(ENABLE_RECT_LIGHT_COLOR); + bgHoverOnColor = QColor(ON_HOVER_BG_LIGHT_COLOR); + bgHoverOffColor = QColor(OFF_HOVER_BG_LIGHT_COLOR); + bgColorDisabled = QColor(DISABLE_LIGHT_COLOR); + } +} + +//动画绘制 +void SwitchButton::animation(QPainter *painter){ + painter->save(); + int h = height(); + int w = width(); + painter->setPen(Qt::NoPen); + //颜色设置 + if(checked){ + //开关在左侧时 + painter->setBrush(bgColorOn); + rect.setRect(0,0,h+mStartX,h); + }else{ + painter->setBrush(bgColorOff); + rect.setRect(mStartX,0,w-mStartX,h); + } + painter->drawRoundedRect(rect,rectRadius,rectRadius); + + painter->restore(); +} + +//绘制背景 +void SwitchButton::drawBg(QPainter *painter){ + int w = width(); + int h = height(); + painter->save(); + painter->setPen(Qt::NoPen); + if (disabled && m_useDisableStyle) { + painter->setPen(Qt::NoPen); + painter->setBrush(bgColorDisabled); + } else { + if(checked){ + if(isMoving){ + painter->setBrush(bgColorOff); + rect.setRect(mStartX,0,w-mStartX,h); + }else { + painter->setBrush(bgColorOn); + rect.setRect(0, 0, w, h); + } + }else{ + if(isMoving){ + painter->setBrush(bgColorOn); + rect.setRect(0,0,mStartX+h,h); + } + else { + painter->setBrush(bgColorOff); + rect.setRect(0, 0, w, h); + } + } + } + //半径为高度的一半 + painter->drawRoundedRect(rect,rectRadius,rectRadius); + + painter->restore(); +} + +//绘制滑块,也就是圆形按钮 +void SwitchButton::drawSlider(QPainter *painter){ + painter->save(); + painter->setPen(Qt::NoPen); + + if (!disabled || !m_useDisableStyle){ + painter->setBrush(sliderColorEnabled); + } + else + painter->setBrush(sliderColorDisabled); + if (disabled) { + if (!checked){ + QRect smallRect(8, height() / 2 - 2, 10 , 4); + painter->drawRoundedRect(smallRect,3,3); + }else{ + QRect smallRect(width() - 8 * 2, height() / 2 - 2, 10 , 4); + painter->drawRoundedRect(smallRect,3,3); + } + } + + QRect rect(0, 0, width(), height()); + int sliderWidth = rect.height() - space * 2; + QRect sliderRect(mStartX + space, space, sliderWidth, sliderWidth); + painter->drawEllipse(sliderRect); + + painter->restore(); +} + +void SwitchButton::mousePressEvent(QMouseEvent *){ + qDebug()<start(); + isMoving = true; + } +} + +void SwitchButton::resizeEvent(QResizeEvent *){ + //每次开始的x坐标都是跳过圆角,从直线的地方开始计算 + mStep = width() / MOVING_STEPS; + + if (checked){ + //circle out +// startX = width() - height() + space; + //circle in + mStartX = width() - height(); + } + else + mStartX = 0; + + rectRadius = height()/2; + update(); +} +void SwitchButton::enterEvent(QEvent *event) { + bgColorOn = bgHoverOnColor; + bgColorOff = bgHoverOffColor; + + hover = true; + update(); + return QWidget::enterEvent(event); +} + +void SwitchButton::leaveEvent(QEvent *event) { + hover = false; + + QString style = m_qtThemeSetting->get("styleName").toString(); + changeColor(style); + + update(); + return QWidget::leaveEvent(event); +} + +//根据事件向左还是向右移动 +void SwitchButton::updatevalue(){ + if (checked) + if (mStartX < mEndX-mStep){ + mStartX = mStartX + mStep; + } + else{ + mStartX = mEndX; + mTimer->stop(); + isMoving = false; + } + else{ + if (mStartX > mEndX+mStep){ + mStartX = mStartX - mStep; + } + else{ + mStartX = mEndX; + mTimer->stop(); + isMoving = false; + } + } + update(); +} + +void SwitchButton::setChecked(bool checked){ + if (this->checked != checked){ + this->checked = checked; + Q_EMIT checkedChanged(checked); + update(); + } + + mStep = width() / MOVING_STEPS; + + if (checked){ + //circle out +// endX = width() - height() + space; + //circle in + mEndX = width() - height(); + } + else{ + mEndX = 0; + } + mTimer->start(); + isMoving = true; +} + +bool SwitchButton::isChecked(){ + return this->checked; +} + +void SwitchButton::setDisabledFlag(bool value) +{ + disabled = value; + update(); +} + +bool SwitchButton::getDisabledFlag() +{ + return disabled; +} + +void SwitchButton::setAnimation(bool on){ + isAnimation = on; +} + diff --git a/plugins/component/SwitchButton/switchbutton.h b/plugins/component/SwitchButton/switchbutton.h new file mode 100644 index 00000000..a54e501b --- /dev/null +++ b/plugins/component/SwitchButton/switchbutton.h @@ -0,0 +1,121 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef SWITCHBUTTON_H +#define SWITCHBUTTON_H + +#include +#include +#include +#include +#include +#include + +#define OFF_BG_DARK_COLOR "#404040" +#define OFF_HOVER_BG_DARK_COLOR "#666666" +#define ON_BG_DARK_COLOR "#3790FA" +#define ON_HOVER_BG_DARK_COLOR "#40A9FB" +#define DISABLE_DARK_COLOR "#474747" +#define DISABLE_RECT_DARK_COLOR "#6E6E6E" +#define ENABLE_RECT_DARK_COLOR "#FFFFFF" + +#define OFF_BG_LIGHT_COLOR "#E0E0E0" +#define OFF_HOVER_BG_LIGHT_COLOR "#B3B3B3" +#define ON_BG_LIGHT_COLOR "#3790FA" +#define ON_HOVER_BG_LIGHT_COLOR "#40A9FB" +#define DISABLE_LIGHT_COLOR "#E9E9E9" +#define DISABLE_RECT_LIGHT_COLOR "#B3B3B3" +#define ENABLE_RECT_LIGHT_COLOR "#FFFFFF" + + +class SwitchButton : public QWidget +{ + Q_OBJECT + +public: + SwitchButton(QWidget *parent = 0, bool useDisableStyle = true); + ~SwitchButton(); + + void setChecked(bool checked); + void setAnimation(bool on); + + bool isChecked(); + void setDisabledFlag(bool); + bool getDisabledFlag(); +protected: + void mousePressEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *); + void paintEvent(QPaintEvent *); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + + void drawBg(QPainter * painter); + void drawSlider(QPainter * painter); + void changeColor(const QString &themes); + +private: + bool checked; //切换的判断 + bool disabled; + + void animation(QPainter *painter); + QRect rect; + bool isMoving; //滑块动作判断 + bool isAnimation; // 是否允许动画执行 + + QColor bgColorOff; + QColor bgColorOn; + QColor bgHoverOnColor; + QColor bgHoverOffColor; + QColor bgColorDisabled; + + QColor sliderColorEnabled; + QColor sliderColorDisabled; + + + QColor rectColorEnabled; + QColor rectColorDisabled; + + QColor sliderColorOff; + QColor sliderColorOn; + QGSettings *m_qtThemeSetting; + QGSettings *m_gtkThemeSetting; + + int space; //滑块离背景间隔 + int rectRadius; //圆角角度 + + int mStep; //移动步长 + int mStartX; + int mEndX; + + bool hover; + QTimer * mTimer; + + bool m_useDisableStyle; + + +private Q_SLOTS: + void updatevalue(); + + +Q_SIGNALS: + void checkedChanged(bool checked); + void disabledClick(); +}; + +#endif // SWITCHBUTTON_H diff --git a/plugins/component/addbtn.pri b/plugins/component/addbtn.pri new file mode 100644 index 00000000..f3961167 --- /dev/null +++ b/plugins/component/addbtn.pri @@ -0,0 +1,11 @@ +#LIBINTERFACE_NAME = $$qtLibraryTarget(addnetbtn) + +SOURCES += \ + $$PWD/AddBtn/addnetbtn.cpp \ + $$PWD/AddBtn/grayinfobutton.cpp + +HEADERS += \ + $$PWD/AddBtn/addnetbtn.h \ + $$PWD/AddBtn/grayinfobutton.h + + diff --git a/plugins/component/drownlabel.pri b/plugins/component/drownlabel.pri new file mode 100644 index 00000000..185bbd36 --- /dev/null +++ b/plugins/component/drownlabel.pri @@ -0,0 +1,9 @@ +#LIBINTERFACE_NAME = $$qtLibraryTarget(drownlabel) + +SOURCES += \ + $$PWD/DrownLabel/drownlabel.cpp \ + +HEADERS += \ + $$PWD/DrownLabel/drownlabel.h \ + + diff --git a/plugins/component/infobutton.pri b/plugins/component/infobutton.pri new file mode 100644 index 00000000..5e84a760 --- /dev/null +++ b/plugins/component/infobutton.pri @@ -0,0 +1,9 @@ +#LIBINTERFACE_NAME = $$qtLibraryTarget(infobutton) + +SOURCES += \ + $$PWD/InfoButton/infobutton.cpp \ + +HEADERS += \ + $$PWD/InfoButton/infobutton.h \ + + diff --git a/plugins/component/switchbutton.pri b/plugins/component/switchbutton.pri new file mode 100644 index 00000000..b1c4b1bc --- /dev/null +++ b/plugins/component/switchbutton.pri @@ -0,0 +1,8 @@ + +#LIBINTERFACE_NAME = $$qtLibraryTarget(switchbutton) + +SOURCES += \ + $$PWD/SwitchButton/switchbutton.cpp \ + +HEADERS += \ + $$PWD/SwitchButton/switchbutton.h \ diff --git a/plugins/mobilehotspot/blacklistitem.cpp b/plugins/mobilehotspot/blacklistitem.cpp new file mode 100644 index 00000000..bc59735d --- /dev/null +++ b/plugins/mobilehotspot/blacklistitem.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "blacklistitem.h" +#include + +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_SPACING 0 +#define ITEM_FRAME_MARGINS 0,0,0,0 +#define ITEM_FRAME_SPACING 10 +#define FRAME_WIDTH 395 +#define INFO_ICON_WIDTH 16 +#define INFO_ICON_HEIGHT 16 +#define LIGHT_HOVER_COLOR QColor(240,240,240,255) +#define DARK_HOVER_COLOR QColor(15,15,15,255) + +#define FRAME_MIN_SIZE 550, 60 +#define CONTECT_FRAME_MAX_SIZE 16777215, 60 +#define LABLE_MIN_WIDTH 188 +#define ITEM_MARGINS 16, 0, 16, 0 + +BlacklistItem::BlacklistItem(QString staMac, QString staName, QWidget *parent) : + QFrame(parent), + m_mac(staMac), + m_hostName(staName) +{ + this->setMinimumHeight(60); + this->setFixedHeight(60); + + QHBoxLayout *hItemLayout = new QHBoxLayout(this); + hItemLayout->setContentsMargins(ITEM_MARGINS); + QLabel *nameLabel = new QLabel(staName, this); + m_removeFromBlacklistBtn = new KBorderlessButton(this); + m_removeFromBlacklistBtn->setText(tr("Remove")); + hItemLayout->setSpacing(0); + hItemLayout->addWidget(nameLabel, Qt::AlignLeft); + hItemLayout->addStretch(); + hItemLayout->addWidget(m_removeFromBlacklistBtn, Qt::AlignRight); + + m_removeFromBlacklistBtn->installEventFilter(this); + this->setLayout(hItemLayout); +} + +bool BlacklistItem::eventFilter(QObject *w, QEvent *e) +{ + if (e->type() == QEvent::MouseButtonRelease) { + if (w == m_removeFromBlacklistBtn) { + emit onBtnClicked(m_mac, m_hostName); + return true; + } + } + return QWidget::eventFilter(w,e); +} + diff --git a/plugins/mobilehotspot/blacklistitem.h b/plugins/mobilehotspot/blacklistitem.h new file mode 100644 index 00000000..dab02aae --- /dev/null +++ b/plugins/mobilehotspot/blacklistitem.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef BLACKLISTITEM_H +#define BLACKLISTITEM_H +#include +#include +#include +#include +#include +#include +#include +#include "kborderlessbutton.h" + +using namespace kdk; + +class BlacklistItem : public QFrame +{ + Q_OBJECT +public: + BlacklistItem(QString staMac, QString staName, QWidget *parent = nullptr); + +protected: + KBorderlessButton *m_removeFromBlacklistBtn = nullptr; + + QString m_mac; + QString m_hostName; + bool eventFilter(QObject *w, QEvent *e); + +signals: + void onBtnClicked(QString staMac, QString staName); + + +}; + +#endif // LISTITEM_H diff --git a/plugins/mobilehotspot/blacklistpage.cpp b/plugins/mobilehotspot/blacklistpage.cpp new file mode 100644 index 00000000..1b82d8bd --- /dev/null +++ b/plugins/mobilehotspot/blacklistpage.cpp @@ -0,0 +1,200 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "blacklistpage.h" +#include + +#define CONTENTS_MARGINS 0, 0, 0, 0 +#define FRAME_MIN_SIZE 550, 60 +#define FRAME_MAX_SIZE 16777215, 16777215 +#define LINE_MAX_SIZE 16777215, 1 +#define LINE_MIN_SIZE 0, 1 + +#define LOG_HEAD "[BlacklistPage]" + +BlacklistPage::BlacklistPage(QWidget *parent) : QWidget(parent) +{ + QVBoxLayout *Vlayout = new QVBoxLayout(this); + Vlayout->setContentsMargins(CONTENTS_MARGINS); + Vlayout->setSpacing(0); + + QFrame *blacklistFrame = new QFrame(this); + blacklistFrame->setMinimumSize(FRAME_MIN_SIZE); + blacklistFrame->setMaximumSize(FRAME_MAX_SIZE); + blacklistFrame->setFrameShape(QFrame::Box); + + m_blacklistLayout = new QVBoxLayout(blacklistFrame); + m_blacklistLayout->setContentsMargins(0, 0, 0, 0); + m_blacklistLayout->setSpacing(0); + + m_titleLabel = new TitleLabel(this); + m_titleLabel->setText(tr("Blacklist")); + + Vlayout->addWidget(m_titleLabel); + Vlayout->addSpacing(8); + Vlayout->addWidget(blacklistFrame); +} + +QFrame* BlacklistPage::myLine() +{ + QFrame *line = new QFrame(this); + line->setMinimumSize(QSize(LINE_MIN_SIZE)); + line->setMaximumSize(QSize(LINE_MAX_SIZE)); + line->setLineWidth(0); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + return line; +} + +void BlacklistPage::getBlacklistDevice(QMap &blacklistMap) +{ + if (m_settingPathInterface == nullptr || !m_settingPathInterface->isValid()) { + qDebug() << LOG_HEAD << "dbus interface m_settingPathInterface is invaild"; + return; + } + + QDBusMessage reply = m_settingPathInterface->call("Getblacklist"); + if(reply.type() == QDBusMessage::ErrorMessage) + { + qWarning() << LOG_HEAD << "Getblacklist error:" << reply.errorMessage(); + return; + } + if (reply.arguments().isEmpty() + || reply.arguments().at(0).toString() == "" + || reply.arguments().at(1).toString() == "") { + qDebug() << LOG_HEAD << "Dbus interface call Getblacklist return is empty!"; + return; + } + QStringList macList = reply.arguments().at(0).toString().split(";"); + QStringList hostNameList = reply.arguments().at(1).toString().split(";"); + for (int index = 0; index < macList.count() && macList.at(index) != nullptr; index ++) { + QString macTemp = macList.at(index); + macTemp = macTemp.trimmed(); + if (!blacklistMap.contains(macTemp)) { + blacklistMap[macTemp] = hostNameList.at(index); + } + } +} + +void BlacklistPage::initBlacklistDev() +{ + QMap::const_iterator item = m_blacklistMap.cbegin(); + while (item != m_blacklistMap.cend()) { + addBlacklistDevFrame(item.key(), item.value()); + item ++; + if (item != m_blacklistMap.cend()) { + m_blacklistLayout->addWidget(myLine()); + } + } +} + +void BlacklistPage::onsetStaIntoBlacklist(QString staMac, QString staName) +{ + if (m_settingPathInterface == nullptr || !m_settingPathInterface->isValid()) { + qDebug() << LOG_HEAD << LOG_HEAD << "dbus interface m_settingPathInterface is invaild"; + return; + } + + QDBusMessage reply = m_settingPathInterface->call("Addblacklist", staMac, staName); + if(reply.type() == QDBusMessage::ErrorMessage) + { + qWarning() << LOG_HEAD << "Addblacklist error:" << reply.errorMessage(); + return; + } + + refreshBlacklist(); +} + +void BlacklistPage::addBlacklistDevFrame(QString staMac, QString staName) +{ + BlacklistItem *itemFrame = new BlacklistItem(staMac, staName, m_blacklistLayout->widget()); + m_blacklistLayout->addWidget(itemFrame); + connect(itemFrame, &BlacklistItem::onBtnClicked, this, &BlacklistPage::onRemoveFromBlacklistBtnClicked); +} + +void BlacklistPage::clearBlacklistLayout() +{ + if (m_blacklistLayout->layout() != NULL) { + QLayoutItem* layoutItem; + while ((layoutItem = m_blacklistLayout->layout()->takeAt(0)) != NULL) { + delete layoutItem->widget(); + delete layoutItem; + } + } +} + +bool BlacklistPage::removeStaFromBlacklist(QString staMac, QString staName) +{ + if (m_settingPathInterface == nullptr || !m_settingPathInterface->isValid()) { + qDebug() << LOG_HEAD << "dbus interface m_settingPathInterface is invaild"; + return false; + } + + QDBusMessage reply = m_settingPathInterface->call("Delblacklist", staMac, staName); + if(reply.type() == QDBusMessage::ErrorMessage) + { + qWarning() << LOG_HEAD << "Delblacklist error:" << reply.errorMessage(); + return false; + } + + return true; +} + +void BlacklistPage::resetLayoutHight() +{ + int height = 0; + for (int i = 0; i < m_blacklistLayout->count(); i ++) { + QWidget *w = m_blacklistLayout->itemAt(i)->widget(); + if (w != nullptr) { + height += w->height(); + } + } + this->setFixedHeight(height + m_titleLabel->height() + 8); + + if (m_blacklistMap.isEmpty()) { + this->hide(); + } else { + this->show(); + } + this->update(); +} + +void BlacklistPage::refreshBlacklist() +{ + m_blacklistMap.clear(); + getBlacklistDevice(m_blacklistMap); + clearBlacklistLayout(); + initBlacklistDev(); + resetLayoutHight(); +} + +void BlacklistPage::onRemoveFromBlacklistBtnClicked(QString staMac, QString staName) +{ + if (staMac.isNull() + || staMac.isEmpty() + || staName.isNull() + || staName.isEmpty()) { + qDebug() << LOG_HEAD <<"On remove from blacklist button clicked error! sta mac or name is empty!"; + return; + } + removeStaFromBlacklist(staMac, staName); + refreshBlacklist(); +} + diff --git a/plugins/mobilehotspot/blacklistpage.h b/plugins/mobilehotspot/blacklistpage.h new file mode 100644 index 00000000..a1e3f01d --- /dev/null +++ b/plugins/mobilehotspot/blacklistpage.h @@ -0,0 +1,73 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef BLACKLISTPAGE_H +#define BLACKLISTPAGE_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "titlelabel.h" +#include "blacklistitem.h" + +using namespace kdk; + +class BlacklistPage : public QWidget +{ + Q_OBJECT +public: + explicit BlacklistPage(QWidget *parent = nullptr); + + void refreshBlacklist(); + bool setStaIntoBlacklist(QString staMac); + + inline void setInterface(QDBusInterface *settingInterface) { + m_settingPathInterface = settingInterface; + } + +private: + + QFrame* myLine(); + + TitleLabel *m_titleLabel = nullptr; + QVBoxLayout *m_blacklistLayout = nullptr; + QMap m_blacklistMap; + + QDBusInterface *m_settingPathInterface = nullptr; + + void getBlacklistDevice(QMap &blacklistMap); + bool removeStaFromBlacklist(QString staMac, QString staName); + void initBlacklistDev(); + void addBlacklistDevFrame(QString staMac, QString staName); + void clearBlacklistLayout(); + void resetLayoutHight(); + +private slots: + void onsetStaIntoBlacklist(QString staMac, QString staName); + void onRemoveFromBlacklistBtnClicked(QString staMac, QString staName); +}; + +#endif // MOBILEHOTSPOTWIDGET_H diff --git a/plugins/mobilehotspot/connectdevlistitem.cpp b/plugins/mobilehotspot/connectdevlistitem.cpp new file mode 100644 index 00000000..a8107905 --- /dev/null +++ b/plugins/mobilehotspot/connectdevlistitem.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "connectdevlistitem.h" +#include + +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_SPACING 0 +#define ITEM_FRAME_MARGINS 0,0,0,0 +#define ITEM_FRAME_SPACING 10 +#define FRAME_WIDTH 395 +#define INFO_ICON_WIDTH 16 +#define INFO_ICON_HEIGHT 16 +#define LIGHT_HOVER_COLOR QColor(240,240,240,255) +#define DARK_HOVER_COLOR QColor(15,15,15,255) + +#define FRAME_MIN_SIZE 550, 60 +#define CONTECT_FRAME_MAX_SIZE 16777215, 60 +#define LABLE_MIN_WIDTH 188 +#define ITEM_MARGINS 16, 0, 16, 0 + +ConnectDevListItem::ConnectDevListItem(QString staMac, QString staName, QWidget *parent) : + QFrame(parent), + m_mac(staMac), + m_hostName(staName) +{ + this->setMinimumSize(FRAME_MIN_SIZE); + this->setFixedHeight(60); + + QHBoxLayout *hItemLayout = new QHBoxLayout(this); + hItemLayout->setContentsMargins(ITEM_MARGINS); + QLabel *nameLabel = new QLabel(staName, this); + m_dragIntoBlackListBtn = new KBorderlessButton(this); + m_dragIntoBlackListBtn->setText(tr("drag into blacklist")); + hItemLayout->setSpacing(0); + hItemLayout->addWidget(nameLabel, Qt::AlignLeft); + hItemLayout->addStretch(); + hItemLayout->addWidget(m_dragIntoBlackListBtn, Qt::AlignRight); + + m_dragIntoBlackListBtn->installEventFilter(this); + this->setLayout(hItemLayout); +} + +bool ConnectDevListItem::eventFilter(QObject *w, QEvent *e) +{ + if (e->type() == QEvent::MouseButtonRelease) { + if (w == m_dragIntoBlackListBtn) { + emit onBtnClicked(m_mac, m_hostName); + return true; + } + } + return QWidget::eventFilter(w,e); +} + diff --git a/plugins/mobilehotspot/connectdevlistitem.h b/plugins/mobilehotspot/connectdevlistitem.h new file mode 100644 index 00000000..182d581e --- /dev/null +++ b/plugins/mobilehotspot/connectdevlistitem.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CONNECTDEVLISTITEM_H +#define CONNECTDEVLISTITEM_H +#include +#include +#include +#include +#include +#include +#include +#include "kborderlessbutton.h" + +using namespace kdk; + +class ConnectDevListItem : public QFrame +{ + Q_OBJECT +public: + ConnectDevListItem(QString staMac, QString staName, QWidget *parent = nullptr); + +protected: + KBorderlessButton *m_dragIntoBlackListBtn = nullptr; + + QString m_mac; + QString m_hostName; + bool eventFilter(QObject *w, QEvent *e); + +signals: + void onBtnClicked(QString staMac, QString staName); + + +}; + +#endif // LISTITEM_H diff --git a/plugins/mobilehotspot/connectdevpage.cpp b/plugins/mobilehotspot/connectdevpage.cpp new file mode 100644 index 00000000..f8862e01 --- /dev/null +++ b/plugins/mobilehotspot/connectdevpage.cpp @@ -0,0 +1,191 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "connectdevpage.h" +#include + +#define CONTENTS_MARGINS 0, 0, 0, 0 +#define FRAME_MIN_SIZE 550, 60 +#define FRAME_MAX_SIZE 16777215, 16777215 +#define LINE_MAX_SIZE 16777215, 1 +#define LINE_MIN_SIZE 0, 1 + +#define LOG_HEAD "[ConnectdevPage]" + +ConnectdevPage::ConnectdevPage(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout *Vlayout = new QVBoxLayout(this); + Vlayout->setContentsMargins(CONTENTS_MARGINS); + Vlayout->setSpacing(0); + + QFrame *staistFrame = new QFrame(this); + staistFrame->setMinimumSize(FRAME_MIN_SIZE); + staistFrame->setMaximumSize(FRAME_MAX_SIZE); + staistFrame->setFrameShape(QFrame::Box); + + m_staListLayout = new QVBoxLayout(staistFrame); + m_staListLayout->setContentsMargins(0, 0, 0, 0); + m_staListLayout->setSpacing(0); + + m_titleLabel = new TitleLabel(this); + m_titleLabel->setText(tr("Connect device")); + + Vlayout->addWidget(m_titleLabel); + Vlayout->addSpacing(8); + Vlayout->addWidget(staistFrame); +} + +QFrame* ConnectdevPage::myLine() +{ + QFrame *line = new QFrame(this); + line->setMinimumSize(QSize(LINE_MIN_SIZE)); + line->setMaximumSize(QSize(LINE_MAX_SIZE)); + line->setLineWidth(0); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + return line; +} + +void ConnectdevPage::getConnectStaDevice(QMap &staMap) +{ + staMap.clear(); + if (m_activePathInterface == nullptr || !m_activePathInterface->isValid()) { + qDebug() << LOG_HEAD << "dbus interface m_activePathInterface is invaild"; + return; + } + + QDBusMessage reply = m_activePathInterface->call("Getstainfo"); + if(reply.type() == QDBusMessage::ErrorMessage) + { + qWarning() << LOG_HEAD << "Getstainfo error:" << reply.errorMessage(); + return; + } + + if (reply.arguments().isEmpty() + || reply.arguments().at(0).toString() == "" + || reply.arguments().at(0).toString() == "[Invalid UTF-8]" + || reply.arguments().at(1).toString() == "") { + qDebug() << LOG_HEAD << "Dbus interface call Getstainfo return is empty!"; + return; + } + + QStringList macList = reply.arguments().at(0).toString().split(";"); + QStringList hostNameList = reply.arguments().at(1).toString().split(";"); + for (int index = 0; index < macList.count() && macList.at(index) != nullptr; index ++) { + if (!staMap.contains(macList.at(index))) { + staMap[macList.at(index)] = hostNameList.at(index); + } + } + +} + +void ConnectdevPage::initStaDev() +{ + QMap::const_iterator item = m_staMap.cbegin(); + while (item != m_staMap.cend()) { + addStaDevFrame(item.key(), item.value()); + item ++; + if (item != m_staMap.cend()) { + m_staListLayout->addWidget(myLine()); + } + } +} + +void ConnectdevPage::addStaDevFrame(QString staMac, QString staName) +{ + ConnectDevListItem *itemFrame = new ConnectDevListItem(staMac, staName, m_staListLayout->widget()); + m_staListLayout->addWidget(itemFrame); + connect(itemFrame, &ConnectDevListItem::onBtnClicked, this, &ConnectdevPage::onDropIntoBlacklistBtnClicked); +} + +void ConnectdevPage::clearStaListLayout() +{ + + if (m_staListLayout->layout() != NULL) { + QLayoutItem* layoutItem; + while ((layoutItem = m_staListLayout->layout()->takeAt(0)) != NULL) { + delete layoutItem->widget(); + delete layoutItem; + } + } +} + +void ConnectdevPage::onStaDevAdded(bool istrue, QString staMac, QString staName) +{ + if (!m_staMap.contains(staMac)) { + m_staMap.insert(staMac, staName); + clearStaListLayout(); + initStaDev(); + resetLayoutHight(); + } +} + +void ConnectdevPage::onStaDevRemoved(bool istrue, QString staMac, QString staName) +{ + if (m_staMap.contains(staMac)) { + if (m_staMap.remove(staMac)) { + clearStaListLayout(); + initStaDev(); + resetLayoutHight(); + } + } +} + +void ConnectdevPage::resetLayoutHight() +{ + int height = 0; + for (int i = 0; i < m_staListLayout->count(); i ++) { + QWidget *w = m_staListLayout->itemAt(i)->widget(); + if (w != nullptr) { + height += w->height(); + } + } + this->setFixedHeight(height + m_titleLabel->height() + 8); + + if (m_staMap.isEmpty()) { + this->hide(); + } else { + this->show(); + } + this->update(); +} + +void ConnectdevPage::refreshStalist() +{ + m_staMap.clear(); + getConnectStaDevice(m_staMap); + clearStaListLayout(); + initStaDev(); + resetLayoutHight(); +} + +void ConnectdevPage::onDropIntoBlacklistBtnClicked(QString staMac, QString staName) +{ + if (staMac.isNull() + || staMac.isEmpty() + || staName.isNull() + || staName.isEmpty()) { + qDebug() << LOG_HEAD <<"On drop into blacklist button clicked error! sta mac or name is empty!"; + return; + } + + emit setStaIntoBlacklist(staMac, staName); +} diff --git a/plugins/mobilehotspot/connectdevpage.h b/plugins/mobilehotspot/connectdevpage.h new file mode 100644 index 00000000..944fc995 --- /dev/null +++ b/plugins/mobilehotspot/connectdevpage.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CONNECTDEVPAGE_H +#define CONNECTDEVPAGE_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "titlelabel.h" +#include "connectdevlistitem.h" + +using namespace kdk; + +class ConnectdevPage : public QWidget +{ + Q_OBJECT +public: + explicit ConnectdevPage(QWidget *parent = nullptr); + + void refreshStalist(); + + inline void setInterface(QDBusInterface *activeInterface) { + m_activePathInterface = activeInterface; + } + +private: + QFrame* myLine(); + + TitleLabel *m_titleLabel = nullptr; + QVBoxLayout *m_staListLayout = nullptr; + QMap m_staMap; + + QDBusInterface *m_activePathInterface = nullptr; + + void getConnectStaDevice(QMap &blacklistMap); + bool removeStaFromBlacklist(QString staMac); + void initStaDev(); + void addStaDevFrame(QString staMac, QString staName); + void clearStaListLayout(); + QString getActivePathByUuid(QDBusInterface *interface); + void initNmDbus(QDBusInterface *interface); + + void onStaDevChanged(bool istrue, QString staMac, QString staName); + void resetLayoutHight(); + +signals: + void setStaIntoBlacklist(QString staMac, QString staName); + +public slots: + void onStaDevAdded(bool istrue, QString staMac, QString staName); + void onStaDevRemoved(bool istrue, QString staMac, QString staName); + +private slots: + void onDropIntoBlacklistBtnClicked(QString staMac, QString staName); +}; + +#endif // MOBILEHOTSPOTWIDGET_H diff --git a/plugins/mobilehotspot/mobilehotspot.cpp b/plugins/mobilehotspot/mobilehotspot.cpp new file mode 100644 index 00000000..46bd4409 --- /dev/null +++ b/plugins/mobilehotspot/mobilehotspot.cpp @@ -0,0 +1,155 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "mobilehotspot.h" + + +#include + + +MobileHotspot::MobileHotspot() : mFirstLoad(true) { + + QTranslator* translator = new QTranslator(this); + qDebug() << "/usr/share/kylin-nm/mobilehotspot/" + QLocale::system().name(); + if (!translator->load("/usr/share/kylin-nm/mobilehotspot/" + QLocale::system().name())) { + qDebug() << "load failed"; + } + QApplication::installTranslator(translator); + + pluginName = tr("MobileHotspot"); + qDebug() << pluginName; + pluginType = NETWORK; + + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + needLoad = isExitWirelessDevice(); +} + +MobileHotspot::~MobileHotspot() +{ + if (!mFirstLoad) { +// delete pluginWidget; +// pluginWidget = nullptr; + + } +} + +QString MobileHotspot::plugini18nName() { + return pluginName; +} + +int MobileHotspot::pluginTypes() { + return pluginType; +} + +QWidget *MobileHotspot::pluginUi() { + if (mFirstLoad) { + mFirstLoad = false; + + pluginWidget = new MobileHotspotWidget; + pluginWidget->setAttribute(Qt::WA_DeleteOnClose); + } + return pluginWidget; +} + +const QString MobileHotspot::name() const { + + return QStringLiteral("mobilehotspot"); +} + +bool MobileHotspot::isEnable() const +{ + qDebug() << needLoad; + return needLoad; +} + + +bool MobileHotspot::isShowOnHomePage() const +{ + return false; +} + +QIcon MobileHotspot::icon() const +{ + return QIcon::fromTheme("ukui-hotspot-symbolic"); +} + +QString MobileHotspot::translationPath() const +{ + return "/usr/share/kylin-nm/mobilehotspot/%1.ts"; +} + +void MobileHotspot::initSearchText() +{ + //~ contents_path /mobilehotspot/mobilehotspot + tr("mobilehotspot"); + //~ contents_path /mobilehotspot/mobilehotspot open + tr("mobilehotspot open"); +} + +bool MobileHotspot::isExitWirelessDevice() +{ + QDBusInterface *interface = new QDBusInterface("com.kylin.network", "/com/kylin/network", + "com.kylin.network", + QDBusConnection::sessionBus()); + if (!interface->isValid()) { + qDebug() << "/com/kylin/network is invalid"; + return false; + } + + QDBusMessage result = interface->call(QStringLiteral("getDeviceListAndEnabled"),1); + if(result.type() == QDBusMessage::ErrorMessage) { + qWarning() << "getWirelessDeviceList error:" << result.errorMessage(); + return false; + } + + auto dbusArg = result.arguments().at(0).value(); + QMap deviceListMap; + dbusArg >> deviceListMap; + + QDBusReply > capReply = interface->call("getWirelessDeviceCap"); + if (!capReply.isValid()) { + qDebug()<<"execute dbus method 'getWirelessDeviceCap' is invalid in func initInterfaceInfo()" < devCapMap = capReply.value(); + + + if (deviceListMap.isEmpty()) { + qDebug() << "no wireless device"; + return false; + } else { + QMap::Iterator iter = deviceListMap.begin(); + while (iter != deviceListMap.end()) { + QString interfaceName = iter.key(); + if (!devCapMap.contains(interfaceName)) { + iter++; + continue; + } + if (deviceListMap[interfaceName] & 0x01) { + qDebug() << "wireless device" << interfaceName << "support hotspot"; + return true; + } + iter++; + } + } + qDebug() << "no wireless device support hotspot"; + return false; +} + diff --git a/plugins/mobilehotspot/mobilehotspot.h b/plugins/mobilehotspot/mobilehotspot.h new file mode 100644 index 00000000..7bb3cb63 --- /dev/null +++ b/plugins/mobilehotspot/mobilehotspot.h @@ -0,0 +1,78 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MOBILEHOTSPOT_H +#define MOBILEHOTSPOT_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "interface.h" +#include "switchbutton.h" +#include "hoverbtn.h" +#include "mobilehotspotwidget.h" + + +namespace Ui { +class MobileHotspot; +} + +class MobileHotspot : public QObject, CommonInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface") + Q_INTERFACES(CommonInterface) + +public: + MobileHotspot(); + ~MobileHotspot(); + + QString plugini18nName() Q_DECL_OVERRIDE; + int pluginTypes() Q_DECL_OVERRIDE; + QWidget * pluginUi() Q_DECL_OVERRIDE; + const QString name() const Q_DECL_OVERRIDE; + bool isShowOnHomePage() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + bool isEnable() const Q_DECL_OVERRIDE; + QString translationPath() const Q_DECL_OVERRIDE; + +private: + + void initSearchText(); + bool isExitWirelessDevice(); + + QString pluginName; + int pluginType; + MobileHotspotWidget *pluginWidget; + +private: + bool mFirstLoad; + bool needLoad; + +}; +#endif // MOBILEHOTSPOT_H diff --git a/plugins/mobilehotspot/mobilehotspot.pro b/plugins/mobilehotspot/mobilehotspot.pro new file mode 100644 index 00000000..0bb86a93 --- /dev/null +++ b/plugins/mobilehotspot/mobilehotspot.pro @@ -0,0 +1,52 @@ +QT += widgets network dbus gui core +TEMPLATE = lib +CONFIG += plugin + +TARGET = $$qtLibraryTarget(mobilehotspot) +DESTDIR = ../.. +target.path = $$[QT_INSTALL_LIBS]/ukui-control-center +trans.files = translations/* +trans.path = /usr/share/kylin-nm/mobilehotspot/ + +INCLUDEPATH += \ + $$PROJECT_COMPONENTSOURCE \ + $$PROJECT_ROOTDIR \ + /usr/include/ukcc/interface \ + /usr/include/ukcc/widgets + +LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt -lukcc + +CONFIG += c++11 \ + link_pkgconfig \ + +PKGCONFIG += gsettings-qt \ + kysdk-qtwidgets \ + +#DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + blacklistpage.cpp \ + blacklistitem.cpp \ + connectdevpage.cpp \ + connectdevlistitem.cpp \ + mobilehotspot.cpp \ + mobilehotspotwidget.cpp + +HEADERS += \ + blacklistpage.h \ + blacklistitem.h \ + connectdevpage.h \ + connectdevlistitem.h \ + mobilehotspot.h \ + mobilehotspotwidget.h \ + libukcc_global.h + + +INSTALLS += target \ + trans + +TRANSLATIONS += \ + translations/zh_CN.ts \ + translations/tr.ts \ + translations/bo.ts\ + translations/bo_CN.ts diff --git a/plugins/mobilehotspot/mobilehotspotwidget.cpp b/plugins/mobilehotspot/mobilehotspotwidget.cpp new file mode 100644 index 00000000..a03a2af1 --- /dev/null +++ b/plugins/mobilehotspot/mobilehotspotwidget.cpp @@ -0,0 +1,888 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "mobilehotspotwidget.h" +#include +#include + +#define LABEL_RECT 17, 0, 105, 23 +#define CONTENTS_MARGINS 0, 0, 0, 0 +#define ITEM_MARGINS 16, 0, 16, 0 +#define FRAME_MIN_SIZE 550, 60 +#define FRAME_MAX_SIZE 16777215, 16777215 +#define CONTECT_FRAME_MAX_SIZE 16777215, 60 +#define HINT_TEXT_MARGINS 8, 0, 0, 0 +#define FRAME_MIN_SIZE 550, 60 +#define LABLE_MIN_WIDTH 188 +#define COMBOBOX_MIN_WIDTH 200 +#define LINE_MAX_SIZE 16777215, 1 +#define LINE_MIN_SIZE 0, 1 +#define ICON_SIZE 24,24 +#define PASSWORD_FRAME_MIN_HIGHT 60 +#define PASSWORD_FRAME_FIX_HIGHT 80 +#define PASSWORD_FRAME_MIN_SIZE 550, 60 +#define PASSWORD_FRAME_MAX_SIZE 16777215, 86 +#define PASSWORD_ITEM_MARGINS 16, 12, 16, 14 + +#define WIRELESS 1 + +#define AP_NAME_MAX_LENGTH 32 + +#define REFRESH_MSEC 20*1000 + +#define LOG_HEAD "[MobileHotspotWidget]" + +const QByteArray GSETTINGS_SCHEMA = "org.ukui.kylin-nm.switch"; +const QString WIRELESS_SWITCH = "wirelessswitch"; + +void MobileHotspotWidget::showDesktopNotify(const QString &message) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QList args; + args<<(tr("ukui control center")) + <<((unsigned int) 0) + <setContentsMargins(CONTENTS_MARGINS); + m_Vlayout->setSpacing(0); + + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >>(); + + initUI(); + +#ifdef HOTSPOT_CONTROL + initConnectDevPage(); + initBlackListPage(); +#endif + + m_switchBtn->installEventFilter(this); + m_interface = new QDBusInterface("com.kylin.network", "/com/kylin/network", + "com.kylin.network", + QDBusConnection::sessionBus()); + if(!m_interface->isValid()) { + qDebug() << LOG_HEAD << "dbus interface com.kylin.network is invaild"; + m_switchBtn->setChecked(false); + setUiEnabled(false); + } + + m_hostName = getHostName(); + + initDbusConnect(); + + initInterfaceInfo(); + getApInfo(); + +#ifdef HOTSPOT_CONTROL + initNmDbus(); +#endif + + this->setLayout(m_Vlayout); + m_Vlayout->addStretch(); + + connect(m_switchBtn, &KSwitchButton::stateChanged, this, &MobileHotspotWidget::setUiEnabled); + connect(m_interfaceComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=]() { + m_interfaceName = m_interfaceComboBox->currentText(); + updateBandCombox(); + }); + +#ifdef HOTSPOT_CONTROL + m_connectDevPage->refreshStalist(); + m_blacklistPage->refreshBlacklist(); +#endif + this->update(); +} + +MobileHotspotWidget::~MobileHotspotWidget() +{ + deleteActivePathInterface(); + deleteSettingPathInterface(); + delete m_interface; +} + +bool MobileHotspotWidget::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonDblClick && watched == m_switchBtn) { + return true; + } + + + if (watched == m_switchBtn) { + if (event->type() == QEvent::MouseButtonRelease) { + if (!m_interface->isValid()) { + return true; + } + if (!m_switchBtn->isCheckable()) { + showDesktopNotify(tr("wirless switch is close or no wireless device")); + return true; + } + if (m_switchBtn->isChecked()) { +// showDesktopNotify(tr("start to close hotspot")); + QDBusReply reply = m_interface->call("deactiveWirelessAp", m_apNameLine->text(), m_uuid); + if (!reply.isValid()) { + qDebug() << LOG_HEAD << "call deactiveWirelessAp failed "; + return true; + } +#ifdef HOTSPOT_CONTROL + deleteActivePathInterface(); + m_connectDevPage->setInterface(nullptr); + m_connectDevPage->refreshStalist(); + m_blacklistPage->refreshBlacklist(); +#endif + this->update(); + } else { + if (m_apNameLine->text().isEmpty() || m_interfaceName.isEmpty()) + { + showDesktopNotify(tr("hotpots name or device is invalid")); + return true; + } + if (m_pwdNameLine->text().length() < 8) { +// showDesktopNotify(tr("can not create hotspot with password length less than eight!")); + return true; + } +// showDesktopNotify(tr("start to open hotspot ") + m_apNameLine->text()); + QDBusReply reply = m_interface->call("activeWirelessAp", + m_apNameLine->text(), + m_pwdNameLine->text(), + m_freqBandComboBox->currentText(), + m_interfaceComboBox->currentText()); + if (!reply.isValid()) { + qDebug() << LOG_HEAD << "call activeWirelessAp failed "; + return true; + } + + } + return true; + } + } + return QWidget::eventFilter(watched, event); +} + +void MobileHotspotWidget::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); +} + +void MobileHotspotWidget::resetFrameSize() +{ + int height = 0; + for (int i = 0; i < m_hotspotFrame->layout()->count(); i ++) { + QWidget *w = m_hotspotFrame->layout()->itemAt(i)->widget(); + if (w != nullptr && !w->isHidden()) { + height += w->height(); + } + } + m_hotspotFrame->setFixedHeight(height); +} + +void MobileHotspotWidget::initUI() +{ + m_hotspotFrame = new QFrame(this); + m_hotspotFrame->setMinimumSize(FRAME_MIN_SIZE); + m_hotspotFrame->setMaximumSize(FRAME_MAX_SIZE); + m_hotspotFrame->setFrameShape(QFrame::Box); + + QVBoxLayout *hotspotLyt = new QVBoxLayout(this); + hotspotLyt->setContentsMargins(0, 0, 0, 0); + m_hotspotFrame->setLayout(hotspotLyt); + + m_hotspotTitleLabel = new TitleLabel(this); + m_hotspotTitleLabel->setText(tr("Hotspot")); + + setSwitchFrame(); + setApNameFrame(); + setPasswordFrame(); + setFreqBandFrame(); + setInterFaceFrame(); + + switchAndApNameLine = myLine(); + apNameAndPwdLine = myLine(); + pwdAndfreqBandLine = myLine(); + freqBandAndInterfaceLine = myLine(); + + hotspotLyt->addWidget(m_switchFrame); + hotspotLyt->addWidget(switchAndApNameLine); + hotspotLyt->addWidget(m_ApNameFrame); + hotspotLyt->addWidget(apNameAndPwdLine); + hotspotLyt->addWidget(m_passwordFrame); + hotspotLyt->addWidget(pwdAndfreqBandLine); + hotspotLyt->addWidget(m_freqBandFrame); + hotspotLyt->addWidget(freqBandAndInterfaceLine); + hotspotLyt->addWidget(m_interfaceFrame); + hotspotLyt->setSpacing(0); + + resetFrameSize(); + + m_Vlayout->addWidget(m_hotspotTitleLabel); + m_Vlayout->addSpacing(8); + m_Vlayout->addWidget(m_hotspotFrame); + +} + + +void MobileHotspotWidget::initDbusConnect() +{ + if(m_interface->isValid()) { + connect(m_interface,SIGNAL(activateFailed(QString)), this, SLOT(onActivateFailed(QString)), Qt::QueuedConnection); + connect(m_interface,SIGNAL(deactivateFailed(QString)), this, SLOT(onDeactivateFailed(QString)), Qt::QueuedConnection); + connect(m_interface,SIGNAL(deviceStatusChanged()), this, SLOT(onDeviceStatusChanged()), Qt::QueuedConnection); + connect(m_interface,SIGNAL(deviceNameChanged(QString, QString, int)), this, SLOT(onDeviceNameChanged(QString, QString, int)), Qt::QueuedConnection); + connect(m_interface,SIGNAL(hotspotDeactivated(QString, QString)), this, SLOT(onHotspotDeactivated(QString, QString)), Qt::QueuedConnection); + connect(m_interface,SIGNAL(hotspotActivated(QString, QString, QString, QString, QString)), this, SLOT(onHotspotActivated(QString, QString, QString, QString, QString)), Qt::QueuedConnection); + + connect(m_interface, SIGNAL(wlanactiveConnectionStateChanged(QString, QString, QString, int)), this, SLOT(onActiveConnectionChanged(QString, QString, QString, int)), Qt::QueuedConnection); + + connect(m_interface, SIGNAL(wirelessSwitchBtnChanged(bool)), this, SLOT(onWirelessBtnChanged(bool)), Qt::QueuedConnection); + } + + + connect(m_apNameLine, &QLineEdit::textEdited, this, &MobileHotspotWidget::onApLineEditTextEdit); +#ifdef HOTSPOT_CONTROL + connect(m_connectDevPage, SIGNAL(setStaIntoBlacklist(QString, QString)), m_blacklistPage, SLOT(onsetStaIntoBlacklist(QString, QString))); +#endif + connect(m_pwdNameLine, SIGNAL(textChanged(QString)), this, SLOT(onPwdTextChanged())); +} + +void MobileHotspotWidget::onApLineEditTextEdit(QString text) +{ + int count = 0; + int i = 0; + + for ( ; i < text.length(); ++i) { + count += text.mid(i,1).toLocal8Bit().length(); + if (count > AP_NAME_MAX_LENGTH) { + break; + } + } + + m_apNameLine->setText(text.left(i)); +} + +void MobileHotspotWidget::onPwdTextChanged() +{ + if (m_pwdNameLine->text().length() < 8) { + m_passwordFrame->setFixedHeight(PASSWORD_FRAME_FIX_HIGHT); + m_pwdHintLabel->show(); + } else { + m_passwordFrame->setFixedHeight(PASSWORD_FRAME_MIN_HIGHT); + m_pwdHintLabel->hide(); + } + resetFrameSize(); + this->update(); +} + +void MobileHotspotWidget::onActiveConnectionChanged(QString deviceName, QString ssid, QString uuid, int status) +{ + if(m_uuid == uuid && status == 4) { + showDesktopNotify(tr("hotspot already close")); + m_switchBtn->setChecked(false); + setUiEnabled(false); + m_uuid.clear(); + } +} + +void MobileHotspotWidget::onWirelessBtnChanged(bool state) +{ + if (!state) { + m_switchBtn->setChecked(state); + m_uuid.clear(); + m_switchBtn->setCheckable(false); + } else { + m_switchBtn->setCheckable(true); + } +} + +void MobileHotspotWidget::initInterfaceInfo() +{ + if(!m_interface->isValid()) { + return; + } + m_interfaceComboBox->clear(); + QDBusReply > reply = m_interface->call("getDeviceListAndEnabled",WIRELESS); + + if (!reply.isValid()) { + qDebug() << LOG_HEAD <<"execute dbus method 'getDeviceListAndEnabled' is invalid in func initInterfaceInfo()"; + setWidgetHidden(true); + return; + } + QMap devMap = reply.value(); + + QDBusReply > capReply = m_interface->call("getWirelessDeviceCap"); + if (!capReply.isValid()) { + qDebug() << LOG_HEAD <<"execute dbus method 'getWirelessDeviceCap' is invalid in func initInterfaceInfo()" < devCapMap = capReply.value(); + + + if (devMap.isEmpty()) { + qDebug() << LOG_HEAD << "no wireless device"; + setWidgetHidden(true); + m_switchBtn->setCheckable(false); + } else { + QMap::Iterator iter = devMap.begin(); + while (iter != devMap.end()) { + QString interfaceName = iter.key(); + if (devCapMap[interfaceName] & 0x01) { + m_interfaceComboBox->addItem(interfaceName); + } + iter++; + } + if (m_interfaceComboBox->count() > 0) { + setWidgetHidden(false); + m_interfaceName = m_interfaceComboBox->currentText(); + if (m_interfaceComboBox->count() == 1) { + updateBandCombox(); + } + } else { + qDebug() << LOG_HEAD << "no useable wireless device"; + setWidgetHidden(true); + } + } +} + +void MobileHotspotWidget::getApInfo() +{ + if (!m_interface->isValid()) { + return; + } + + if (m_interfaceComboBox->count() <= 0) { + m_switchBtn->setChecked(false); + setWidgetHidden(true); + qWarning() << LOG_HEAD << "getApInfo but interface is empty"; + return; + } + + + QDBusReply reply = m_interface->call("getStoredApInfo"); + if (!reply.isValid()) { + qDebug() << LOG_HEAD <<"execute dbus method 'getStoredApInfo' is invalid in func getObjectPath()"; + } + + QStringList apInfo = reply.value(); + + if (apInfo.isEmpty()) { + qDebug() << LOG_HEAD << "no stored hotspot info"; + m_apNameLine->setText(m_hostName); + m_pwdNameLine->setText("12345678"); + return; + } else { + int index = m_interfaceComboBox->findText(apInfo.at(2)); + if (index >= 0) { + m_apNameLine->setText(apInfo.at(0)); + m_pwdNameLine->setText(apInfo.at(1)); + m_interfaceComboBox->setCurrentIndex(index); + m_interfaceName = apInfo.at(2); + if (apInfo.at(3) == "true") { + m_switchBtn->setChecked(true); + setUiEnabled(true); + m_uuid = apInfo.at(4); + } else { + m_switchBtn->setChecked(false); + setUiEnabled(false); + m_uuid = apInfo.at(4); + } + } else { + qDebug() << LOG_HEAD << "no such interface " << apInfo.at(2); + } + } +} + +void MobileHotspotWidget::setSwitchFrame() +{ + /* Open */ + m_switchFrame = new QFrame(this); + m_switchFrame->setFrameShape(QFrame::Shape::NoFrame); + m_switchFrame->setMinimumSize(FRAME_MIN_SIZE); + m_switchFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE); + + QHBoxLayout *switchLayout = new QHBoxLayout(m_switchFrame); + + m_switchLabel = new QLabel(tr("Open"), this); + m_switchLabel->setMinimumWidth(LABLE_MIN_WIDTH); + m_switchBtn = new KSwitchButton(this); + switchLayout->setContentsMargins(ITEM_MARGINS); + switchLayout->addWidget(m_switchLabel); + switchLayout->addStretch(); + switchLayout->addWidget(m_switchBtn); + + m_switchFrame->setLayout(switchLayout); +} + +void MobileHotspotWidget::setApNameFrame() +{ + /* ApName */ + m_ApNameFrame = new QFrame(this); + m_ApNameFrame->setFrameShape(QFrame::Shape::NoFrame); + m_ApNameFrame->setMinimumSize(FRAME_MIN_SIZE); + m_ApNameFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE); + + QHBoxLayout *apNameHLayout = new QHBoxLayout(m_ApNameFrame); + + m_apNameLabel = new QLabel(tr("Wi-Fi Name"), this); + m_apNameLabel->setMinimumWidth(LABLE_MIN_WIDTH); + m_apNameLine = new QLineEdit(this); + m_apNameLine->setMinimumWidth(COMBOBOX_MIN_WIDTH); + m_apNameLine->setMaxLength(AP_NAME_MAX_LENGTH); + apNameHLayout->setContentsMargins(ITEM_MARGINS); + apNameHLayout->setSpacing(0); + apNameHLayout->addWidget(m_apNameLabel); + apNameHLayout->addWidget(m_apNameLine); + m_ApNameFrame->setLayout(apNameHLayout); + +} + +void MobileHotspotWidget::setPasswordFrame() +{ + /* Password */ + m_passwordFrame = new QFrame(this); + m_passwordFrame->setFrameShape(QFrame::Shape::NoFrame); + m_passwordFrame->setMinimumSize(PASSWORD_FRAME_MIN_SIZE); + m_passwordFrame->setMaximumSize(PASSWORD_FRAME_MAX_SIZE); + + m_pwdLabel = new QLabel(tr("Password"), this); + m_pwdLabel->setMinimumWidth(LABLE_MIN_WIDTH); + m_pwdNameLine = new KPasswordEdit(this); + m_pwdNameLine->setClearButtonEnabled(false);//禁用ClearBtn按钮X + m_pwdNameLine->setMinimumWidth(COMBOBOX_MIN_WIDTH); + m_pwdHintLabel= new QLabel(this); + m_pwdHintLabel->setFixedHeight(20); + m_pwdHintLabel->setContentsMargins(HINT_TEXT_MARGINS); + + QPalette hintTextColor; + hintTextColor.setColor(QPalette::WindowText, Qt::red); + m_pwdHintLabel->setPalette(hintTextColor); + m_pwdHintLabel->setText(tr("Contains at least 8 characters")); //至少包含8个字符 + + QWidget *pwdInputWidget = new QWidget(m_passwordFrame); + QVBoxLayout *pwdInputVLayout = new QVBoxLayout(pwdInputWidget); + pwdInputVLayout->setContentsMargins(CONTENTS_MARGINS); + pwdInputVLayout->setSpacing(0); + pwdInputVLayout->addWidget(m_pwdNameLine); + pwdInputVLayout->addWidget(m_pwdHintLabel); + + QFormLayout *pwdLayout = new QFormLayout(m_passwordFrame); + pwdLayout->setContentsMargins(PASSWORD_ITEM_MARGINS); + pwdLayout->setSpacing(0); + pwdLayout->addRow(m_pwdLabel, pwdInputWidget); + + m_passwordFrame->setLayout(pwdLayout); + + m_pwdNameLine->installEventFilter(this); +} + +void MobileHotspotWidget::setFreqBandFrame() +{ + /* frequency band */ + m_freqBandFrame = new QFrame(this); + m_freqBandFrame->setFrameShape(QFrame::Shape::NoFrame); + m_freqBandFrame->setMinimumSize(FRAME_MIN_SIZE); + m_freqBandFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE); + + QHBoxLayout *freqBandHLayout = new QHBoxLayout(m_freqBandFrame); + + m_freqBandLabel = new QLabel(tr("Frequency band"), this); + m_freqBandLabel->setMinimumWidth(LABLE_MIN_WIDTH); + m_freqBandComboBox = new QComboBox(this); + m_freqBandComboBox->setInsertPolicy(QComboBox::NoInsert); + m_freqBandComboBox->setMinimumWidth(COMBOBOX_MIN_WIDTH); + m_freqBandComboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed); + m_freqBandComboBox->addItem("2.4GHz"); + m_freqBandComboBox->addItem("5GHz"); + freqBandHLayout->setContentsMargins(ITEM_MARGINS); + freqBandHLayout->setSpacing(0); + freqBandHLayout->addWidget(m_freqBandLabel); + freqBandHLayout->addWidget(m_freqBandComboBox); + + m_freqBandFrame->setLayout(freqBandHLayout); +} + +void MobileHotspotWidget::setInterFaceFrame() +{ + /* key tips */ + m_interfaceFrame = new QFrame(this); + m_interfaceFrame->setFrameShape(QFrame::Shape::NoFrame); + m_interfaceFrame->setMinimumSize(FRAME_MIN_SIZE); + m_interfaceFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE); + + QHBoxLayout *interfaceHLayout = new QHBoxLayout(m_interfaceFrame); + + m_interfaceLabel = new QLabel(tr("Net card"), this); + m_interfaceLabel->setMinimumWidth(LABLE_MIN_WIDTH); + m_interfaceComboBox = new QComboBox(this); + m_interfaceComboBox->setInsertPolicy(QComboBox::NoInsert); + m_interfaceComboBox->setMinimumWidth(COMBOBOX_MIN_WIDTH); + m_interfaceComboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed); + interfaceHLayout->setContentsMargins(ITEM_MARGINS); + interfaceHLayout->setSpacing(0); + interfaceHLayout->addWidget(m_interfaceLabel); + interfaceHLayout->addWidget(m_interfaceComboBox); + + m_interfaceFrame->setLayout(interfaceHLayout); +} + +void MobileHotspotWidget::onActivateFailed(QString errorMessage) +{ + if (errorMessage.indexOf("hotspot")) { + //todo +// showDesktopNotify(errorMessage); + } +} + +void MobileHotspotWidget::onDeactivateFailed(QString errorMessage) +{ + if (errorMessage.indexOf("hotspot")) { +// showDesktopNotify(errorMessage); + } +} + +//设备插拔 +void MobileHotspotWidget::onDeviceStatusChanged() +{ + initInterfaceInfo(); + getApInfo(); +} + +void MobileHotspotWidget::onDeviceNameChanged(QString oldName, QString newName, int type) +{ + if (WIRELESS != type) { + return; + } + int index = m_interfaceComboBox->findText(oldName); + if (index >= 0) { + m_interfaceComboBox->setItemText(index, newName); + if (m_interfaceName == oldName) { + m_interfaceName = newName; + } + } +} + +//热点断开 +void MobileHotspotWidget::onHotspotDeactivated(QString devName, QString ssid) +{ + if (!m_switchBtn->isChecked()) { + return; + } + if (devName == m_interfaceComboBox->currentText() && ssid == m_apNameLine->text()) { + m_switchBtn->setChecked(false); + m_uuid.clear(); +// setUiEnabled(true); + showDesktopNotify(tr("hotspot already close")); + } +} + +//热点连接 +void MobileHotspotWidget::onHotspotActivated(QString devName, QString ssid, QString uuid, QString activePath, QString settingPath) +{ + qDebug() << LOG_HEAD << "onHotspotActivated" <isChecked()) { + return; + } +#ifdef HOTSPOT_CONTROL + if (activePath != nullptr) { + deleteActivePathInterface(); + initActivePathInterface(activePath); + } + if (settingPath != nullptr) { + deleteSettingPathInterface(); + initSettingPathInterface(settingPath); + } + + m_connectDevPage->refreshStalist(); + m_blacklistPage->refreshBlacklist(); +#endif + this->update(); + + if (devName == m_interfaceComboBox->currentText() && ssid == m_apNameLine->text()) { + m_switchBtn->setChecked(true); + m_uuid = uuid; +// setUiEnabled(false); + showDesktopNotify(tr("hotspot already open")); + } else { + QStringList info; + if (!getApInfoBySsid(devName, ssid, info)) { + return; + } + int index = m_interfaceComboBox->findText(devName); + if (index >= 0) { + showDesktopNotify(tr("hotspot already open")); + m_apNameLine->setText(ssid); + m_interfaceComboBox->setCurrentIndex(index); + m_switchBtn->setChecked(true); + m_switchBtn->setCheckable(true); + m_pwdNameLine->setText(info.at(0)); + m_interfaceName = devName; + updateBandCombox(); + index = m_freqBandComboBox->findText(info.at(1)); + if (index >= 0) { + m_freqBandComboBox->setCurrentIndex(index); + } + m_uuid = uuid; + } else { + qDebug() << "no such device in combo box"; + } + } + + +} + +bool MobileHotspotWidget::getApInfoBySsid(QString devName, QString ssid, QStringList &info) +{ + info.clear(); + if(!m_interface->isValid()) { + return false; + } + QDBusReply reply = m_interface->call("getApInfoBySsid", devName, ssid); + if (!reply.isValid()) { + qDebug()<<"execute dbus method 'getApInfoBySsid' is invalid in func getApInfoBySsid()"; + } + info = reply.value(); + if (info.size() != 2) { + return false; + } else { + return true; + } +} + +void MobileHotspotWidget::setUiEnabled(bool enable) +{ + qDebug() << "switch mode change to " << enable; + if (enable) { + m_pwdNameLine->setEnabled(false); + m_freqBandComboBox->setEnabled(false); + m_interfaceComboBox->setEnabled(false); + m_apNameLine->setEnabled(false); + } else { + m_pwdNameLine->setEnabled(true); + m_freqBandComboBox->setEnabled(true); + m_interfaceComboBox->setEnabled(true); + m_apNameLine->setEnabled(true); + } +} + +void MobileHotspotWidget::setWidgetHidden(bool isHidden) +{ + m_ApNameFrame->setHidden(isHidden); + m_passwordFrame->setHidden(isHidden); + m_freqBandFrame->setHidden(isHidden); + m_interfaceFrame->setHidden(isHidden); + + switchAndApNameLine->setHidden(isHidden); + apNameAndPwdLine->setHidden(isHidden); + pwdAndfreqBandLine->setHidden(isHidden); + freqBandAndInterfaceLine->setHidden(isHidden); + + if (isHidden) { + m_switchBtn->setChecked(false); + m_switchBtn->setCheckable(false); + m_interfaceName = ""; + m_uuid = ""; + } else { + m_switchBtn->setCheckable(true); + QDBusReply reply = m_interface->call("getWirelessSwitchBtnState"); + bool state = reply.value(); + onWirelessBtnChanged(state); + } + resetFrameSize(); + +} + +void MobileHotspotWidget::updateBandCombox() +{ + m_freqBandComboBox->clear(); + QDBusReply > capReply = m_interface->call("getWirelessDeviceCap"); + if (!capReply.isValid()) { + qDebug()<<"execute dbus method 'getWirelessDeviceCap' is invalid in func initInterfaceInfo()" << capReply.error().message(); + setWidgetHidden(true); + return; + } + QMap devCapMap = capReply.value(); + if (devCapMap[m_interfaceName] & 0x02) { + m_freqBandComboBox->addItem("2.4GHz"); + } + if (devCapMap[m_interfaceName] & 0x04) { + m_freqBandComboBox->addItem("5GHz"); + } +} + +QFrame* MobileHotspotWidget::myLine() +{ + QFrame *line = new QFrame(this); + line->setMinimumSize(QSize(LINE_MIN_SIZE)); + line->setMaximumSize(QSize(LINE_MAX_SIZE)); + line->setLineWidth(0); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + return line; +} + +QString MobileHotspotWidget::getHostName() +{ + int count = 0; + while (count < 3) { + QDBusInterface hostInterface("org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + QDBusConnection::systemBus()); + if (hostInterface.isValid()) { + return hostInterface.property("Hostname").value(); + } else { + count++; + } + } + return "default"; +} + +QString MobileHotspotWidget::getSettingPathByUuid() +{ + if (!m_interface->isValid()) { + return nullptr; + } + + QDBusReply reply = m_interface->call("getApConnectionPath", m_uuid); + if (!reply.isValid()) { + return nullptr; + } + + return reply.value(); +} + +QString MobileHotspotWidget::getActivePathByUuid() +{ + if (!m_interface->isValid()) { + return nullptr; + } + + QDBusReply reply = m_interface->call("getActiveConnectionPath", m_uuid); + if (!reply.isValid()) { + return nullptr; + } + return reply.value(); +} + +void MobileHotspotWidget::initNmDbus() +{ + QString activePath = getActivePathByUuid(); + QString settingPath = getSettingPathByUuid(); + + if (activePath != nullptr) { + m_activePathInterface = new QDBusInterface("org.freedesktop.NetworkManager", + activePath, + "org.freedesktop.NetworkManager.Connection.Active", + QDBusConnection::systemBus()); + if (m_activePathInterface->isValid()) { + m_connectDevPage->setInterface(m_activePathInterface); + + connect(m_activePathInterface, SIGNAL(NewStaConnected(bool, QString, QString)), m_connectDevPage, SLOT(onStaDevAdded(bool, QString, QString)), Qt::QueuedConnection); + connect(m_activePathInterface, SIGNAL(StaRemoved(bool, QString, QString)), m_connectDevPage, SLOT(onStaDevRemoved(bool, QString, QString)), Qt::QueuedConnection); + } + } + + if (settingPath != nullptr) { + m_settingPathInterface = new QDBusInterface("org.freedesktop.NetworkManager", + settingPath, + "org.freedesktop.NetworkManager.Settings.Connection", + QDBusConnection::systemBus()); + if (m_settingPathInterface->isValid()) { + m_blacklistPage->setInterface(m_settingPathInterface); + } + } +} + +void MobileHotspotWidget::initActivePathInterface(QString path) +{ + if (path != nullptr){ + m_activePathInterface = new QDBusInterface("org.freedesktop.NetworkManager", + path, + "org.freedesktop.NetworkManager.Connection.Active", + QDBusConnection::systemBus()); + if (m_activePathInterface->isValid()) { + m_connectDevPage->setInterface(m_activePathInterface); + + connect(m_activePathInterface, SIGNAL(NewStaConnected(bool, QString, QString)), m_connectDevPage, SLOT(onStaDevAdded(bool, QString, QString)), Qt::QueuedConnection); + connect(m_activePathInterface, SIGNAL(StaRemoved(bool, QString, QString)), m_connectDevPage, SLOT(onStaDevRemoved(bool, QString, QString)), Qt::QueuedConnection); + } + } +} + +void MobileHotspotWidget::deleteActivePathInterface() +{ + if (m_activePathInterface != nullptr){ + disconnect(m_activePathInterface); + delete m_activePathInterface; + m_activePathInterface = nullptr; + } +} + +void MobileHotspotWidget::initSettingPathInterface(QString path) +{ + if (path != nullptr){ + m_settingPathInterface = new QDBusInterface("org.freedesktop.NetworkManager", + path, + "org.freedesktop.NetworkManager.Settings.Connection", + QDBusConnection::systemBus()); + if (m_settingPathInterface->isValid()) { + m_blacklistPage->setInterface(m_settingPathInterface); + } + } +} + +void MobileHotspotWidget::deleteSettingPathInterface() +{ + if (m_settingPathInterface != nullptr){ + disconnect(m_settingPathInterface); + delete m_settingPathInterface; + m_settingPathInterface = nullptr; + } +} + +void MobileHotspotWidget::initConnectDevPage() +{ + m_connectDevPage = new ConnectdevPage(this); + m_Vlayout->addSpacing(32); + m_Vlayout->addWidget(m_connectDevPage); +} + +void MobileHotspotWidget::initBlackListPage() +{ + m_blacklistPage = new BlacklistPage(this); + m_Vlayout->addSpacing(32); + m_Vlayout->addWidget(m_blacklistPage); +} + diff --git a/plugins/mobilehotspot/mobilehotspotwidget.h b/plugins/mobilehotspot/mobilehotspotwidget.h new file mode 100644 index 00000000..13b29d9d --- /dev/null +++ b/plugins/mobilehotspot/mobilehotspotwidget.h @@ -0,0 +1,163 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef MOBILEHOTSPOTWIDGET_H +#define MOBILEHOTSPOTWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "titlelabel.h" +#include "kwidget.h" +#include "kswitchbutton.h" +#include "kpasswordedit.h" +#include "connectdevlistitem.h" +#include "blacklistpage.h" +#include "connectdevpage.h" + +using namespace kdk; + +class MobileHotspotWidget : public QWidget +{ + Q_OBJECT +public: + explicit MobileHotspotWidget(QWidget *parent = nullptr); + ~MobileHotspotWidget(); + +private: + QFrame *m_hotspotFrame = nullptr; + QFrame *m_switchFrame = nullptr; //开关 + QFrame *m_ApNameFrame = nullptr; //wifi名称 + QFrame *m_passwordFrame = nullptr; //密码 + QFrame *m_freqBandFrame = nullptr; //频带 + QFrame *m_interfaceFrame = nullptr; //网卡 + + KSwitchButton *m_switchBtn; + + TitleLabel *m_hotspotTitleLabel; + QLabel *m_switchLabel; + QLabel *m_apNameLabel; + QLabel *m_pwdLabel; + QLabel *m_pwdHintLabel; + QLabel *m_freqBandLabel; + QLabel *m_interfaceLabel; + + QFrame *switchAndApNameLine; + QFrame *apNameAndPwdLine; + QFrame *pwdAndfreqBandLine; + QFrame *freqBandAndInterfaceLine; + + QVBoxLayout *m_Vlayout; + + QLineEdit *m_apNameLine; + KPasswordEdit *m_pwdNameLine; + + QComboBox *m_freqBandComboBox; + QComboBox *m_interfaceComboBox; + + QDBusInterface *m_interface = nullptr; + + QString m_interfaceName = ""; + + QGSettings *m_switchGsettings = nullptr; + + QString m_uuid = ""; + QString m_hostName = ""; + + void resetFrameSize(); + void initUI(); + void initDbusConnect(); + void initInterfaceInfo(); + void getApInfo(); + bool getApInfoBySsid(QString devName, QString ssid, QStringList &info); + void setSwitchFrame(); + void setApNameFrame(); + void setPasswordFrame(); + void setFreqBandFrame(); + void setInterFaceFrame(); + + void setUiEnabled(bool enable); + void setWidgetHidden(bool isHidden); + + void showDesktopNotify(const QString &message); + + void updateBandCombox(); + + QString getHostName(); + + bool eventFilter(QObject *watched, QEvent *event); + void paintEvent(QPaintEvent *event); + + QFrame* myLine(); + + QDBusInterface *m_activePathInterface = nullptr; + QDBusInterface *m_settingPathInterface = nullptr; + + ConnectdevPage * m_connectDevPage = nullptr; + BlacklistPage *m_blacklistPage = nullptr; + + QString getActivePathByUuid(); + QString getSettingPathByUuid(); + void initNmDbus(); + void initActivePathInterface(QString path); + void deleteActivePathInterface(); + void initSettingPathInterface(QString path); + void deleteSettingPathInterface(); + void initConnectDevPage(); + void initBlackListPage(); + +signals: + +private slots: + void onActivateFailed(QString errorMessage); + void onDeactivateFailed(QString errorMessage); + //设备插拔 + void onDeviceStatusChanged(); + void onDeviceNameChanged(QString oldName, QString newName, int type); + //热点断开 + void onHotspotDeactivated(QString devName, QString ssid); + //热点连接 + void onHotspotActivated(QString devName, QString ssid, QString uuid, QString activePath, QString settingPath); + + void onWirelessBtnChanged(bool state); + + void onActiveConnectionChanged(QString deviceName, QString ssid, QString uuid, int status); + + void onApLineEditTextEdit(QString text); + + void onPwdTextChanged(); +}; + +#endif // MOBILEHOTSPOTWIDGET_H diff --git a/plugins/mobilehotspot/translations/bo.qm b/plugins/mobilehotspot/translations/bo.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/mobilehotspot/translations/bo.qm @@ -0,0 +1 @@ + + + + + BlacklistItem + + + Remove + + + + + BlacklistPage + + + Blacklist + + + + + ConnectDevListItem + + + drag into blacklist + + + + + ConnectdevPage + + + Connect device + + + + + MobileHotspot + + + MobileHotspot + + + + + mobilehotspot + + /mobilehotspot/mobilehotspot + + + + mobilehotspot open + + /mobilehotspot/mobilehotspot open + + + + MobileHotspotWidget + + + ukui control center + + + + + ukui control center desktop message + + + + + wirless switch is close or no wireless device + + + + + start to close hotspot + + + + + hotpots name or device is invalid + + + + + start to open hotspot + + + + + Contains at least 8 characters + + + + + Hotspot + + + + + + hotspot already close + + + + + Open + + + + + Wi-Fi Name + + + + + Password + + + + + Frequency band + + + + + Net card + + + + + + hotspot already open + + + + diff --git a/plugins/mobilehotspot/translations/bo_CN.qm b/plugins/mobilehotspot/translations/bo_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..b9da303bb534ccfb76ae8d0bd16391ba92ce54aa GIT binary patch literal 2616 zcma)8U1%It7`@GZvPmu^srZN7qLzxyOA%2~NY`~qp~j8bY)VDlyR&zbVRvV?GdBqd z;*-9ps3?LDEk%vg>WhsaeNidY7r_@%!3Ur8Q7nj1A3filnVs2fXWEC^d*|n#@7(j9 z@4Nft<@%jJTs!;0kB9F4uKLk8zvmfaU$UV$EXD@**l^=p#)ckZPd)rEVC6V_UOkuuio*tZ z?fB(u58(NQi7WrSj`bHOem(g&;vCH#`*aVuIvjt=bB`|b++XL-3&0!v&}MAh83eN64Zg=;;W>=&@=KU4V_w0mfw9b|#_$mv zq3e0ocDK|hrc?Qrw3;p3*C(`UA0V7Z@cnyypL;xybw#s!0Vp2sPT{wJv1H<`m@mqh z$Jpatz+U*0TvrDEiByoP32_|o4gLv0S1_xA%B3(&9Avic$#r2n+7-2kKZTol+I1Xd z>4MrincUJ5UWE|*e3x5h6D6*VIQ<)qBTR=#qOP`V%SaVH!jtZ1jv1}Afvo^?7lBBp zb&QmW)8=jg;YhUx?&1(r&$>0cr50W7cU*1M>Um<+I+7Bg%2%q;A09|eP5M5kzZ z2pPr3Yso@>ddBctQ}F4PCYZ$3|v5aBD{X(MibdjB`dJ) zeJl@ZAut$~HCd_xYH{wzmXsEj^s))fndGM>bLhD+eW`qAOqwWqBwd0*N&5b_dkY44 zvo&V3c~)dLOpt6WG1A1EJzuoNl5CsmOJ%ckgS>%4QL8E#%k@`!&Lnsxv{o5=IfdjT z?R5whgu3*F0|vtN!cHJ;AB|^Aw(M+?7gK2E(bmY<%kUUAxDrIn@e{@wfzKLvL*n-P z{a{$qLbg05>pQ|~xqh}bh1(=Sjf>h-Z;8K*%&a8bHP=rdD)iLc9PVPqeY}bdllQ2| zFGBTX@4Ca+($fNM-Rw<-0W-_%G+LB4Qs&JeMI}w*2B%0+Bh<1;bcrviu&K>Z1EPbH zx+o=rDk}IYWXMFf++$v}<%pKZ`3pv8dVk*Jfh>|# zWp=ZHiF}Vaz%OTU4LVJN65)PKJ(kQ e*8)S~Z`<11pjr-$hVph?fw#)Mjt~8tTKj*V5lwIa literal 0 HcmV?d00001 diff --git a/plugins/mobilehotspot/translations/bo_CN.ts b/plugins/mobilehotspot/translations/bo_CN.ts new file mode 100644 index 00000000..2e4fb436 --- /dev/null +++ b/plugins/mobilehotspot/translations/bo_CN.ts @@ -0,0 +1,140 @@ + + + + + BlacklistItem + + + Remove + སྤོ་སྐྱོད་བྱས་པ། + + + + BlacklistPage + + + Blacklist + སྒྲིག་ཆས་ཀྱི་མིང་ཐོ་ནག་པོ། + + + + ConnectDevListItem + + + drag into blacklist + མིང་ཐོ་ནག་པོའི་ཁ་སྣོན་རྒྱག་པ། + + + + ConnectdevPage + + + Connect device + འབྲེལ་མཐུད་སྒྲིག་ཆས། + + + + MobileHotspot + + + MobileHotspot + སྒུལ་བདེའི་ཧའོ་ཚི་ཀུང་སི། + + + + mobilehotspot + སྒུལ་བདེའི་འཕྲུལ་ཆས། + /mobilehotspot/mobilehotspot + + + + mobilehotspot open + སྒུལ་བདེའི་འཕྲུལ་ཆས་ཀྱི་སྒོ་ཕྱེ་བ། + /mobilehotspot/mobilehotspot open + + + + MobileHotspotWidget + + + ukui control center + ཝུའུ་ཁི་ལན་གྱི་ཚོད་འཛིན་ལྟེ་གནས། + + + + ukui control center desktop message + ukui ཚོད་འཛིན་ལྟེ་གནས་ཀྱི་ཅོག་ངོས་ཆ་འཕྲིན། + + + + wirless switch is close or no wireless device + སྐུད་མེད་གློག་སྒོ་རྒྱག་པའམ་ཡང་ན་སྐུད་མེད་སྒྲིག་ཆས་མེད་པ། + + + + start to close hotspot + སྒོ་རྒྱག་འགོ་བརྩམས། + + + + hotpots name or device is invalid + ཚ་བ་ཆེ་བའི་མིང་ངམ་སྒྲིག་ཆས་ལ་ནུས་པ་མེད། + + + can not create hotspot with password length less than eight! + གསང་གྲངས་ཀྱི་རིང་ཚད་ནི་གླེང་མང་བའི་གནད་དོན་བརྒྱད་ལས་ཆུང་བ་བྱེད་མི་རུང་།! + + + + start to open hotspot + ཀུན་གྱིས་དོ་སྣང་བྱེད་ཡུལ་གསར་སྐྲུན་བྱེད་འགོ་ + + + + Contains at least 8 characters + མ་མཐར་ཡང་ཡིག་རྟགས་བརྒྱད་འདུས་ཡོད། + + + + Hotspot + ཚ་བ་ཆེ་བ། + + + + + hotspot already close + ཚ་བ་ཆེ་བའི་གནད་དོན་ཐག་ཉེ་རུ་སོང་ཡོད། + + + + Open + སྒོ་ཕྱེ་བ། + + + + Wi-Fi Name + Wi-Fiཡི་མིང་། + + + + Password + གསང་གྲངས། + + + + Frequency band + ཐེངས་གྲངས་ཀྱི་རོལ་ཆའི་རུ་ཁག + + + + Net card + དྲ་རྒྱའི་བྱང་བུ། + + + + + hotspot already open + ཚ་བ་ཆེ་བའི་གནད་དོན་དེ་སྒོ་ཕྱེ་ཟིན། + + + diff --git a/plugins/mobilehotspot/translations/tr.qm b/plugins/mobilehotspot/translations/tr.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/mobilehotspot/translations/tr.qm @@ -0,0 +1 @@ + + + + + BlacklistItem + + + Remove + + + + + BlacklistPage + + + Blacklist + + + + + ConnectDevListItem + + + drag into blacklist + + + + + ConnectdevPage + + + Connect device + + + + + MobileHotspot + + + MobileHotspot + + + + + mobilehotspot + + /mobilehotspot/mobilehotspot + + + + mobilehotspot open + + /mobilehotspot/mobilehotspot open + + + + MobileHotspotWidget + + + ukui control center + + + + + ukui control center desktop message + + + + + wirless switch is close or no wireless device + + + + + start to close hotspot + + + + + hotpots name or device is invalid + + + + + start to open hotspot + + + + + Contains at least 8 characters + + + + + Hotspot + + + + + + hotspot already close + + + + + Open + + + + + Wi-Fi Name + + + + + Password + + + + + Frequency band + + + + + Net card + + + + + + hotspot already open + + + + diff --git a/plugins/mobilehotspot/translations/zh_CN.qm b/plugins/mobilehotspot/translations/zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..1b67cfd1e75c7c8a763aa0d6aaa59291ce31c517 GIT binary patch literal 1698 zcmai!T}TvB6vwaYs_VMDnO|i^T*)jn33>>FqOcGH+uB`i6HB{0dtC=-XV$sn+7@Vm zy=0(0h!NTsiBd1oLl}_~^Z`W=MMTgChSgJMSWqZ^oEdjVSKR4g*_m_i|Mx%V+;eC9 zh=1jiss7$)1#8BRUb*+K93gZQna^+tCH0_`#!-Y!eP~C?4}{Dc(65#nSRXQNW4ZAD z$JAc=683#gIa~1%;wbg!@Op%jFQi?Kbi(T<%k_zmpnsfxyK5KhZ%H4SDug((-k&~= zP)e=!Rn=F}J2SQnUW54f+<(%FjL<+ma6Z@?2OfaF&UULGxTe3hFZnNkbJuaOC3)_uAA%_3R0UnT*}i;9GOF&`C>wObNJ$|-wjxN4!brTaZM zsM_nsj_6M8r(vGcQjUcnqT5>{v+m*0Way4AwC|IAyg(}@g@q(V%Q`NiWxa$fsL7fP zWsaB|!VRc;v+kJ{C&p5UiV2J}PkleU+>=sWg36r5b>0(2I%6#qtPoygm?&7FgekZT zb4^4hoI+)$^0MO!@$&uvRp!d+aJ9cZf3AL>=BSWqODh$*2=)=tZ>)}0rRS2ipnC~T zZLSvQjSiQG9G~(`=u(T5Dwrd(v86e#edhhqh9&f}s0G$NI+ir=bAT|`CjH09fxL)E zrKke&)%M6YU2XO9r4>AOlAtzO34OEF(NdMZJasyI^Sh>WMghzUOc=u=P_QINCl&Jy z20u&$-na!;6@6sd#d;@oWNvi)FcD-*{1MCv5;M*)iizuI&SFe#AQRSUYe2P6)l}lH zQXW%?tYEmrS{^uxH5?|5G!(n1g#FO9JMo z2p7W;kr_iYRrUFLR<(W7QR|jK!2z;nMGD~{WemP=hUj8C-agiVTx{+LeR)oM-68MB yK)PDD`_jqZ;ZAjjdOvj2(l%ZefQ?xjuW(K3q|7xIhDVeztWs@x{*$-lf&ByVl + + + + BlacklistItem + + + Remove + 移出 + + + + BlacklistPage + + + Blacklist + 设备黑名单 + + + + ConnectDevListItem + + + drag into blacklist + 添加进黑名单 + + + + ConnectdevPage + + + Connect device + 连接设备 + + + + MobileHotspot + + + MobileHotspot + 移动热点 + + + + mobilehotspot + 移动热点 + /mobilehotspot/mobilehotspot + + + + mobilehotspot open + 移动热点 开启 + /mobilehotspot/mobilehotspot open + + + + MobileHotspotWidget + + + ukui control center + 控制面板 + + + + ukui control center desktop message + 控制面板桌面通知 + + + + wirless switch is close or no wireless device + 无线开关已关闭或不存在有热点功能的无线网卡 + + + + start to close hotspot + 开始关闭热点 + + + + hotpots name or device is invalid + 热点名称或设备错误 + + + can not create hotspot with password length less than eight! + 不能创建密码长度小于八位的热点! + + + + start to open hotspot + 开始创建热点 + + + + Contains at least 8 characters + 至少包含8个字符 + + + + Hotspot + 移动热点 + + + + + hotspot already close + 热点已关闭 + + + + Open + 开启 + + + + Wi-Fi Name + Wi-Fi名称 + + + + Password + 网络密码 + + + + Frequency band + 网络频带 + + + + Net card + 共享网卡端口 + + + + + hotspot already open + 热点已开启 + + + diff --git a/plugins/netconnect/deviceframe.cpp b/plugins/netconnect/deviceframe.cpp new file mode 100644 index 00000000..31a3ea5a --- /dev/null +++ b/plugins/netconnect/deviceframe.cpp @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "deviceframe.h" + +#define LAYOUT_MARGINS 16,0,16,0 +#define FRAME_HEIGHT 58 +#define RADIUS 6.0 + +DeviceFrame::DeviceFrame(QString devName, QWidget *parent) : QFrame(parent) +{ + this->setFrameShape(QFrame::Box); + this->setFixedHeight(FRAME_HEIGHT); + QHBoxLayout *deviceLayout = new QHBoxLayout(this); + deviceLayout->setContentsMargins(LAYOUT_MARGINS); + setLayout(deviceLayout); + + deviceLabel = new QLabel(this); + dropDownLabel = new DrownLabel(devName, this); + deviceSwitch = new KSwitchButton(this); + deviceSwitch->installEventFilter(this); + + deviceLayout->addWidget(deviceLabel); + deviceLayout->addStretch(); + deviceLayout->addWidget(dropDownLabel); + deviceLayout->addWidget(deviceSwitch); +} + +bool DeviceFrame::eventFilter(QObject *w,QEvent *e) +{ + if (w == deviceSwitch) { + if (e->type() == QEvent::MouseButtonPress) { + emit deviceSwitchClicked(!deviceSwitch->isChecked()); + return true; + } + } + return QFrame::eventFilter(w, e); +} + +void DeviceFrame::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + painter.setBrush(pal.color(QPalette::Base)); + + QRect rect = this->rect(); + QPainterPath path; + path.addRoundedRect (rect, RADIUS, RADIUS); + QRect temp_rect(rect.left(), rect.top() + rect.height()/2, rect.width(), rect.height()/2); + path.addRect(temp_rect); + painter.drawPath(path); + QFrame::paintEvent(event); +} diff --git a/plugins/netconnect/deviceframe.h b/plugins/netconnect/deviceframe.h new file mode 100644 index 00000000..41752d03 --- /dev/null +++ b/plugins/netconnect/deviceframe.h @@ -0,0 +1,58 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DEVICEFRAME_H +#define DEVICEFRAME_H +#include +#include +#include +#include +#include +#include +#include +#include "../component/DrownLabel/drownlabel.h" +#include "kwidget.h" +#include "kswitchbutton.h" + +using namespace kdk; + +class DeviceFrame : public QFrame +{ + Q_OBJECT +public: + DeviceFrame(QString devName, QWidget *parent = nullptr); +public: + QLabel * deviceLabel = nullptr; + KSwitchButton * deviceSwitch = nullptr; + DrownLabel *dropDownLabel = nullptr; + +protected: + void paintEvent(QPaintEvent *event); + bool eventFilter(QObject *w,QEvent *e); + +private: + bool isDropDown = false; + int frameSize; + +signals: + void deviceSwitchClicked(bool); + +}; + +#endif // DEVICEFRAME_H diff --git a/plugins/netconnect/itemframe.cpp b/plugins/netconnect/itemframe.cpp new file mode 100644 index 00000000..17b83de7 --- /dev/null +++ b/plugins/netconnect/itemframe.cpp @@ -0,0 +1,61 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "itemframe.h" + +#include +#include + +#define LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +ItemFrame::ItemFrame(QString devName, QWidget *parent) : QFrame(parent) +{ + deviceLanLayout = new QVBoxLayout(this); + deviceLanLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); + lanItemFrame = new QFrame(this); + lanItemFrame->setFrameShape(QFrame::Shape::NoFrame); + + lanItemLayout = new QVBoxLayout(this); + lanItemLayout->setContentsMargins(LAYOUT_MARGINS); + lanItemLayout->setSpacing(1); + addLanWidget = new AddNetBtn(false, this); + + deviceLanLayout->setSpacing(1); + setLayout(deviceLanLayout); + lanItemFrame->setLayout(lanItemLayout); + + deviceFrame = new DeviceFrame(devName, this); + deviceLanLayout->addWidget(deviceFrame); + deviceLanLayout->addWidget(lanItemFrame); + deviceLanLayout->addWidget(addLanWidget); + + //下拉按钮 + connect(deviceFrame->dropDownLabel, &DrownLabel::labelClicked, this, &ItemFrame::onDrownLabelClicked); +} + +void ItemFrame::onDrownLabelClicked() +{ + if (!deviceFrame->dropDownLabel->isChecked) { + lanItemFrame->show(); + deviceFrame->dropDownLabel->setDropDownStatus(true); + } else { + lanItemFrame->hide(); + deviceFrame->dropDownLabel->setDropDownStatus(false); + } +} diff --git a/plugins/netconnect/itemframe.h b/plugins/netconnect/itemframe.h new file mode 100644 index 00000000..ee3bbe9e --- /dev/null +++ b/plugins/netconnect/itemframe.h @@ -0,0 +1,51 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef ITEMFRAME_H +#define ITEMFRAME_H +#include +#include +#include "deviceframe.h" +#include +#include "../component/AddBtn/addnetbtn.h" +#include "lanitem.h" + +class ItemFrame : public QFrame +{ + Q_OBJECT +public: + ItemFrame(QString devName, QWidget *parent = nullptr); + //单设备整体layout + QVBoxLayout * deviceLanLayout = nullptr; + //单设备名称+下拉按钮Frame+d单设备开关 + DeviceFrame * deviceFrame = nullptr; + //单设备列表Frame + QFrame * lanItemFrame = nullptr; + //单设备列表layout + QVBoxLayout * lanItemLayout = nullptr; + //新建有线连接 + AddNetBtn * addLanWidget = nullptr; + //单设备item列表 key:uuid + QMap itemMap; + +private slots: + void onDrownLabelClicked(); +}; + +#endif // ITEMFRAME_H diff --git a/plugins/netconnect/lanitem.cpp b/plugins/netconnect/lanitem.cpp new file mode 100644 index 00000000..a8903cf3 --- /dev/null +++ b/plugins/netconnect/lanitem.cpp @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "lanitem.h" +#define FRAME_SPEED 150 +#define LIMIT_TIME 60*1000 +#define TOTAL_PAGE 8 + +#define THEME_QT_SCHEMA "org.ukui.style" +#define MODE_QT_KEY "style-name" + +LanItem::LanItem(bool isAcitve, QWidget *parent) + : QPushButton(parent),isAcitve(isAcitve) +{ + this->setMinimumSize(550, 58); + this->setProperty("useButtonPalette", true); + this->setFlat(true); + QPalette pal = this->palette(); + QColor color = pal.color(QPalette::Button); + color.setAlphaF(0.5); + pal.setColor(QPalette::Button, color); + this->setPalette(pal); +// setStyleSheet("QPushButton:!checked{background-color: palette(base)}"); + QHBoxLayout *mLanLyt = new QHBoxLayout(this); + mLanLyt->setContentsMargins(16,0,16,0); + mLanLyt->setSpacing(16); + iconLabel = new QLabel(this); + iconLabel->setProperty("useIconHighlightEffect", 0x2); + titileLabel = new FixLabel(this); + statusLabel = new QLabel(this); + statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); +// statusLabel->setMinimumSize(36,36); + infoLabel = new GrayInfoButton(this); + mLanLyt->addWidget(iconLabel); + mLanLyt->addWidget(titileLabel,Qt::AlignLeft); + mLanLyt->addStretch(); + mLanLyt->addWidget(statusLabel); + mLanLyt->addWidget(infoLabel); + + loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic")); + waitTimer = new QTimer(this); + connect(waitTimer, &QTimer::timeout, this, &LanItem::updateIcon); +} + +LanItem::~LanItem() +{ + +} + +void LanItem::updateIcon() +{ + if (currentIconIndex > 6) { + currentIconIndex = 0; + } + statusLabel->setPixmap(loadIcons.at(currentIconIndex).pixmap(16,16)); + currentIconIndex ++; +} + +void LanItem::startLoading() +{ + waitTimer->start(FRAME_SPEED); + loading = true; +} + +void LanItem::stopLoading(){ + waitTimer->stop(); + loading = false; +} + +void LanItem::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + painter.setBrush(pal.color(QPalette::Base)); + + QRect rect = this->rect(); + + painter.drawRect(rect); + QPushButton::paintEvent(event); +} + diff --git a/plugins/netconnect/lanitem.h b/plugins/netconnect/lanitem.h new file mode 100644 index 00000000..ea1b1355 --- /dev/null +++ b/plugins/netconnect/lanitem.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef LANITEM_H +#define LANITEM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fixlabel.h" +//#include "infobutton.h" +#include "../component/AddBtn/grayinfobutton.h" + +class LanItem : public QPushButton +{ +public: + LanItem(bool isAcitve, QWidget *parent = nullptr); + ~LanItem(); +public: + QLabel * iconLabel = nullptr; + GrayInfoButton * infoLabel = nullptr; + FixLabel * titileLabel = nullptr; + QLabel * statusLabel = nullptr; + +public: + void startLoading(); + void stopLoading(); + + bool loading = false; + bool isAcitve = false; + + QString uuid; + QString dbusPath; + +protected: + void paintEvent(QPaintEvent *); + +private: + QTimer *waitTimer = nullptr; + QGSettings *themeGsettings = nullptr; + QList loadIcons; + int currentIconIndex=0; + +private slots: + void updateIcon(); + +}; + +#endif // LANITEM_H diff --git a/plugins/netconnect/netconnect.cpp b/plugins/netconnect/netconnect.cpp new file mode 100644 index 00000000..877ac8de --- /dev/null +++ b/plugins/netconnect/netconnect.cpp @@ -0,0 +1,898 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "netconnect.h" +#include "ui_netconnect.h" + +#include +#include +#include +#include +#include +#include +#include + +#define WIRED_TYPE 0 +#define ITEMHEIGH 50 +#define LAN_TYPE 0 +#define CONTROL_CENTER_WIFI "org.ukui.control-center.wifi.switch" + +const QString KLanSymbolic = "network-wired-connected-symbolic"; +const QString NoNetSymbolic = "network-wired-disconnected-symbolic"; + +const QString WIRED_SWITCH = "wiredswitch"; +const QByteArray GSETTINGS_SCHEMA = "org.ukui.kylin-nm.switch"; + +#define ACTIVATING 1 +#define ACTIVATED 2 +#define DEACTIVATING 3 +#define DEACTIVATED 4 + +#define NO_MARGINS 0,0,0,0 +#define TOP_MARGINS 0,8,0,0 +#define MAIN_LAYOUT_MARGINS 0,0,0,8 +#define SPACING 8 +#define ICON_SIZE 16,16 + +bool sortByVal(const QPair &l, const QPair &r) { + return (l.second < r.second); +} + +void NetConnect::showDesktopNotify(const QString &message) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QList args; + args<<(tr("ukui control center")) + <<((unsigned int) 0) + <load("/usr/share/kylin-nm/netconnect/" + QLocale::system().name()); + QApplication::installTranslator(translator); + + pluginName = tr("WiredConnect"); + pluginType = NETWORK; +} + +NetConnect::~NetConnect() { + if (!mFirstLoad) { + delete ui; + ui = nullptr; + delete m_interface; + delete m_switchGsettings; + } +} + +QString NetConnect::plugini18nName() { + return pluginName; +} + +int NetConnect::pluginTypes() { + return pluginType; +} + +QWidget *NetConnect::pluginUi() { + if (mFirstLoad) { + mFirstLoad = false; + + ui = new Ui::NetConnect; + pluginWidget = new QWidget; + pluginWidget->setAttribute(Qt::WA_DeleteOnClose); + ui->setupUi(pluginWidget); + qDBusRegisterMetaType>(); + m_interface = new QDBusInterface("com.kylin.network", + "/com/kylin/network", + "com.kylin.network", + QDBusConnection::sessionBus()); + if(!m_interface->isValid()) { + qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); + } + initSearchText(); + initComponent(); + } + return pluginWidget; +} + +const QString NetConnect::name() const { + + return QStringLiteral("netconnect"); +} + +bool NetConnect::isEnable() const +{ + return true; +} + + +bool NetConnect::isShowOnHomePage() const +{ + return false; +} + +QIcon NetConnect::icon() const +{ + return QIcon::fromTheme("network-wired-symbolic"); +} + +QString NetConnect::translationPath() const +{ + return "/usr/share/kylin-nm/netconnect/%1.ts"; +} + +void NetConnect::initSearchText() { + //~ contents_path /netconnect/Advanced settings" + ui->detailBtn->setText(tr("Advanced settings")); + ui->titleLabel->setText(tr("Wired Network")); + //~ contents_path /netconnect/open + ui->openLabel->setText(tr("open")); +} + +bool NetConnect::eventFilter(QObject *w, QEvent *e) { + if (e->type() == QEvent::Enter) { + if (w->findChild()) + w->findChild()->setStyleSheet("QWidget{background: palette(button);border-radius:4px;}"); + } else if (e->type() == QEvent::Leave) { + if (w->findChild()) + w->findChild()->setStyleSheet("QWidget{background: palette(base);border-radius:4px;}"); + } + if (w == wiredSwitch) { + if (e->type() == QMouseEvent::MouseButtonRelease) { + if (!wiredSwitch->isCheckable()) { + showDesktopNotify(tr("No ethernet device avaliable")); + } else { + m_interface->call(QStringLiteral("setWiredSwitchEnable"), !wiredSwitch->isChecked()); + return true; + } + } + } + + return QObject::eventFilter(w,e); +} + +void NetConnect::initComponent() { + wiredSwitch = new KSwitchButton(pluginWidget); + ui->openWIifLayout->addWidget(wiredSwitch); + ui->openWIifLayout->setContentsMargins(0,0,8,0); + ui->detailLayOut->setContentsMargins(MAIN_LAYOUT_MARGINS); + ui->verticalLayout_3->setContentsMargins(NO_MARGINS); + ui->verticalLayout_3->setSpacing(8); + ui->availableLayout->setSpacing(SPACING); + ui->horizontalLayout->setContentsMargins(TOP_MARGINS); + + wiredSwitch->installEventFilter(this); + + if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA)) { + m_switchGsettings = new QGSettings(GSETTINGS_SCHEMA); + + setSwitchStatus(); + + connect(m_switchGsettings, &QGSettings::changed, this, [=] (const QString &key) { + if (key == WIRED_SWITCH) { + setSwitchStatus(); + } + }); + } else { + wiredSwitch->blockSignals(true); + wiredSwitch->setChecked(true); + wiredSwitch->blockSignals(false); + qDebug()<<"[Netconnect] org.ukui.kylin-nm.switch is not installed!"; + } + + getDeviceStatusMap(deviceStatusMap); + if (deviceStatusMap.isEmpty()) { + qDebug() << "[Netconnect] no device exist when init, set switch disable"; + wiredSwitch->setChecked(false); + wiredSwitch->setCheckable(false); + } + initNet(); + + if (!wiredSwitch->isChecked() || deviceStatusMap.isEmpty() || !m_interface->isValid()) { + hideLayout(ui->availableLayout); + } + + + // 有线网络断开或连接时刷新可用网络列表 + connect(m_interface, SIGNAL(lanActiveConnectionStateChanged(QString, QString, int)), this, SLOT(onActiveConnectionChanged(QString, QString, int)), Qt::QueuedConnection); + //有线网络新增时添加网络 + connect(m_interface, SIGNAL(lanAdd(QString, QStringList)), this, SLOT(onLanAdd(QString, QStringList)), Qt::QueuedConnection); + //删除有线网络 + connect(m_interface, SIGNAL(lanRemove(QString)), this, SLOT(onLanRemove(QString)), Qt::QueuedConnection); + //更新有线网络 + connect(m_interface, SIGNAL(lanUpdate(QString, QStringList)), this, SLOT(updateLanInfo(QString, QStringList)),Qt::QueuedConnection); + //网卡插拔处理 + connect(m_interface, SIGNAL(deviceStatusChanged()), this, SLOT(onDeviceStatusChanged()),Qt::QueuedConnection); + //网卡name处理 + connect(m_interface, SIGNAL(deviceNameChanged(QString, QString, int)), this, SLOT(onDeviceNameChanged(QString, QString, int)),Qt::QueuedConnection); + + + connect(ui->detailBtn, &QPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + runExternalApp(); + }); +} + +//获取网卡列表 +void NetConnect::getDeviceStatusMap(QMap &map) +{ + if (!m_interface->isValid()) { + return; + } + qDebug() << "[NetConnect]call getDeviceListAndEnabled" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getDeviceListAndEnabled"),0); + qDebug() << "[NetConnect]call getDeviceListAndEnabled Respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "[NetConnect]getWiredDeviceList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + dbusArg >> map; +} + +//lanUpdate +void NetConnect::updateLanInfo(QString deviceName, QStringList lanInfo) +{ + //she bei gui shu bian hua && you xian ming cheng bian hua + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (deviceName.isEmpty()) { + //变为无指定网卡,所有列表都要添加 + if (!iter.value()->itemMap.contains(lanInfo.at(1))) { + qDebug() << "[NetConnect]" << lanInfo.at(0) << " change to device none, add every list"; + addOneLanFrame(iter.value(), iter.key(), lanInfo); + } else { + if (iter.value()->itemMap[lanInfo.at(1)]->titileLabel->text() != lanInfo.at(0)) { + qDebug() << "[NetConnect]" << iter.key() + << iter.value()->itemMap[lanInfo.at(1)]->titileLabel->text() << "change to" << lanInfo.at(0); + iter.value()->itemMap[lanInfo.at(1)]->titileLabel->setText(lanInfo.at(0)); + } + } + } else { + if (iter.key() != deviceName) { + qDebug() << "[NetConnect]" << lanInfo.at(0) << " not belongs to " << iter.key(); + removeOneLanFrame(iter.value(), deviceName, lanInfo.at(1)); + } else { + if (!iter.value()->itemMap.contains(lanInfo.at(1))) { + qDebug() << "[NetConnect]" << lanInfo.at(0) << " now belongs to " << deviceName; + addOneLanFrame(iter.value(), deviceName, lanInfo); + } else { + qDebug() << "[NetConnect]" << deviceName + << iter.value()->itemMap[lanInfo.at(1)]->titileLabel->text() << "change to" << lanInfo.at(0); + if (iter.value()->itemMap[lanInfo.at(1)]->titileLabel->text() != lanInfo.at(0)) { + iter.value()->itemMap[lanInfo.at(1)]->titileLabel->setText(lanInfo.at(0)); + } + } + } + } + } +} + + +//总开关 +void NetConnect::setSwitchStatus() +{ + if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA)) { + bool status = m_switchGsettings->get(WIRED_SWITCH).toBool(); + wiredSwitch->blockSignals(true); + wiredSwitch->setChecked(status); + wiredSwitch->blockSignals(false); + if (!status) { + hideLayout(ui->availableLayout); + } else { + showLayout(ui->availableLayout); + } + } else { + qDebug()<<"[netconnect] org.ukui.kylin-nm.switch is not installed!"; + } + +} + +//总体隐藏 +void NetConnect::hideLayout(QVBoxLayout * layout) { + for (int i = layout->layout()->count()-1; i >= 0; --i) + { + QLayoutItem *it = layout->layout()->itemAt(i); + ItemFrame *itemFrame = qobject_cast(it->widget()); + itemFrame->hide(); + } +} + +//总体显示 +void NetConnect::showLayout(QVBoxLayout * layout) { + for (int i = layout->layout()->count()-1; i >= 0; --i) + { + QLayoutItem *it = layout->layout()->itemAt(i); + ItemFrame *itemFrame = qobject_cast(it->widget()); + itemFrame->show(); + } +} + +//初始化 +void NetConnect::initNet() +{ + //先构建每个设备的列表头 + QStringList deviceList = deviceStatusMap.keys(); + for (int i = 0; i < deviceList.size(); ++i) { + addDeviceFrame(deviceList.at(i)); + } + //再填充每个设备的列表 + for (int i = 0; i < deviceList.size(); ++i) { + initNetListFromDevice(deviceList.at(i)); + } +} + +void NetConnect::runExternalApp() { + QString cmd = "nm-connection-editor"; + QProcess process(this); + process.startDetached(cmd); +} + +//激活 +void NetConnect::activeConnect(QString ssid, QString deviceName, int type) { + qDebug() << "[NetConnect]call activateConnect" << __LINE__; + m_interface->call(QStringLiteral("activateConnect"),type, deviceName, ssid); + qDebug() << "[NetConnect]call activateConnect respond" << __LINE__; +} + +//断开 +void NetConnect::deActiveConnect(QString ssid, QString deviceName, int type) { + qDebug() << "[NetConnect]call deActivateConnect" << __LINE__; + m_interface->call(QStringLiteral("deActivateConnect"),type, deviceName, ssid); + qDebug() << "[NetConnect]call deActivateConnect respond" << __LINE__; +} + +//初始化设备列表 网卡标号问题? +void NetConnect::initNetListFromDevice(QString deviceName) +{ + qDebug() << "[NetConnect]initNetListFromDevice " << deviceName; + if (!deviceFrameMap.contains(deviceName)) { + qDebug() << "[NetConnect]initNetListFromDevice " << deviceName << " not exist"; + return; + } + if (!m_interface->isValid()) { + return; + } + qDebug() << "[NetConnect]call getWiredList" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getWiredList")); + qDebug() << "[NetConnect]call getWiredList respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "getWiredList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + QMap> variantList; + dbusArg >> variantList; + if (variantList.size() == 0) { + qDebug() << "[NetConnect]initNetListFromDevice " << deviceName << " list empty"; + return; + } + QMap>::iterator iter; + + for (iter = variantList.begin(); iter != variantList.end(); iter++) { + if (deviceName == iter.key()) { + QVector wlanListInfo = iter.value(); + //处理列表 已连接 + qDebug() << "[NetConnect]initNetListFromDevice " << deviceName << " acitved lan " << wlanListInfo.at(0); + addLanItem(deviceFrameMap[deviceName], deviceName, wlanListInfo.at(0), true); + //处理列表 未连接 + for (int i = 1; i < wlanListInfo.length(); i++) { + qDebug() << "[NetConnect]initNetListFromDevice " << deviceName << " deacitved lan " << wlanListInfo.at(i); + addLanItem(deviceFrameMap[deviceName], deviceName, wlanListInfo.at(i), false); + } + } + } + return; +} + +//初始化时添加一个项 不考虑顺序 +void NetConnect::addLanItem(ItemFrame *frame, QString devName, QStringList infoList, bool isActived) +{ + if (frame == nullptr) { + return; + } + if (infoList.size() == 1) { + return; + } + + LanItem * lanItem = new LanItem(pluginWidget); + QString iconPath = KLanSymbolic; + if (isActived) { + lanItem->statusLabel->setText(tr("connected")); + } else { + lanItem->statusLabel->setText(""); + } + QIcon searchIcon = QIcon::fromTheme(iconPath); +// if (iconPath != KLanSymbolic && iconPath != NoNetSymbolic) { +// lanItem->iconLabel->setProperty("useIconHighlightEffect", 0x10); +// } + lanItem->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(ICON_SIZE)))); + lanItem->titileLabel->setText(infoList.at(0)); + + lanItem->uuid = infoList.at(1); + lanItem->dbusPath = infoList.at(2); + + connect(lanItem->infoLabel, &GrayInfoButton::clicked, this, [=]{ + // open landetail page + if (!m_interface->isValid()) { + return; + } + qDebug() << "[NetConnect]call showPropertyWidget" << __LINE__; + m_interface->call(QStringLiteral("showPropertyWidget"), devName, infoList.at(1)); + qDebug() << "[NetConnect]call showPropertyWidget respond" << __LINE__; + }); + + lanItem->isAcitve = isActived; + + connect(lanItem, &QPushButton::clicked, this, [=] { + if (lanItem->isAcitve || lanItem->loading) { + deActiveConnect(lanItem->uuid, devName, WIRED_TYPE); + } else { + activeConnect(lanItem->uuid, devName, WIRED_TYPE); + } + }); + + //记录到deviceFrame的itemMap中 + deviceFrameMap[devName]->itemMap.insert(infoList.at(1), lanItem); + qDebug()<<"insert " << infoList.at(1) << " to " << devName << " list"; + frame->lanItemLayout->addWidget(lanItem); +} + +//增加设备 +void NetConnect::addDeviceFrame(QString devName) +{ + qDebug() << "[NetConnect]addDeviceFrame " << devName; + + qDebug() << "[NetConnect]call getDeviceListAndEnabled" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getDeviceListAndEnabled"),0); + qDebug() << "[NetConnect]call getDeviceListAndEnabled Respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "[NetConnect]getWiredDeviceList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + QMap map; + dbusArg >> map; + + bool enable = true; + if (map.contains(devName)) { + enable = map[devName]; + } + + ItemFrame *itemFrame = new ItemFrame(devName, pluginWidget); + ui->availableLayout->addWidget(itemFrame); + itemFrame->deviceFrame->deviceLabel->setText(tr("card")+/*QString("%1").arg(count)+*/":"+devName); + itemFrame->deviceFrame->deviceSwitch->setChecked(enable); + if (enable) { + itemFrame->lanItemFrame->show(); + itemFrame->deviceFrame->dropDownLabel->show(); + } else { + itemFrame->lanItemFrame->hide(); + itemFrame->deviceFrame->dropDownLabel->hide(); + itemFrame->deviceFrame->dropDownLabel->setDropDownStatus(false); + } + deviceFrameMap.insert(devName, itemFrame); + qDebug() << "[NetConnect]deviceFrameMap insert" << devName; + + connect(itemFrame->deviceFrame, &DeviceFrame::deviceSwitchClicked ,this, [=] (bool checked) { + qDebug() << "[NetConnect]call setDeviceEnable" << devName << checked << __LINE__; + m_interface->call(QStringLiteral("setDeviceEnable"), devName, checked); + qDebug() << "[NetConnect]call setDeviceEnable Respond" << __LINE__; + }); + + connect(itemFrame->deviceFrame->deviceSwitch, &KSwitchButton::stateChanged, this, [=] (bool checked) { + + if (checked) { + qDebug() << "[NetConnect]set " << devName << "status" << true; + itemFrame->lanItemFrame->show(); + itemFrame->deviceFrame->dropDownLabel->show(); + itemFrame->deviceFrame->dropDownLabel->setDropDownStatus(true); + deviceStatusMap[devName] = true; + } else { + qDebug() << "[NetConnect]set " << devName << "status" << false; + itemFrame->lanItemFrame->hide(); + itemFrame->deviceFrame->dropDownLabel->hide(); + deviceStatusMap[devName] = false; + } + }); + + connect(itemFrame->addLanWidget, &AddNetBtn::clicked, this, [=](){ + if (m_interface->isValid()) { + qDebug() << "[NetConnect]call showCreateWiredConnectWidget" << devName << __LINE__; + m_interface->call(QStringLiteral("showCreateWiredConnectWidget"), devName); + qDebug() << "[NetConnect]call setDeviceEnable Respond" << __LINE__; + } + }); +} + +//减少设备 +void NetConnect::removeDeviceFrame(QString devName) +{ + qDebug() << "[NetConnect]removeDeviceFrame " << devName; + if (deviceFrameMap.contains(devName)) { + ItemFrame *item = deviceFrameMap[devName]; + if (item->lanItemFrame->layout() != NULL) { + QLayoutItem* layoutItem; + while ((layoutItem = item->lanItemFrame->layout()->takeAt(0)) != NULL) { + delete layoutItem->widget(); + delete layoutItem; + layoutItem = nullptr; + } + item->itemMap.clear(); + } + delete item; + item = nullptr; + deviceFrameMap.remove(devName); + qDebug() << "[NetConnect]deviceFrameMap remove" << devName; + } +} + +//device add or remove================================= +void NetConnect::onDeviceStatusChanged() +{ + qDebug()<<"[NetConnect]onDeviceStatusChanged"; + QEventLoop eventloop; + QTimer::singleShot(300, &eventloop, SLOT(quit())); + eventloop.exec(); + QStringList list; + QMap map; + getDeviceStatusMap(map); + list = map.keys(); + + QStringList removeList; + QMap addMap; + + //remove的设备 + for (int i = 0; i< deviceStatusMap.keys().size(); ++i) { + if (!list.contains(deviceStatusMap.keys().at(i))) { + qDebug() << "[NetConnect]onDeviceStatusChanged " << deviceStatusMap.keys().at(i) << "was removed"; + removeList << deviceStatusMap.keys().at(i); + } + } + + //add的设备 + for (int i = 0; i< list.size(); ++i) { + if (!deviceStatusMap.keys().contains(list.at(i))) { + qDebug() << "[NetConnect]onDeviceStatusChanged " << list.at(i) << "was add, init status" << map[list.at(i)]; + addMap.insert(list.at(i),map[list.at(i)]); + } + } + + for (int i = 0; i < removeList.size(); ++i) { + removeDeviceFrame(removeList.at(i)); + } + + QStringList addList = addMap.keys(); + for (int i = 0; i < addList.size(); ++i) { + qDebug() << "add a device " << addList.at(i) << "status" << map[addList.at(i)]; + addDeviceFrame(addList.at(i)); + initNetListFromDevice(addList.at(i)); + } + deviceStatusMap = map; + if (deviceStatusMap.isEmpty()) { + wiredSwitch->setChecked(false); + wiredSwitch->setCheckable(false); + } else { + wiredSwitch->setCheckable(true); + setSwitchStatus(); + } + + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (deviceStatusMap.contains(iter.key())) { + if (iter.value()->deviceFrame->deviceSwitch->isChecked() != deviceStatusMap[iter.key()]) { + iter.value()->deviceFrame->deviceSwitch->setChecked(deviceStatusMap[iter.key()]); + } + } + } +} + +void NetConnect::onDeviceNameChanged(QString oldName, QString newName, int type) +{ + if (WIRED_TYPE != type || !deviceFrameMap.contains(oldName) || !deviceStatusMap.contains(oldName)) { + qDebug() << "[NetConnect]onDeviceNameChanged no such device " << oldName; + return; + } + + if (deviceFrameMap.contains(newName) && deviceStatusMap.contains(newName)) { + qDebug() << "[NetConnect]onDeviceNameChanged already has device " << newName; + return; + } + + qDebug() << "[NetConnect]onDeviceNameChanged " << oldName << "change to" << newName; + + //shan chu chong jian + removeDeviceFrame(oldName); + removeDeviceFrame(newName); + + getDeviceStatusMap(deviceStatusMap); + if (deviceStatusMap.contains(newName)) { + addDeviceFrame(newName); + initNetListFromDevice(newName); + } +} + +//wifi add=============================================================== +void NetConnect::onLanAdd(QString deviceName, QStringList lanInfo) +{ + qDebug()<<"[NetConnect]onLanAdd "<< deviceName << " " << lanInfo; + + if (!deviceName.isEmpty() && !deviceStatusMap.contains(deviceName)) { + return; + } + + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (deviceName.isEmpty()) { + qDebug() << "[NetConnect]onLanAdd every list" << iter.key(); + addOneLanFrame(iter.value(), iter.key(), lanInfo); + } else if (deviceName == iter.key()) { + qDebug() << "[NetConnect]onLanAdd "<< deviceName; + addOneLanFrame(iter.value(), deviceName, lanInfo); + break; + } + } +} + +//wifi remove ============================================================= +void NetConnect::onLanRemove(QString lanPath) +{ + //开关已关闭 忽略 +// if (!wifiSwtch->isChecked()) { +// qDebug() << "[NetConnect]recieve network remove,but wireless switch is off"; +// return; +// } + + qDebug()<<"[NetConnect]lan remove " << "dbus path:" << lanPath; + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + QMap::iterator itemIter; + for (itemIter = iter.value()->itemMap.begin(); itemIter != iter.value()->itemMap.end(); itemIter++) { + if (itemIter.value()->dbusPath == lanPath) { + qDebug()<<"[NetConnect]lan remove " << lanPath << " find in " << itemIter.value()->titileLabel->text(); + QString key = itemIter.key(); + iter.value()->lanItemLayout->removeWidget(itemIter.value()); + delete itemIter.value(); + iter.value()->itemMap.remove(key); + break; + } + } + } +} + +//增加一项 +void NetConnect::addOneLanFrame(ItemFrame *frame, QString deviceName, QStringList infoList) +{ + if (nullptr == frame) { + return; + } + + if (frame->itemMap.contains(infoList.at(1))) { + qDebug() << "[NetConnect]Already exist a lan " << infoList.at(1) << " in " << deviceName; + return; + } + + qDebug() << "[NetConnect]addOneLanFrame" << deviceName << infoList.at(0); + QString connName = infoList.at(0); + QString connUuid = infoList.at(1); + QString connDbusPath = infoList.at(2); + LanItem * lanItem = new LanItem(pluginWidget); + + QString iconPath; + iconPath = KLanSymbolic; + lanItem->statusLabel->setText(""); + + QIcon searchIcon = QIcon::fromTheme(iconPath); +// if (iconPath != KLanSymbolic && iconPath != NoNetSymbolic) { +// lanItem->iconLabel->setProperty("useIconHighlightEffect", 0x10); +// } + lanItem->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(ICON_SIZE)))); + lanItem->titileLabel->setText(connName); + + lanItem->uuid = connUuid; + lanItem->dbusPath = connDbusPath; + + connect(lanItem->infoLabel, &GrayInfoButton::clicked, this, [=]{ + // open landetail page + if (!m_interface->isValid()) { + return; + } + qDebug() << "[NetConnect]call showPropertyWidget" << deviceName << connUuid << __LINE__; + m_interface->call(QStringLiteral("showPropertyWidget"), deviceName, connUuid); + qDebug() << "[NetConnect]call showPropertyWidget respond" << __LINE__; + }); + + lanItem->isAcitve = false; + + connect(lanItem, &QPushButton::clicked, this, [=] { + if (lanItem->isAcitve || lanItem->loading) { + deActiveConnect(lanItem->uuid, deviceName, WIRED_TYPE); + } else { + activeConnect(lanItem->uuid, deviceName, WIRED_TYPE); + } + }); + + //记录到deviceFrame的itemMap中 + deviceFrameMap[deviceName]->itemMap.insert(connUuid, lanItem); + int index = getInsertPos(connName, deviceName); + qDebug()<<"[NetConnect]addOneLanFrame " << connName << " to " << deviceName << " list at pos:" << index; + frame->lanItemLayout->insertWidget(index, lanItem); +} + +void NetConnect::removeOneLanFrame(ItemFrame *frame, QString deviceName, QString uuid) +{ + if (nullptr == frame) { + return; + } + + if (!frame->itemMap.contains(uuid)) { + qDebug() << "[NetConnect]not exist a lan " << uuid << " in " << deviceName; + return; + } + + qDebug()<<"[NetConnect]removeOneLanFrame " << uuid << " find in " << deviceName; + + frame->lanItemLayout->removeWidget(frame->itemMap[uuid]); + delete frame->itemMap[uuid]; + frame->itemMap.remove(uuid); +} + +//activeconnect status change +void NetConnect::onActiveConnectionChanged(QString deviceName, QString uuid, int status) +{ + if (uuid.isEmpty()) { + qDebug() << "[NetConnect]onActiveConnectionChanged but uuid is empty"; + return; + } + qDebug() << "[NetConnect]onActiveConnectionChanged " << deviceName << uuid << status; + LanItem * item= nullptr; + if (deviceName.isEmpty()) { + if (status != DEACTIVATED) { + return; + } + //断开时 设备为空 说明此有线未指定设备 添加到所有列表中 + QStringList infoList; + QMap::iterator iters; + for (iters = deviceFrameMap.begin(); iters != deviceFrameMap.end(); iters++) { + if (iters.value()->itemMap.contains(uuid)) { + item = iters.value()->itemMap[uuid]; + infoList << item->titileLabel->text() << item->uuid << item->dbusPath; + //为断开则重新插入 + int index = getInsertPos(item->titileLabel->text(), iters.key()); + qDebug() << "[NetConnect]reinsert" << item->titileLabel->text() << "pos" << index << "in" << iters.key() << "because status changes to deactive"; + deviceFrameMap[iters.key()]->lanItemLayout->removeWidget(item); + deviceFrameMap[iters.key()]->lanItemLayout->insertWidget(index,item); + itemActiveConnectionStatusChanged(item, status); + } + } + //添加到所有列表中 + if (!infoList.isEmpty()) { + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (!iter.value()->itemMap.contains(uuid)) { + addOneLanFrame(iter.value(), iter.key(), infoList); + } + } + } + } else { + if (deviceFrameMap.contains(deviceName)) { + if (deviceFrameMap[deviceName]->itemMap.contains(uuid)) { + item = deviceFrameMap[deviceName]->itemMap[uuid]; + if (status == ACTIVATED) { + //为已连接则放到第一个 + deviceFrameMap[deviceName]->lanItemLayout->removeWidget(item); + deviceFrameMap[deviceName]->lanItemLayout->insertWidget(0,item); + } else if (status == DEACTIVATED) { + //为断开则重新插入 + int index = getInsertPos(item->titileLabel->text(), deviceName); + qDebug() << "[NetConnect]reinsert" << item->titileLabel->text() << "pos" << index << "in" << deviceName << "because status changes to deactive"; + deviceFrameMap[deviceName]->lanItemLayout->removeWidget(item); + deviceFrameMap[deviceName]->lanItemLayout->insertWidget(index,item); + } + itemActiveConnectionStatusChanged(item, status); + } + } else { + if (status == ACTIVATED || status == DEACTIVATED) { + //虚拟网卡处理 + QMap::iterator iters; + for (iters = deviceFrameMap.begin(); iters != deviceFrameMap.end(); iters++) { + if (iters.value()->itemMap.contains(uuid)) { + removeOneLanFrame(iters.value(), iters.key(), uuid); + } + } + } + } + } +} + +void NetConnect::itemActiveConnectionStatusChanged(LanItem *item, int status) +{ +// QString iconPath = NoNetSymbolic; + if (status == ACTIVATING) { + item->startLoading(); + } else if (status == ACTIVATED) { + item->stopLoading(); +// iconPath = KLanSymbolic; + item->statusLabel->clear(); + item->statusLabel->setMinimumSize(36,36); + item->statusLabel->setMaximumSize(16777215,16777215); + item->statusLabel->setText(tr("connected")); + item->isAcitve = true; + } else if (status == DEACTIVATING) { + item->startLoading(); + } else { + item->stopLoading(); + item->statusLabel->setMinimumSize(36,36); + item->statusLabel->setMaximumSize(16777215,16777215); + item->statusLabel->clear(); + item->isAcitve = false; + } + +// QIcon searchIcon = QIcon::fromTheme(iconPath); +// item->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(24, 24)))); +} + +int NetConnect::getInsertPos(QString connName, QString deviceName) +{ + qDebug() << "[NetConnect]getInsertPos" << connName << deviceName; + int index = 0; + if(!m_interface->isValid()) { + index = 0; + } else { + qDebug() << "[NetConnect]call getWiredList" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getWiredList")); + qDebug() << "[NetConnect]call getWiredList respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "getWiredList error:" << result.errorMessage(); + return 0; + } + auto dbusArg = result.arguments().at(0).value(); + QMap> variantList; + dbusArg >> variantList; + if (!variantList.contains(deviceName)) { + qDebug() << "[NetConnect] getInsertPos but " << deviceName << "not exist"; + return 0; + } + for (int i = 0; i < variantList[deviceName].size(); ++i ) { + if (variantList[deviceName].at(i).at(0) == connName) { + qDebug() << "pos in kylin-nm is " << i; + index = i; + break; + } + } + if (variantList[deviceName].at(0).size() == 1) { + index--; + } + } + return index; +} diff --git a/plugins/netconnect/netconnect.h b/plugins/netconnect/netconnect.h new file mode 100644 index 00000000..f991540f --- /dev/null +++ b/plugins/netconnect/netconnect.h @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef NETCONNECT_H +#define NETCONNECT_H + + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "interface.h" +#include "addbtn.h" +#include "fixlabel.h" +#include "hoverbtn.h" +#include "lanitem.h" +#include "deviceframe.h" +#include "itemframe.h" +#include "kwidget.h" +#include "kswitchbutton.h" + +using namespace kdk; + +enum { + DISCONNECTED, + NOINTERNET, + CONNECTED +}; + +namespace Ui { +class NetConnect; +} + +class NetConnect : public QObject, CommonInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface") + Q_INTERFACES(CommonInterface) + +public: + NetConnect(); + ~NetConnect(); + + QString plugini18nName() Q_DECL_OVERRIDE; + int pluginTypes() Q_DECL_OVERRIDE; + QWidget * pluginUi() Q_DECL_OVERRIDE; + const QString name() const Q_DECL_OVERRIDE; + bool isShowOnHomePage() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + bool isEnable() const Q_DECL_OVERRIDE; + QString translationPath() const Q_DECL_OVERRIDE; +private: + void initSearchText(); + void initComponent(); + void runExternalApp(); + + void showDesktopNotify(const QString &message); + + + //开关相关 + void setSwitchStatus(); + void hideLayout(QVBoxLayout * layout); + void showLayout(QVBoxLayout * layout); + + int getInsertPos(QString connName, QString deviceName); + + + void deleteOneLan(QString ssid); + void activeConnect(QString ssid, QString deviceName, int type); + void deActiveConnect(QString ssid, QString deviceName, int type); + + //获取设备列表 + void getDeviceStatusMap(QMap &map); + void initNet(); + void initNetListFromDevice(QString deviceName); + //处理列表增加 + void addLanItem(ItemFrame *frame, QString devName, QStringList infoList, bool isActived); + //增加设备 + void addDeviceFrame(QString devName); + //减少设备 + void removeDeviceFrame(QString devName); + //增加一项 + void addOneLanFrame(ItemFrame *frame, QString devName, QStringList infoList); + //减少一项 + void removeOneLanFrame(ItemFrame *frame, QString deviceName, QString uuid); + + //单个lan连接状态变化 + void itemActiveConnectionStatusChanged(LanItem *item, int status); + +protected: + bool eventFilter(QObject *w,QEvent *e); + +private: + Ui::NetConnect *ui; + + QString pluginName; + int pluginType; + QWidget *pluginWidget; + + QDBusInterface *m_interface = nullptr; + KSwitchButton *wiredSwitch; + + bool mFirstLoad; + QGSettings *m_switchGsettings; + + QMap deviceStatusMap; + QMap deviceFrameMap; + +private slots: + void updateLanInfo(QString deviceName, QStringList lanInfo); + + void onLanAdd(QString deviceName, QStringList lanInfo); + void onLanRemove(QString dbusPath); + + void onActiveConnectionChanged(QString deviceName, QString uuid, int status); + + void onDeviceStatusChanged(); + void onDeviceNameChanged(QString, QString, int); +}; + +Q_DECLARE_METATYPE(QList); + +#endif // NETCONNECT_H diff --git a/plugins/netconnect/netconnect.pro b/plugins/netconnect/netconnect.pro new file mode 100644 index 00000000..be66275c --- /dev/null +++ b/plugins/netconnect/netconnect.pro @@ -0,0 +1,54 @@ +QT += widgets network dbus gui core +TEMPLATE = lib +CONFIG += plugin + +include(../component/drownlabel.pri) +include(../component/addbtn.pri) + +TARGET = $$qtLibraryTarget(netconnect) +DESTDIR = ../.. +target.path = $$[QT_INSTALL_LIBS]/ukui-control-center +trans.files = translations/* +trans.path = /usr/share/kylin-nm/netconnect/ + +INCLUDEPATH += \ + $$PROJECT_COMPONENTSOURCE \ + $$PROJECT_ROOTDIR \ + /usr/include/ukcc/interface \ + /usr/include/ukcc/widgets + +LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt -lukcc + +CONFIG += c++11 \ + link_pkgconfig \ + +PKGCONFIG += gsettings-qt \ + kysdk-qtwidgets \ + +#DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + deviceframe.cpp \ +# drownlabel.cpp \ + itemframe.cpp \ + lanitem.cpp \ + netconnect.cpp + +HEADERS += \ + deviceframe.h \ +# drownlabel.h \ + itemframe.h \ + lanitem.h \ + netconnect.h + +FORMS += \ + netconnect.ui + +INSTALLS += target \ + trans + +TRANSLATIONS += \ + translations/zh_CN.ts \ + translations/tr.ts \ + translations/bo.ts \ + translations/bo_CN.ts diff --git a/plugins/netconnect/netconnect.ui b/plugins/netconnect/netconnect.ui new file mode 100644 index 00000000..4c4e2267 --- /dev/null +++ b/plugins/netconnect/netconnect.ui @@ -0,0 +1,244 @@ + + + NetConnect + + + + 0 + 0 + 885 + 700 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + NetConnect + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Wired Network + + + true + + + + + + + 1 + + + 0 + + + + + + 0 + 60 + + + + + 16777215 + 50 + + + + QFrame::Box + + + + 18 + + + 0 + + + 9 + + + 0 + + + + + 0 + + + 8 + + + + + + 118 + 0 + + + + open + + + + + + + Qt::Horizontal + + + + 523 + 20 + + + + + + + + + + + + + + + 1 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + + + + + + + + + + + + + + 120 + 36 + + + + + 16777215 + 36 + + + + Advanced settings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + TitleLabel + QLabel +
titlelabel.h
+
+
+ + +
diff --git a/plugins/netconnect/translations/bo.qm b/plugins/netconnect/translations/bo.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/netconnect/translations/bo.qm @@ -0,0 +1 @@ + + + + + AddNetBtn + + + Add WiredNetork + + + + + NetConnect + + + + Wired Network + + + + + + open + + /netconnect/open + + + + + Advanced settings + + /netconnect/Advanced settings" + + + + ukui control center + + + + + ukui control center desktop message + + + + + WiredConnect + + + + + No ethernet device avaliable + + + + + + connected + + + + + card + + + + diff --git a/plugins/netconnect/translations/bo_CN.qm b/plugins/netconnect/translations/bo_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..511873e26f9cf6e8dc99ebd62cfb2a8a320752c9 GIT binary patch literal 1089 zcma)5O>5Lp6n*{fG#xK~fnpa=Ea+0)34)VYXQPxU*0Hq;lO`{1oG}@aHzN!#{Q)v4 zR1`!6H?Hc+jam>v1QAql^(( zrt##}cS{IS6O&tagcv;{ro7kKw? z7`ZX~hZcceR0iDDm({<$)KT__Z(qYt`!dVGth%6n9B$OwScrS&irMm^V zhza^kXfZ{F1!drSO}A?Yj&fzJwDyCIIDwx5_PH z;z-Ij$YHkCwB$9kV{kGkafP$0&|*=hWo|K)N^hztP+GdG>pM!?UAyJm>n&9z>lCQ| zuhRp`^&DB5J1SA=t+c0q7k#1t-J@qHzQ@I^P>rXY6)?+~Y2%6n@8KaYaBp-@%(!Dm zZc)NK8eAV@9C)S2&RWjFl$^oLR3X*@)YC`H4LER{$C>ZPc-U4!k%S6eN0|*QgG`>A z!&BY$*Hv~@V(c~CCPsGXF~eJkyqvuKoo2_E(5R!ZB^?!L6%{cqi;iew`9jja&<(1j mK0nWHGH3yN;=n3a_OoR}I#!?pZi|~bY|EP}j_r*hv;6@9Z0S<~ literal 0 HcmV?d00001 diff --git a/plugins/netconnect/translations/bo_CN.ts b/plugins/netconnect/translations/bo_CN.ts new file mode 100644 index 00000000..2f426330 --- /dev/null +++ b/plugins/netconnect/translations/bo_CN.ts @@ -0,0 +1,66 @@ + + + + + AddNetBtn + + + Add WiredNetork + སྐུད་ཡོད་བརྙན་འཕྲིན་ཁ་སྣོན་བྱས་ཡོད། + + + + NetConnect + + + + Wired Network + སྐུད་ཡོད་བརྙན་འཕྲིན་དྲ་བ། + + + + + open + སྒོ་ཕྱེ་བ། + /netconnect/open + + + + + Advanced settings + སྔོན་ཐོན་གྱི་སྒྲིག་བཀོད། + /netconnect/Advanced settings" + + + + ukui control center + ཝུའུ་ཁི་ལན་གྱི་ཚོད་འཛིན་ལྟེ་གནས། + + + + ukui control center desktop message + ukui ཚོད་འཛིན་ལྟེ་གནས་ཀྱི་ཅོག་ངོས་ཆ་འཕྲིན། + + + + WiredConnect + སྐུད་ཡོད་སྦྲེལ་མཐུད། + + + + No ethernet device avaliable + ཨེ་ཙི་དྲ་རྒྱའི་སྒྲིག་ཆས་ལ་བཙན་འཛུལ་བྱས་མི་ཆོག། + + + + + connected + འབྲེལ་མཐུད་བྱེད་པ། + + + + card + བྱང་བུ། + + + diff --git a/plugins/netconnect/translations/tr.qm b/plugins/netconnect/translations/tr.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/netconnect/translations/tr.qm @@ -0,0 +1 @@ + + + + + AddNetBtn + + + Add WiredNetork + + + + + NetConnect + + + + Wired Network + + + + + + open + + /netconnect/open + + + + + Advanced settings + + /netconnect/Advanced settings" + + + + ukui control center + + + + + ukui control center desktop message + + + + + WiredConnect + + + + + No ethernet device avaliable + + + + + + connected + + + + + card + + + + diff --git a/plugins/netconnect/translations/zh_CN.qm b/plugins/netconnect/translations/zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..97f6e862995e743ad2b1ba56123b764c201bb308 GIT binary patch literal 661 zcmcE7ks@*G{hX<16=n7(EZlq7iGhJ3fPrmB3j+hAG6Q?sJ|JDeWLYc^d6o!l9zz;^LdXRPyzBk@C*H%4Wt<|85o$fnSl(R z+}}Y9(mCt)*9X?!;Q&do0WrU0N{T{wW>IR2UusEyQ8qhJj1wpZ*wdUS4W)30R*%x>m-4T<;(Qkfq)G zBH7{kW&H9LQcE&Yi}F%S6jD;lGLusk63Y^EG82<>Qn4Auf#Ggmu$vWtR+d9ujcz@r z9v-kBs1vbS!%`m@oCtR%OLAgS3N~eIv7h?yB`<|5S1MeZU7D!?G`plIKSv=sHLoPK2%Am;n9dBJ=}8l$%AdkbP{v{c VFuaSiOY#d8a#M?o6Vow*8vyRAteOA- literal 0 HcmV?d00001 diff --git a/plugins/netconnect/translations/zh_CN.ts b/plugins/netconnect/translations/zh_CN.ts new file mode 100644 index 00000000..0424b7b0 --- /dev/null +++ b/plugins/netconnect/translations/zh_CN.ts @@ -0,0 +1,66 @@ + + + + + AddNetBtn + + + Add WiredNetork + 添加有线网络 + + + + NetConnect + + + + Wired Network + 有线网络 + + + + + open + 开启 + /netconnect/open + + + + + Advanced settings + 高级设置 + /netconnect/Advanced settings" + + + + ukui control center + 控制面板 + + + + ukui control center desktop message + 控制面板桌面通知 + + + + WiredConnect + 有线网络 + + + + No ethernet device avaliable + 未检测到有线设备 + + + + + connected + 已连接 + + + + card + 网卡 + + + diff --git a/plugins/plugin.pro b/plugins/plugin.pro new file mode 100644 index 00000000..cee11d57 --- /dev/null +++ b/plugins/plugin.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +SUBDIRS = \ + netconnect \ + wlanconnect \ + mobilehotspot \ + proxy diff --git a/plugins/proxy/applistwidget.cpp b/plugins/proxy/applistwidget.cpp new file mode 100644 index 00000000..c3c87109 --- /dev/null +++ b/plugins/proxy/applistwidget.cpp @@ -0,0 +1,138 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "applistwidget.h" +#include + +AppListWidget::AppListWidget(QString path, QWidget *parent) + : m_path(path), QWidget(parent) +{ + initUI(); + initDbus(); +} + +AppListWidget::~AppListWidget() +{ + +} + +/** + * @brief AppListWidget::setAppChecked + * @param flag 是否使用应用代理配置 + */ +void AppListWidget::setAppChecked(bool flag) +{ + m_checkBox->setChecked(flag); +} + +/** + * @brief AppListWidget::setAppIcon + * @param icon 应用图标的名称 + */ +void AppListWidget::setAppIcon(const QPixmap &icon) +{ + m_iconLabel->setAlignment(Qt::AlignCenter); + m_iconLabel->setPixmap(icon); +} + +/** + * @brief AppListWidget::setAppName + * @param text 应用名称 + */ +void AppListWidget::setAppName(const QString &text) +{ + m_nameLabel->setText(text); +} + +/** + * @brief AppListWidget::onAppCheckStateChanged + * checkBox是否选中 关联是否配置应用代理 + */ +void AppListWidget::onAppCheckStateChanged() +{ + if (m_checkBox->isChecked()) { + AddAppProxyConfig(); + } else { + RemoveAppProxyConfig(); + } +} + +/** + * @brief AppListWidget::AddAppProxyConfig + * 将该路径下的应用加入应用代理 + */ +void AppListWidget::AddAppProxyConfig() +{ + if(!m_dbusInterface->isValid()) { + qWarning ()<< "init AppProxy dbus error"; + } + + qDebug() << "call QDBusInterface addAppIntoProxy"; + m_dbusInterface->call("addAppIntoProxy", m_path); +} + +/** + * @brief AppListWidget::RemoveAppProxyConfig + * 将该路径下的应用移出应用代理 + */ +void AppListWidget::RemoveAppProxyConfig() +{ + if(!m_dbusInterface->isValid()) { + qWarning ()<< "init AppProxy dbus error"; + } + + qDebug() << "call QDBusInterface delAppIntoProxy"; + m_dbusInterface->call("delAppIntoProxy", m_path); +} + +void AppListWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + m_checkBox->setChecked(!m_checkBox->isChecked()); + onAppCheckStateChanged(); + } + return QWidget::mousePressEvent(event); +} + +void AppListWidget::initUI() +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setContentsMargins(17, 0, 17, 0); + mainLayout->setSpacing(8); + m_checkBox = new QCheckBox(this); + m_checkBox->setFixedSize(16, 16); + m_checkBox->setAttribute(Qt::WA_TransparentForMouseEvents, true); //m_checkBox不响应鼠标事件,将其传递给父窗口 + m_iconLabel = new QLabel(this); + m_iconLabel->setFixedSize(24, 24); + m_nameLabel = new QLabel(this); + + mainLayout->addWidget(m_checkBox); + mainLayout->addSpacing(8); + mainLayout->addWidget(m_iconLabel); + mainLayout->addWidget(m_nameLabel); + mainLayout->addStretch(); +} + +void AppListWidget::initDbus() +{ + m_dbusInterface = new QDBusInterface("org.ukui.SettingsDaemon", + "/org/ukui/SettingsDaemon/AppProxy", + "org.ukui.SettingsDaemon.AppProxy", + QDBusConnection::sessionBus()); +} diff --git a/plugins/proxy/applistwidget.h b/plugins/proxy/applistwidget.h new file mode 100644 index 00000000..7c94e128 --- /dev/null +++ b/plugins/proxy/applistwidget.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef APPLISTWIDGET_H +#define APPLISTWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class AppListWidget : public QWidget +{ + Q_OBJECT +public: + explicit AppListWidget(QString path, QWidget *parent = nullptr); + ~AppListWidget(); + + void setAppChecked(bool flag); + void setAppIcon(const QPixmap &icon); + void setAppName(const QString &text); + void onAppCheckStateChanged(); + void AddAppProxyConfig(); + void RemoveAppProxyConfig(); + +protected: + void mousePressEvent(QMouseEvent *event); + +private: + void initUI(); + void initDbus(); + + QCheckBox *m_checkBox = nullptr; + QLabel *m_iconLabel = nullptr; + QLabel *m_nameLabel = nullptr; + QString m_path = nullptr; + QDBusInterface *m_dbusInterface = nullptr; +}; + +#endif // APPLISTWIDGET_H diff --git a/plugins/proxy/aptinfo.h b/plugins/proxy/aptinfo.h new file mode 100644 index 00000000..6752eb8e --- /dev/null +++ b/plugins/proxy/aptinfo.h @@ -0,0 +1,32 @@ +#ifndef APTINFO_H +#define APTINFO_H +#include +#include +#include +#include + +struct AptInfo +{ + QString arg; + QDBusVariant out; +}; + +QDBusArgument &operator<<(QDBusArgument &argument, const AptInfo &mystruct) +{ + argument.beginStructure(); + argument << mystruct.arg << mystruct.out; + argument.endStructure(); + return argument; +} + +const QDBusArgument &operator>>(const QDBusArgument &argument, AptInfo &mystruct) +{ + argument.beginStructure(); + argument >> mystruct.arg >> mystruct.out; + argument.endStructure(); + return argument; +} + +Q_DECLARE_METATYPE(AptInfo) + +#endif // APTINFO_H diff --git a/plugins/proxy/aptproxydialog.cpp b/plugins/proxy/aptproxydialog.cpp new file mode 100644 index 00000000..2c1cc21a --- /dev/null +++ b/plugins/proxy/aptproxydialog.cpp @@ -0,0 +1,127 @@ +#include "aptproxydialog.h" +#include +#include +#include +#include +#include +#include "proxy.h" + +AptProxyDialog::AptProxyDialog(QWidget *parent ): + QDialog(parent) +{ + initUi(); + setupComponent(); + initConnect(); +} + +AptProxyDialog::~AptProxyDialog() +{ + +} + +void AptProxyDialog::initUi() +{ + setWindowTitle(tr("Set Apt Proxy")); + this->setFixedSize(480, 200); + + QVBoxLayout *mAptProxyLyt = new QVBoxLayout(this); + mAptProxyLyt->setContentsMargins(24, 24, 24, 24); + mAptProxyLyt->setSpacing(16); + + QFrame *mHostFrame = new QFrame(this); + mHostFrame->setFixedSize(432, 36); + mHostFrame->setFrameShape(QFrame::NoFrame); + + QHBoxLayout *mLyt_1= new QHBoxLayout(mHostFrame); + mLyt_1->setContentsMargins(0, 0, 0, 0); + mLyt_1->setSpacing(8); + + FixLabel *mSetHostLabel = new FixLabel(mHostFrame); + mSetHostLabel->setFixedSize(92, 36); + mSetHostLabel->setText(tr("Server Address")); + + mHostEdit = new QLineEdit(mHostFrame); + mHostEdit->setAttribute(Qt::WA_InputMethodEnabled, false); //限制中文输入法 + mHostEdit->setFixedSize(332, 36); + mHostEdit->installEventFilter(this); + + mLyt_1->addWidget(mSetHostLabel); + mLyt_1->addWidget(mHostEdit); + + QFrame *mPortFrame = new QFrame(this); + mPortFrame->setFixedSize(432, 36); + mPortFrame->setFrameShape(QFrame::NoFrame); + + QHBoxLayout *mLyt_2= new QHBoxLayout(mPortFrame); + mLyt_2->setContentsMargins(0, 0, 0, 0); + mLyt_2->setSpacing(8); + + QLabel *mSetPortLabel = new QLabel(tr("Port") ,mPortFrame); + mSetPortLabel->setFixedSize(92, 36); + + mPortEdit = new QLineEdit(mPortFrame); + mPortEdit->setAttribute(Qt::WA_InputMethodEnabled, false); //限制中文输入法 + mPortEdit->setFixedSize(332, 36); + mPortEdit->installEventFilter(this); + + mLyt_2->addWidget(mSetPortLabel); + mLyt_2->addWidget(mPortEdit); + + QFrame *mChooseFrame = new QFrame(this); + mChooseFrame->setFixedWidth(432); + mChooseFrame->setFrameShape(QFrame::NoFrame); + + QHBoxLayout *mLyt_3= new QHBoxLayout(mChooseFrame); + mLyt_3->setContentsMargins(0, 0, 0, 0); + mLyt_3->setSpacing(16); + + mCancelBtn = new QPushButton(mChooseFrame); + mCancelBtn->setMinimumWidth(96); + mCancelBtn->setText(tr("Cancel")); + + mConfirmBtn = new QPushButton(mChooseFrame); + mConfirmBtn->setMinimumWidth(96); + mConfirmBtn->setText(tr("Confirm")); + + mLyt_3->addStretch(); + mLyt_3->addWidget(mCancelBtn); + mLyt_3->addWidget(mConfirmBtn); + + mAptProxyLyt->addWidget(mHostFrame); + mAptProxyLyt->addWidget(mPortFrame); + mAptProxyLyt->addSpacing(16); + mAptProxyLyt->addWidget(mChooseFrame); +} + +void AptProxyDialog::initConnect() +{ + connect(mHostEdit, &QLineEdit::textEdited, this, [=]() { + if (mHostEdit->text().isEmpty()) { + mConfirmBtn->setEnabled(false); + } else { + mConfirmBtn->setEnabled(true); + } + }); + + connect(mCancelBtn, &QPushButton::clicked, this, [=]() { + this->close(); + }); + + connect(mConfirmBtn, &QPushButton::clicked, this, [=]() { + Proxy::setAptProxy(mHostEdit->text() , mPortEdit->text() , true); + this->close(); + }); +} + +void AptProxyDialog::setupComponent() +{ + QString host = Proxy::getAptProxy()["ip"].toString(); + QString port = Proxy::getAptProxy()["port"].toString();; + + mHostEdit->setText(host); + mPortEdit->setText(port); + + if (host.isEmpty()) { + mConfirmBtn->setEnabled(false); + } +} diff --git a/plugins/proxy/aptproxydialog.h b/plugins/proxy/aptproxydialog.h new file mode 100644 index 00000000..ab677ebb --- /dev/null +++ b/plugins/proxy/aptproxydialog.h @@ -0,0 +1,38 @@ +#ifndef APTPROXYDIALOG_H +#define APTPROXYDIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include "fixlabel.h" + +#define APT_PROXY_SCHEMA "org.ukui.control-center.apt.proxy" +#define APT_PROXY_ENABLED "enabled" +#define APT_PROXY_HOST_KEY "host" +#define APT_PROXY_PORT_KEY "port" + +class AptProxyDialog : public QDialog +{ + Q_OBJECT +public: + AptProxyDialog(QWidget *parent = nullptr); + ~AptProxyDialog(); + + void initUi(); +private: + QLineEdit *mHostEdit; + QLineEdit *mPortEdit; + + QPushButton *mCancelBtn; + QPushButton *mConfirmBtn; + +private: + void initConnect(); + void setupComponent(); +}; + +#endif // APTPROXYDIALOG_H diff --git a/plugins/proxy/certificationdialog.h b/plugins/proxy/certificationdialog.h new file mode 100644 index 00000000..3cffb5ef --- /dev/null +++ b/plugins/proxy/certificationdialog.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CERTIFICATIONDIALOG_H +#define CERTIFICATIONDIALOG_H + +#include + +#define HTTP_PROXY_SCHEMA "org.gnome.system.proxy.http" +#define HTTP_AUTH_KEY "use-authentication" +#define HTTP_AUTH_USER_KEY "authentication-user" +#define HTTP_AUTH_PASSWD_KEY "authentication-password" + + +#endif // CERTIFICATIONDIALOG_H diff --git a/plugins/proxy/certificationdialog.ui b/plugins/proxy/certificationdialog.ui new file mode 100644 index 00000000..72ca56aa --- /dev/null +++ b/plugins/proxy/certificationdialog.ui @@ -0,0 +1,342 @@ + + + CertificationDialog + + + + 0 + 0 + 500 + 246 + + + + + 500 + 246 + + + + + 500 + 246 + + + + UserCertification + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 20 + + + 25 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + 10 + + + 20 + + + + + + 0 + 0 + + + + UserCertification + + + true + + + + + + + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 60 + 20 + + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + User: + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 60 + 20 + + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + + 60 + 16777215 + + + + Passwd: + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 80 + + + + + + + + + + + diff --git a/plugins/proxy/proxy.cpp b/plugins/proxy/proxy.cpp new file mode 100644 index 00000000..0e89d9e5 --- /dev/null +++ b/plugins/proxy/proxy.cpp @@ -0,0 +1,1367 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "proxy.h" +#include "aptproxydialog.h" +#include "aptinfo.h" +//#include "utils.h" + +#include +#include +#include +#include + +#define PROXY_SCHEMA "org.gnome.system.proxy" +#define PROXY_MODE_KEY "mode" +#define PROXY_AUTOCONFIG_URL_KEY "autoconfig-url" +#define IGNORE_HOSTS_KEY "ignore-hosts" + +#define HTTP_PROXY_SCHEMA "org.gnome.system.proxy.http" +#define HTTP_USE_AUTH_KEY "use-authentication" +#define HTTP_AUTH_USER_KEY "authentication-user" +#define HTTP_AUTH_PASSWD_KEY "authentication-password" + +#define HTTPS_PROXY_SCHEMA "org.gnome.system.proxy.https" + +#define FTP_PROXY_SCHEMA "org.gnome.system.proxy.ftp" + +#define SOCKS_PROXY_SCHEMA "org.gnome.system.proxy.socks" + +#define PROXY_HOST_KEY "host" +#define PROXY_PORT_KEY "port" + +#define FRAME_LAYOUT_MARGINS 16,0,16,0 +#define FRAME_LAYOUT_SPACING 8 +#define LABEL_WIDTH 136 +#define LINE_EDIT_HEIGHT 36 + +Proxy::Proxy() : mFirstLoad(true) +{ + qDBusRegisterMetaType>(); + qDBusRegisterMetaType(); + + QTranslator* translator = new QTranslator(this); + translator->load("/usr/share/kylin-nm/proxy/" + QLocale::system().name()); + QApplication::installTranslator(translator); + + pluginName = tr("Proxy"); + pluginType = NETWORK; +} + +Proxy::~Proxy() +{ + if (!mFirstLoad) { + plugin_leave(); + } +} + +QString Proxy::plugini18nName() { + return pluginName; +} + +int Proxy::pluginTypes() { + return pluginType; +} + +QWidget *Proxy::pluginUi() { + if (mFirstLoad) { + mFirstLoad = false; + pluginWidget = new QWidget; + pluginWidget->setAttribute(Qt::WA_DeleteOnClose); + initUi(pluginWidget); + retranslateUi(); + + mfileWatch_1 = new QFileSystemWatcher(this); + mfileWatch_2 = new QFileSystemWatcher(this); + + QString dir_1("/etc/apt/apt.conf.d"); + QString dir_2("/etc/profile.d"); + mfileWatch_1->addPath(dir_1); + mfileWatch_2->addPath(dir_2); + + const QByteArray id(PROXY_SCHEMA); + const QByteArray idd(HTTP_PROXY_SCHEMA); + const QByteArray iddd(HTTPS_PROXY_SCHEMA); + const QByteArray iid(FTP_PROXY_SCHEMA); + const QByteArray iiid(SOCKS_PROXY_SCHEMA); + const QByteArray iVd(APT_PROXY_SCHEMA); + + initSearchText(); + setupComponent(); + + if (QGSettings::isSchemaInstalled(id) && QGSettings::isSchemaInstalled(idd) && + QGSettings::isSchemaInstalled(iddd) && QGSettings::isSchemaInstalled(iid) && + QGSettings::isSchemaInstalled(iiid) && QGSettings::isSchemaInstalled(iVd)){ + + isExistSettings = true; + proxysettings = new QGSettings(id,QByteArray(),this); + httpsettings = new QGSettings(idd,QByteArray(),this); + securesettings = new QGSettings(iddd,QByteArray(),this); + ftpsettings = new QGSettings(iid,QByteArray(),this); + sockssettings = new QGSettings(iiid,QByteArray(),this); + + setupConnect(); + initProxyModeStatus(); + initAutoProxyStatus(); + initManualProxyStatus(); + initIgnoreHostStatus(); + initDbus(); + initAppProxyStatus(); + } else { + qCritical() << "Xml needed by Proxy is not installed"; + } + } + return pluginWidget; +} + +void Proxy::plugin_leave() +{ + if (isExistSettings) { + if (proxysettings->get(PROXY_MODE_KEY) == "manual") { + if ((httpsettings->get(PROXY_HOST_KEY).toString().isEmpty() || httpsettings->get(PROXY_PORT_KEY).toInt() == 0) + && (securesettings->get(PROXY_HOST_KEY).toString().isEmpty() || securesettings->get(PROXY_PORT_KEY).toInt() == 0) + && (ftpsettings->get(PROXY_HOST_KEY).toString().isEmpty() || ftpsettings->get(PROXY_PORT_KEY).toInt() == 0) + && (sockssettings->get(PROXY_HOST_KEY).toString().isEmpty() || sockssettings->get(PROXY_PORT_KEY).toInt() == 0)) { + proxysettings->set(PROXY_MODE_KEY,"auto"); + mManualBtn->setChecked(false); + mAutoBtn->setChecked(true); + _setSensitivity(); + } + } + } +} + +const QString Proxy::name() const { + + return QStringLiteral("Proxy"); +} + +bool Proxy::isShowOnHomePage() const +{ + return true; +} + +QIcon Proxy::icon() const +{ + return QIcon::fromTheme("ukui-network-agent-symbolic"); +} + +bool Proxy::isEnable() const +{ + return true; +} + +void Proxy::initUi(QWidget *widget) +{ + QVBoxLayout *mverticalLayout = new QVBoxLayout(widget); + mverticalLayout->setSpacing(8); + mverticalLayout->setContentsMargins(0, 0, 0, 0); + + mProxyBtnGroup = new QButtonGroup(this); + mProxyBtnGroup->setExclusive (false); // 防止互斥 + + mTitleLabel = new TitleLabel(widget); + + mProxyFrame = new QFrame(widget); + mProxyFrame->setMinimumSize(QSize(550, 0)); + mProxyFrame->setMaximumSize(QSize(16777215, 16777215)); + mProxyFrame->setFrameShape(QFrame::Box); + QVBoxLayout *Lyt = new QVBoxLayout(mProxyFrame); + Lyt->setContentsMargins(0, 0, 0, 0); + Lyt->setSpacing(0); + + mEnableFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mEnableFrame); + + QHBoxLayout *enableLyt = new QHBoxLayout(mEnableFrame); + enableLyt->setContentsMargins(16, 0, 16, 0); + QLabel *enableLabel = new QLabel(tr("Start using"), mEnableFrame); + mEnableBtn = new KSwitchButton(mEnableFrame); + enableLyt->addWidget(enableLabel); + enableLyt->addStretch(); + enableLyt->addWidget(mEnableBtn); + + line_8 = setLine(mProxyFrame); + + mSelectFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mSelectFrame); + QHBoxLayout *selectLyt = new QHBoxLayout(mSelectFrame); + selectLyt->setContentsMargins(16, 0, 16, 0); + selectLyt->setSpacing(4); + QLabel *selectLabel = new QLabel(tr("Proxy mode"), mSelectFrame); + selectLabel->setFixedWidth(148); + mAutoBtn = new QRadioButton(mSelectFrame); + mProxyBtnGroup->addButton(mAutoBtn); + QLabel *autoLabel = new QLabel(tr("Auto"), mSelectFrame); + mManualBtn = new QRadioButton(mSelectFrame); + mProxyBtnGroup->addButton(mManualBtn); + QLabel *manualLabel = new QLabel(tr("Manual"), mSelectFrame); + selectLyt->addWidget(selectLabel); + selectLyt->addWidget(mAutoBtn); + selectLyt->addWidget(autoLabel); + selectLyt->addSpacing(100); + selectLyt->addWidget(mManualBtn); + selectLyt->addWidget(manualLabel); + selectLyt->addStretch(); + + line_1 = setLine(mProxyFrame); + + mUrlFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mUrlFrame); + + QHBoxLayout *mUrlLayout = new QHBoxLayout(mUrlFrame); + mUrlLayout->setContentsMargins(16, 0, 16, 0); + mUrlLayout->setSpacing(8); + + mUrlLabel = new QLabel(mUrlFrame); + mUrlLabel->setFixedWidth(136); + + mUrlLineEdit = new QLineEdit(mUrlFrame); + mUrlLineEdit->setFixedHeight(36); + + mUrlLayout->addWidget(mUrlLabel); + mUrlLayout->addWidget(mUrlLineEdit); + + line_2 = setLine(mProxyFrame); + + + mHTTPFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mHTTPFrame); + + QHBoxLayout *mHTTPLayout_1 = new QHBoxLayout(mHTTPFrame); + mHTTPLayout_1->setSpacing(8); + mHTTPLayout_1->setContentsMargins(16, 0, 16, 0); + mHTTPLabel = new QLabel(mHTTPFrame); + mHTTPLabel->setFixedWidth(136); + mHTTPPortLabel = new QLabel(mHTTPFrame); + mHTTPPortLabel->setFixedWidth(100); + mHTTPPortLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + mHTTPLineEdit_1 = new QLineEdit(mHTTPFrame); + mHTTPLineEdit_1->resize(300, 36); + mHTTPLineEdit_2 = new QLineEdit(mHTTPFrame); + mHTTPLineEdit_2->setFixedHeight(36); + mHTTPLineEdit_2->setValidator(new QRegExpValidator(QRegExp("[0-9]*") , this)); + mHTTPLayout_1->addWidget(mHTTPLabel); + mHTTPLayout_1->addWidget(mHTTPLineEdit_1); + mHTTPLayout_1->addWidget(mHTTPPortLabel); + mHTTPLayout_1->addWidget(mHTTPLineEdit_2); + + line_3 = setLine(mProxyFrame); + + mHTTPSFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mHTTPSFrame); + + QHBoxLayout *mHTTPSLayout = new QHBoxLayout(mHTTPSFrame); + mHTTPSLayout->setSpacing(8); + mHTTPSLayout->setContentsMargins(16, 0, 16, 0); + mHTTPSLabel = new QLabel(mHTTPSFrame); + mHTTPSLabel->setFixedWidth(136); + mHTTPSPortLabel = new QLabel(mHTTPSFrame); + mHTTPSPortLabel->setFixedWidth(100); + mHTTPSPortLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + mHTTPSLineEdit_1 = new QLineEdit(mHTTPSFrame); + mHTTPSLineEdit_1->resize(300, 36); + mHTTPSLineEdit_2 = new QLineEdit(mHTTPSFrame); + mHTTPSLineEdit_2->setFixedHeight(36); + mHTTPSLineEdit_2->setValidator(new QRegExpValidator(QRegExp("[0-9]*") , this)); + mHTTPSLayout->addWidget(mHTTPSLabel); + mHTTPSLayout->addWidget(mHTTPSLineEdit_1); + mHTTPSLayout->addWidget(mHTTPSPortLabel); + mHTTPSLayout->addWidget(mHTTPSLineEdit_2); + + line_4 = setLine(mProxyFrame); + + mFTPFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mFTPFrame); + + QHBoxLayout *mFTPLayout = new QHBoxLayout(mFTPFrame); + mFTPLayout->setSpacing(8); + mFTPLayout->setContentsMargins(16, 0, 16, 0); + mFTPLabel = new QLabel(mFTPFrame); + mFTPLabel->setFixedWidth(136); + mFTPPortLabel = new QLabel(mFTPFrame); + mFTPPortLabel->setFixedWidth(100); + mFTPPortLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + mFTPLineEdit_1 = new QLineEdit(mFTPFrame); + mFTPLineEdit_1->resize(300, 36); + mFTPLineEdit_2 = new QLineEdit(mFTPFrame); + mFTPLineEdit_2->setFixedHeight(36); + mFTPLineEdit_2->setValidator(new QRegExpValidator(QRegExp("[0-9]*") , this)); + mFTPLayout->addWidget(mFTPLabel); + mFTPLayout->addWidget(mFTPLineEdit_1); + mFTPLayout->addWidget(mFTPPortLabel); + mFTPLayout->addWidget(mFTPLineEdit_2); + + line_5 = setLine(mProxyFrame); + + mSOCKSFrame = new QFrame(mProxyFrame); + setFrame_Noframe(mSOCKSFrame); + + QHBoxLayout *mSOCKSLayout = new QHBoxLayout(mSOCKSFrame); + mSOCKSLayout->setSpacing(8); + mSOCKSLayout->setContentsMargins(16, 0, 16, 0); + mSOCKSLabel = new QLabel(mSOCKSFrame); + mSOCKSLabel->setFixedWidth(136); + mSOCKSPortLabel = new QLabel(mSOCKSFrame); + mSOCKSPortLabel->setFixedWidth(100); + mSOCKSPortLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + mSOCKSLineEdit_1 = new QLineEdit(mSOCKSFrame); + mSOCKSLineEdit_1->resize(300, 36); + mSOCKSLineEdit_2 = new QLineEdit(mSOCKSFrame); + mSOCKSLineEdit_2->setFixedHeight(36); + mSOCKSLineEdit_2->setValidator(new QRegExpValidator(QRegExp("[0-9]*") , this)); + mSOCKSLayout->addWidget(mSOCKSLabel); + mSOCKSLayout->addWidget(mSOCKSLineEdit_1); + mSOCKSLayout->addWidget(mSOCKSPortLabel); + mSOCKSLayout->addWidget(mSOCKSLineEdit_2); + + line_6 = setLine(mProxyFrame); + + mIgnoreFrame = new QFrame(mProxyFrame); + mIgnoreFrame->setMinimumSize(QSize(550, 0)); + mIgnoreFrame->setMaximumSize(QSize(16777215, 16777215)); + mIgnoreFrame->setFrameShape(QFrame::NoFrame); + QVBoxLayout *mIgnoreLayout = new QVBoxLayout(mIgnoreFrame); + mIgnoreLayout->setSpacing(10); + mIgnoreLayout->setContentsMargins(16, 0, 16, 24); + mIgnoreLabel = new QLabel(mIgnoreFrame); + mIgnoreLabel->setFixedHeight(36); + mIgnoreLineEdit = new QTextEdit(mIgnoreFrame); + mIgnoreLineEdit->setFixedHeight(120); + mIgnoreLineEdit->setStyleSheet("border-radius:6px;background-color: palette(button)"); + mIgnoreLayout->addWidget(mIgnoreLabel); + mIgnoreLayout->addWidget(mIgnoreLineEdit); + + Lyt->addWidget(mEnableFrame); + Lyt->addWidget(line_8); + Lyt->addWidget(mSelectFrame); + Lyt->addWidget(line_1); + Lyt->addWidget(mUrlFrame); + Lyt->addWidget(line_2); + Lyt->addWidget(mHTTPFrame); + Lyt->addWidget(line_3); + Lyt->addWidget(mHTTPSFrame); + Lyt->addWidget(line_4); + Lyt->addWidget(mFTPFrame); + Lyt->addWidget(line_5); + Lyt->addWidget(mSOCKSFrame); + Lyt->addWidget(line_6); + Lyt->addWidget(mIgnoreFrame); + + //应用代理模块 + m_appProxyLabel = new TitleLabel(widget); + m_appProxyLabel->setText(tr("Application Proxy")); //应用代理 + setAppProxyFrameUi(widget); + setAppListFrameUi(widget); + + //APT代理模块 + mAptProxyLabel = new TitleLabel(widget); + mAPTFrame = new QFrame(widget); + mAPTFrame->setMinimumSize(QSize(550, 0)); + mAPTFrame->setMaximumSize(QSize(16777215, 16777215)); + mAPTFrame->setFrameShape(QFrame::Box); + + QVBoxLayout *AptLayout = new QVBoxLayout(mAPTFrame); + AptLayout->setContentsMargins(0, 0, 0, 0); + AptLayout->setSpacing(0); + + mAPTFrame_1 = new QFrame(mAPTFrame); + setFrame_Noframe(mAPTFrame_1); + + QHBoxLayout *mAptLayout_1 = new QHBoxLayout(mAPTFrame_1); + mAptLayout_1->setContentsMargins(16, 0, 16, 0); + mAptLayout_1->setSpacing(8); + + mAptLabel = new QLabel(mAPTFrame_1); + mAptLabel->setFixedWidth(200); + mAptBtn = new KSwitchButton(mAPTFrame_1); + mAptLayout_1->addWidget(mAptLabel); + mAptLayout_1->addStretch(); + mAptLayout_1->addWidget(mAptBtn); + + mAPTFrame_2 = new QFrame(mAPTFrame); + setFrame_Noframe(mAPTFrame_2); + + QHBoxLayout *mAptLayout_2 = new QHBoxLayout(mAPTFrame_2); + mAptLayout_2->setContentsMargins(16, 0, 16, 0); + mAptLayout_2->setSpacing(8); + + mAPTHostLabel_1 = new QLabel(mAPTFrame_2); + mAPTHostLabel_2 = new QLabel(mAPTFrame_2); + mAPTPortLabel_1 = new QLabel(mAPTFrame_2); + mAPTPortLabel_2 = new QLabel(mAPTFrame_2); + mEditBtn = new QPushButton(mAPTFrame_2); + mEditBtn->setFixedWidth(80); + mAptLayout_2->addWidget(mAPTHostLabel_1); + mAptLayout_2->addWidget(mAPTHostLabel_2); + mAptLayout_2->addSpacing(100); + mAptLayout_2->addWidget(mAPTPortLabel_1); + mAptLayout_2->addWidget(mAPTPortLabel_2); + mAptLayout_2->addStretch(); + mAptLayout_2->addWidget(mEditBtn,Qt::AlignRight); + + line_7 = setLine(mAPTFrame); + + AptLayout->addWidget(mAPTFrame_1); + AptLayout->addWidget(line_7); + AptLayout->addWidget(mAPTFrame_2); + + mverticalLayout->addWidget(mTitleLabel); + mverticalLayout->addWidget(mProxyFrame); + mverticalLayout->addSpacing(32); + mverticalLayout->addWidget(m_appProxyLabel); + mverticalLayout->addWidget(m_appProxyFrame); + mverticalLayout->addSpacing(4); + mverticalLayout->addWidget(m_appListFrame); + mverticalLayout->addSpacing(32); + mverticalLayout->addWidget(mAptProxyLabel); + mverticalLayout->addWidget(mAPTFrame); + mverticalLayout->addStretch(); +} + +void Proxy::initSearchText() { + +} + +void Proxy::retranslateUi() +{ + mTitleLabel->setText(tr("System Proxy")); + //~ contents_path /Proxy/Auto url + mUrlLabel->setText(tr("Auto url")); + //~ contents_path /Proxy/Http Proxy + mHTTPLabel->setText(tr("Http Proxy")); + //~ contents_path /Proxy/Https Proxy + mHTTPSLabel->setText(tr("Https Proxy")); + //~ contents_path /Proxy/Ftp Proxy + mFTPLabel->setText(tr("Ftp Proxy")); + //~ contents_path /Proxy/Socks Proxy + mSOCKSLabel->setText(tr("Socks Proxy")); + mHTTPPortLabel->setText(tr("Port")); + mHTTPSPortLabel->setText(tr("Port")); + mFTPPortLabel->setText(tr("Port")); + mSOCKSPortLabel->setText(tr("Port")); + mIgnoreLabel->setText(tr("List of ignored hosts. more than one entry, please separate with english semicolon(;)")); + + //~ contents_path /Proxy/Apt Proxy + mAptProxyLabel->setText(tr("Apt Proxy")); + mAptLabel->setText(tr("Open")); + mAPTHostLabel_1->setText(tr("Server Address : ")); + mAPTPortLabel_1->setText(tr("Port : ")); + mEditBtn->setText(tr("Edit")); +} + +void Proxy::setupComponent(){ + //QLineEdit 设置数据 + GSData httpHostData; + httpHostData.schema = HTTP_PROXY_SCHEMA; + httpHostData.key = PROXY_HOST_KEY; + mHTTPLineEdit_1->setProperty("gData", QVariant::fromValue(httpHostData)); + + GSData httpsHostData; + httpsHostData.schema = HTTPS_PROXY_SCHEMA; + httpsHostData.key = PROXY_HOST_KEY; + mHTTPSLineEdit_1->setProperty("gData", QVariant::fromValue(httpsHostData)); + + GSData ftpHostData; + ftpHostData.schema = FTP_PROXY_SCHEMA; + ftpHostData.key = PROXY_HOST_KEY; + mFTPLineEdit_1->setProperty("gData", QVariant::fromValue(ftpHostData)); + + GSData socksHostData; + socksHostData.schema = SOCKS_PROXY_SCHEMA; + socksHostData.key = PROXY_HOST_KEY; + mSOCKSLineEdit_1->setProperty("gData", QVariant::fromValue(socksHostData)); + + GSData httpPortData; + httpPortData.schema = HTTP_PROXY_SCHEMA; + httpPortData.key = PROXY_PORT_KEY; + mHTTPLineEdit_2->setProperty("gData", QVariant::fromValue(httpPortData)); + + GSData httpsPortData; + httpsPortData.schema = HTTPS_PROXY_SCHEMA; + httpsPortData.key = PROXY_PORT_KEY; + mHTTPSLineEdit_2->setProperty("gData", QVariant::fromValue(httpsPortData)); + + GSData ftpPortData; + ftpPortData.schema = FTP_PROXY_SCHEMA; + ftpPortData.key = PROXY_PORT_KEY; + mFTPLineEdit_2->setProperty("gData", QVariant::fromValue(ftpPortData)); + + GSData socksPortData; + socksPortData.schema = SOCKS_PROXY_SCHEMA; + socksPortData.key = PROXY_PORT_KEY; + mSOCKSLineEdit_2->setProperty("gData", QVariant::fromValue(socksPortData)); +} + +void Proxy::setupConnect(){ + connect(mEnableBtn, &KSwitchButton::stateChanged, this ,[=](bool checked) { + mSelectFrame->setVisible(checked); + line_8->setVisible(checked); + mAutoBtn->setChecked(checked); + mManualBtn->setChecked(false); + qDebug()<isChecked(); + proxysettings->set(PROXY_MODE_KEY, checked ? "auto" : "none"); + _setSensitivity(); + }); + + connect(mEditBtn ,&QPushButton::clicked, this, &Proxy::setAptProxySlot); + + connect(mProxyBtnGroup, QOverload::of(&QButtonGroup::buttonClicked), [=](QAbstractButton * eBtn){ + if (eBtn == mAutoBtn) { + mManualBtn->setChecked(false); + proxysettings->set(PROXY_MODE_KEY,"auto"); + } else if (eBtn == mManualBtn){ + mAutoBtn->setChecked(false); + proxysettings->set(PROXY_MODE_KEY,"manual"); + } + _setSensitivity(); + }); + + connect(mUrlLineEdit, &QLineEdit::textChanged, this, [=](const QString &txt){proxysettings->set(PROXY_AUTOCONFIG_URL_KEY, QVariant(txt));}); + + connect(mHTTPLineEdit_1, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mHTTPSLineEdit_1, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mFTPLineEdit_1, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mSOCKSLineEdit_1, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mHTTPLineEdit_2, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mHTTPSLineEdit_2, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mFTPLineEdit_2, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + connect(mSOCKSLineEdit_2, &QLineEdit::textChanged, this, [=](const QString &txt){manualProxyTextChanged(txt);}); + + connect(mIgnoreLineEdit, &QTextEdit::textChanged, this, [=](){ + QString text = mIgnoreLineEdit->toPlainText(); + QStringList hostStringList = text.split(";"); + proxysettings->set(IGNORE_HOSTS_KEY, QVariant(hostStringList)); + }); + + connect(mAptBtn , &KSwitchButton::stateChanged, this ,[=](bool checked){ + if (checked) { + emit mEditBtn->click(); + } else { // 关闭APT代理,删除对应的配置文件 + if (QString(qgetenv("http_proxy").data()).isEmpty()) { + line_7->hide(); + mAPTFrame_2->hide(); + setAptProxy("" ,0 ,false); + } else { + QMessageBox *mReboot = new QMessageBox(pluginWidget->topLevelWidget()); + mReboot->setIcon(QMessageBox::Warning); + mReboot->setText(tr("The apt proxy has been turned off and needs to be restarted to take effect")); + QPushButton *laterbtn = mReboot->addButton(tr("Reboot Later"), QMessageBox::RejectRole); + QPushButton *nowbtn = mReboot->addButton(tr("Reboot Now"), QMessageBox::AcceptRole); + mReboot->exec(); + if (mReboot->clickedButton() == nowbtn) { //选择了立即重启,一秒后系统会重启 + line_7->hide(); + mAPTFrame_2->hide(); + setAptProxy("" ,0 ,false); + sleep(1); + reboot(); + } else { //选择了稍后重启,删掉对应文件,但删不了已生效的环境变量 + line_7->hide(); + mAPTFrame_2->hide(); + setAptProxy("" ,0 ,false); + } + } + } + }); +} + +void Proxy::initProxyModeStatus(){ + int mode = _getCurrentProxyMode(); + QHash mAptinfo = getAptProxy(); + + mAutoBtn->blockSignals(true); + mManualBtn->blockSignals(true); + mAptBtn->blockSignals(true); + mEnableBtn->blockSignals(true); + + if (mode == AUTO){ + mEnableBtn->setChecked(true); + mAutoBtn->setChecked(true); + } else if (mode == MANUAL){ + mEnableBtn->setChecked(true); + mManualBtn->setChecked(true); + } else{ + mEnableBtn->setChecked(false); + mAutoBtn->setChecked(false); + mManualBtn->setChecked(false); + mSelectFrame->setVisible(false); + line_8->setVisible(false); + } + + if (QFile::exists("/etc/apt/ota_version")) { + mAPTFrame->hide(); + mAptProxyLabel->hide(); + } else { + if (mAptinfo["open"].toBool()) { + mAptBtn->setChecked(true); + mAPTHostLabel_2->setText(mAptinfo["ip"].toString()); + mAPTPortLabel_2->setText(mAptinfo["port"].toString()); + } else { + mAptBtn->setChecked(false); + line_7->setVisible(false); + mAPTFrame_2->setVisible(false); + } + } + + + mAutoBtn->blockSignals(false); + mManualBtn->blockSignals(false); + mAptBtn->blockSignals(false); + mEnableBtn->blockSignals(false); + + _setSensitivity(); +} + +void Proxy::initAutoProxyStatus(){ + + mUrlLineEdit->blockSignals(true); + //设置当前url + QString urlString = proxysettings->get(PROXY_AUTOCONFIG_URL_KEY).toString(); + mUrlLineEdit->setText(urlString); + + mUrlLineEdit->blockSignals(false); +} + +void Proxy::initManualProxyStatus(){ + //信号阻塞 + mHTTPLineEdit_1->blockSignals(true); + mHTTPSLineEdit_1->blockSignals(true); + mFTPLineEdit_1->blockSignals(true); + mSOCKSLineEdit_1->blockSignals(true); + + mHTTPLineEdit_2->blockSignals(true); + mHTTPSLineEdit_2->blockSignals(true); + mFTPLineEdit_2->blockSignals(true); + mSOCKSLineEdit_2->blockSignals(true); + + //HTTP + QString httphost = httpsettings->get(PROXY_HOST_KEY).toString(); + mHTTPLineEdit_1->setText(httphost); + int httpport = httpsettings->get(PROXY_PORT_KEY).toInt(); + mHTTPLineEdit_2->setText(QString::number(httpport)); + + //HTTPS + QString httpshost = securesettings->get(PROXY_HOST_KEY).toString(); + mHTTPSLineEdit_1->setText(httpshost); + int httpsport = securesettings->get(PROXY_PORT_KEY).toInt(); + mHTTPSLineEdit_2->setText(QString::number(httpsport)); + + //FTP + QString ftphost = ftpsettings->get(PROXY_HOST_KEY).toString(); + mFTPLineEdit_1->setText(ftphost); + int ftppost = ftpsettings->get(PROXY_PORT_KEY).toInt(); + mFTPLineEdit_2->setText(QString::number(ftppost)); + + //SOCKS + QString sockshost = sockssettings->get(PROXY_HOST_KEY).toString(); + mSOCKSLineEdit_1->setText(sockshost); + int socksport = sockssettings->get(PROXY_PORT_KEY).toInt(); + mSOCKSLineEdit_2->setText(QString::number(socksport)); + + //解除信号阻塞 + mHTTPLineEdit_1->blockSignals(false); + mHTTPSLineEdit_1->blockSignals(false); + mFTPLineEdit_1->blockSignals(false); + mSOCKSLineEdit_1->blockSignals(false); + + mHTTPLineEdit_2->blockSignals(false); + mHTTPSLineEdit_2->blockSignals(false); + mFTPLineEdit_2->blockSignals(false); + mSOCKSLineEdit_2->blockSignals(false); +} + +void Proxy::initIgnoreHostStatus(){ + mIgnoreLineEdit->blockSignals(true); + + //设置当前ignore host + QStringList ignorehost = proxysettings->get(IGNORE_HOSTS_KEY).toStringList(); + mIgnoreLineEdit->setPlainText(ignorehost.join(";")); + + mIgnoreLineEdit->blockSignals(false); +} + +void Proxy::initDbus() +{ + m_appProxyDbus = new QDBusInterface("org.ukui.SettingsDaemon", + "/org/ukui/SettingsDaemon/AppProxy", + "org.ukui.SettingsDaemon.AppProxy", + QDBusConnection::sessionBus()); +} + +void Proxy::initAppProxyStatus() +{ + bool state = getAppProxyState(); + m_appEnableBtn->setChecked(state); + onappProxyEnableChanged(state); + + appProxyInfoPadding(); +// m_cancelBtn->setEnabled(false); +// m_saveBtn->setEnabled(false); + appListPadding(); +} + +int Proxy::_getCurrentProxyMode(){ + GSettings * proxygsettings; + proxygsettings = g_settings_new(PROXY_SCHEMA); + int mode = g_settings_get_enum(proxygsettings, PROXY_MODE_KEY); + g_object_unref(proxygsettings); + + return mode; +} + +void Proxy::_setSensitivity(){ + //自动配置代理界面敏感性 + bool autoChecked = mAutoBtn->isChecked(); + mUrlFrame->setVisible(autoChecked); + line_1->setVisible(autoChecked); + + + //手动配置代理界面敏感性 + bool manualChecked = mManualBtn->isChecked(); + mHTTPFrame->setVisible(manualChecked); + mHTTPSFrame->setVisible(manualChecked); + mFTPFrame->setVisible(manualChecked); + mSOCKSFrame->setVisible(manualChecked); + mIgnoreFrame->setVisible(manualChecked); + line_2->setVisible(manualChecked); + line_3->setVisible(manualChecked); + line_4->setVisible(manualChecked); + line_5->setVisible(manualChecked); + line_6->setVisible(manualChecked); +} + +void Proxy::setAptProxy(QString host, QString port, bool status) +{ + QDBusInterface *mAptproxyDbus = new QDBusInterface("com.control.center.qt.systemdbus", + "/", + "com.control.center.interface", + QDBusConnection::systemBus()); + if (mAptproxyDbus->isValid()) + QDBusReply reply = mAptproxyDbus->call("setaptproxy", host, port , status); +} + +QHash Proxy::getAptProxy() +{ + QHash mAptInfo; + QDBusInterface *mAptproxyDbus = new QDBusInterface("com.control.center.qt.systemdbus", + "/", + "com.control.center.interface", + QDBusConnection::systemBus()); + if (mAptproxyDbus->isValid()) { + QDBusMessage result = mAptproxyDbus->call("getaptproxy"); + + QList outArgs = result.arguments(); + QVariant first = outArgs.at(0); + QDBusArgument dbvFirst = first.value(); + QVariant vFirst = dbvFirst.asVariant(); + const QDBusArgument &dbusArgs = vFirst.value(); + + QVector aptinfo; + + dbusArgs.beginArray(); + while (!dbusArgs.atEnd()) { + AptInfo info; + dbusArgs >> info; + aptinfo.push_back(info); + } + dbusArgs.endArray(); + + for (AptInfo it : aptinfo) { + mAptInfo.insert(it.arg, it.out.variant()); + } + } + return mAptInfo; +} + +void Proxy::setAptInfo() +{ + QMessageBox *mReboot = new QMessageBox(pluginWidget->topLevelWidget()); + mReboot->setIcon(QMessageBox::Warning); + mReboot->setText(tr("The system needs to be restarted to set the Apt proxy, whether to reboot")); + QPushButton *laterbtn = mReboot->addButton(tr("Reboot Later"), QMessageBox::RejectRole); + QPushButton *nowbtn = mReboot->addButton(tr("Reboot Now"), QMessageBox::AcceptRole); + mReboot->exec(); + if (mReboot->clickedButton() == nowbtn) { //选择了立即重启,一秒后系统会重启 + sleep(1); + reboot(); + } else { //选择了稍后重启或点击了关闭按钮,配置文件已写入,但是/etc/profile.d目录下新增的脚本文件未执行 + line_7->show(); + mAPTFrame_2->show(); + mAPTHostLabel_2->setText(getAptProxy()["ip"].toString()); + mAPTPortLabel_2->setText(getAptProxy()["port"].toString()); + } +} + +void Proxy::reboot() +{ + QDBusInterface *rebootDbus = new QDBusInterface("org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + QDBusConnection::sessionBus()); + + rebootDbus->call("reboot"); + delete rebootDbus; + rebootDbus = nullptr; +} + +void Proxy::setFrame_Noframe(QFrame *frame) +{ + frame->setMinimumSize(QSize(550, 60)); + frame->setMaximumSize(QSize(16777215, 60)); + frame->setFrameShape(QFrame::NoFrame); +} + +QFrame *Proxy::setLine(QFrame *frame) +{ + QFrame *line = new QFrame(frame); + line->setMinimumSize(QSize(0, 1)); + line->setMaximumSize(QSize(16777215, 1)); + line->setLineWidth(0); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + return line; +} + +bool Proxy::getAppProxyState() +{ + bool state = true; + if(!m_appProxyDbus->isValid()) { + qWarning ()<< "init AppProxy dbus error"; + } + + //获取应用代理开启状态 + qDebug() << "call QDBusInterface getProxyStateDbus"; + QDBusReply reply = m_appProxyDbus->call("getProxyStateDbus"); + + if (!reply.isValid()) { + return false; + } + state = reply; + + return state; +} + +void Proxy::setAppProxyState(bool state) +{ + if(!m_appProxyDbus->isValid()) { + qWarning ()<< "init AppProxy dbus error"; + return; + } + + //设置应用代理开启状态 + qDebug() << "call QDBusInterface setProxyStateDbus" << state; + m_appProxyDbus->call("setProxyStateDbus", state); +} + +QStringList Proxy::getAppProxyConf() +{ + QStringList info; + info.clear(); + + QDBusInterface dbusInterface("org.ukui.SettingsDaemon", + "/org/ukui/SettingsDaemon/AppProxy", + "org.ukui.SettingsDaemon.AppProxy", + QDBusConnection::sessionBus()); + + if(!dbusInterface.isValid()) { + qWarning ()<< "init AppProxy dbus error"; + } + + //获取应用代理配置信息 + qDebug() << "call QDBusInterface getProxyConfig"; + QDBusReply reply = dbusInterface.call("getProxyConfig"); + + if (!reply.isValid()) { + qWarning ()<< "Return empty app proxy information, getProxyConfig reply is invalid"; + return info; + } + + info = reply.value(); + + if (info.isEmpty()) { + qWarning() << "getAppProxyConf reply is empty"; + } + + return info; +} + +void Proxy::setAppProxyConf(QStringList list) +{ + if (list.count() < 3) { + return; + } + + if(!m_appProxyDbus->isValid()) { + qWarning ()<< "init AppProxy dbus error"; + return; + } + + //写入应用代理配置信息 + qDebug() << "call QDBusInterface setProxyConfig"; + m_appProxyDbus->call("setProxyConfig", list); +} + +QMap Proxy::getAppListProxy() +{ + QMap appList; + appList.clear(); + + QDBusInterface dbusInterface("org.ukui.SettingsDaemon", + "/org/ukui/SettingsDaemon/AppProxy", + "org.ukui.SettingsDaemon.AppProxy", + QDBusConnection::sessionBus()); + + if(!dbusInterface.isValid()) { + qWarning ()<< "init AppProxy dbus error"; + return appList; + } + + //获取可以配置应用代理的应用信息 + qDebug() << "call QDBusInterface getAppProxy"; + QDBusReply> reply = dbusInterface.call("getAppProxy"); + + if (!reply.isValid()) { + qWarning ()<< "Return empty app list, getAppProxy reply is invalid"; + return appList; + } + + appList = reply.value(); + if (appList.isEmpty()) { + qWarning() << "getAppProxy reply appList is empty"; + } + + return appList; +} + +#if 0 +bool Proxy::checkIsChanged(QStringList info) +{ + bool isChanged = false; + info = getAppProxyConf(); + if (info.value(0) != m_proxyTypeComboBox->currentText() + || info.value(1) != m_ipAddressLineEdit->text() + || info.value(2) != m_portLineEdit->text() + || info.value(3) != m_userNameLineEdit->text() + || info.value(4) != m_pwdLineEdit->text()) { + + isChanged = true; //如果在代理界面相关信息已修改,则返回true + } + return isChanged; +} +#endif + +void Proxy::setAppProxyFrameUi(QWidget *widget) +{ + //应用代理模块 + m_appProxyFrame = new QFrame(widget); + m_appProxyFrame->setMinimumSize(QSize(550, 0)); + m_appProxyFrame->setMaximumSize(QSize(16777215, 16777215)); + m_appProxyFrame->setFrameShape(QFrame::Box); + + QVBoxLayout *appProxyLayout = new QVBoxLayout(m_appProxyFrame); + appProxyLayout->setContentsMargins(0, 0, 0, 0); + appProxyLayout->setSpacing(0); + + //开启ui布局 + m_appEnableFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_appEnableFrame); + m_appEnableLabel = new QLabel(tr("Open"), m_appEnableFrame); + m_appEnableBtn = new KSwitchButton(m_appEnableFrame); + m_appEnableBtn->setCheckable(true); + QHBoxLayout *appEnableLayout = new QHBoxLayout(m_appEnableFrame); + appEnableLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + appEnableLayout->addWidget(m_appEnableLabel); + appEnableLayout->addStretch(); + appEnableLayout->addWidget(m_appEnableBtn); + + //代理类型ui布局 + m_proxyTypeFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_proxyTypeFrame); + m_proxyTypeLabel = new QLabel(tr("Proxy type"), m_proxyTypeFrame); + m_proxyTypeLabel->setFixedWidth(LABEL_WIDTH); + m_proxyTypeComboBox = new QComboBox(m_proxyTypeFrame); + QHBoxLayout *proxyTypeLayout = new QHBoxLayout(m_proxyTypeFrame); + proxyTypeLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + proxyTypeLayout->setSpacing(FRAME_LAYOUT_SPACING); + proxyTypeLayout->addWidget(m_proxyTypeLabel); + proxyTypeLayout->addWidget(m_proxyTypeComboBox); + m_proxyTypeComboBox->addItem("http"); //http + m_proxyTypeComboBox->addItem("socks4"); //socks4 + m_proxyTypeComboBox->addItem("socks5"); //socks4 + + //IP地址ui布局 + m_ipAddressFrame = new QFrame(m_appProxyFrame); + m_ipAddressFrame->setMinimumSize(QSize(550, 60)); + m_ipAddressFrame->setMaximumSize(QSize(16777215, 88)); + m_ipAddressFrame->setFrameShape(QFrame::NoFrame); + m_ipAddressLabel = new QLabel(tr("IP address"), m_ipAddressFrame); + m_ipAddressLabel->setFixedWidth(LABEL_WIDTH); + m_ipHintsLabel = new QLabel(m_ipAddressFrame); + m_ipHintsLabel->setContentsMargins(8, 0, 0, 0); + m_ipAddressLineEdit = new QLineEdit(m_ipAddressFrame); + m_ipAddressLineEdit->setFixedHeight(LINE_EDIT_HEIGHT); + m_ipAddressLineEdit->setPlaceholderText(tr("Required")); //必填 + + QWidget *ipInputWidget = new QWidget(m_ipAddressFrame); + QVBoxLayout *ipVLayout = new QVBoxLayout(ipInputWidget); + ipVLayout->setContentsMargins(0, 0, 0, 0); + ipVLayout->setSpacing(3); + ipVLayout->addWidget(m_ipAddressLineEdit); + ipVLayout->addWidget(m_ipHintsLabel); + + QFormLayout *ipAddressLayout = new QFormLayout(m_ipAddressFrame); + ipAddressLayout->setContentsMargins(16, 12, 16, 12); + ipAddressLayout->setSpacing(FRAME_LAYOUT_SPACING); + ipAddressLayout->addRow(m_ipAddressLabel, ipInputWidget); + + // IP的正则格式限制 + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + m_ipAddressLineEdit->setValidator(new QRegExpValidator(rx, this)); + //无效的IP地址提示 + QPalette hintTextColor; + hintTextColor.setColor(QPalette::WindowText, Qt::red); + m_ipHintsLabel->setPalette(hintTextColor); + m_ipHintsLabel->setText(tr("Invalid IP Address")); + m_ipHintsLabel->hide(); + + + //端口ui布局 + m_portFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_portFrame); + m_portLabel = new QLabel(tr("Port"), m_portFrame); + m_portLabel->setFixedWidth(LABEL_WIDTH); + m_portLineEdit = new QLineEdit(m_portFrame); + m_portLineEdit->setPlaceholderText(tr("Required")); //必填 + m_portLineEdit->setValidator(new QRegExpValidator(QRegExp("[0-9]*") , this)); + QHBoxLayout *portLayout = new QHBoxLayout(m_portFrame); + portLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + portLayout->setSpacing(FRAME_LAYOUT_SPACING); + portLayout->addWidget(m_portLabel); + portLayout->addWidget(m_portLineEdit); + + //用户名ui布局 + m_userNameFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_userNameFrame); + m_userNameLabel = new QLabel(tr("Username"), m_userNameFrame); + m_userNameLabel->setFixedWidth(LABEL_WIDTH); + m_userNameLineEdit = new QLineEdit(m_userNameFrame); + m_userNameLineEdit->setPlaceholderText(tr("Optional")); //选填 + QHBoxLayout *userNameLayout = new QHBoxLayout(m_userNameFrame); + userNameLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + userNameLayout->setSpacing(FRAME_LAYOUT_SPACING); + userNameLayout->addWidget(m_userNameLabel); + userNameLayout->addWidget(m_userNameLineEdit); + + //密码ui布局 + m_pwdFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_pwdFrame); + m_pwdLabel = new QLabel(tr("Password"), m_pwdFrame); + m_pwdLabel->setFixedWidth(LABEL_WIDTH); + m_pwdLineEdit = new KPasswordEdit(m_pwdFrame); + m_pwdLineEdit->setClearButtonEnabled(false); + QString str = tr("Optional"); + m_pwdLineEdit->setPlaceholderText(str); //选填 + + QHBoxLayout *pwdLayout = new QHBoxLayout(m_pwdFrame); + pwdLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + pwdLayout->setSpacing(FRAME_LAYOUT_SPACING); + pwdLayout->addWidget(m_pwdLabel); + pwdLayout->addWidget(m_pwdLineEdit); + + QRegExp rxPwd("^[A-Za-z0-9`~!@#$%^&*()_-+=<>,.\\\/]+$"); + QRegExpValidator *latitude = new QRegExpValidator(rxPwd, this); + m_pwdLineEdit->setValidator(latitude); + +#if 0 + //按钮ui布局 + m_appBtnFrame = new QFrame(m_appProxyFrame); + setFrame_Noframe(m_appBtnFrame); + m_cancelBtn = new QPushButton(m_appBtnFrame); + m_saveBtn = new QPushButton(m_appBtnFrame); + m_cancelBtn->setText(tr("Cancel")); + m_saveBtn->setText(tr("Save")); + + QHBoxLayout *btnLayout = new QHBoxLayout(m_appBtnFrame); + btnLayout->setContentsMargins(FRAME_LAYOUT_MARGINS); + btnLayout->setSpacing(16); + btnLayout->addStretch(); + btnLayout->addWidget(m_cancelBtn); + btnLayout->addWidget(m_saveBtn); +#endif + + //分隔线 + m_appLine1 = setLine(m_appProxyFrame); + m_appLine2 = setLine(m_appProxyFrame); + m_appLine3 = setLine(m_appProxyFrame); + m_appLine4 = setLine(m_appProxyFrame); + m_appLine5 = setLine(m_appProxyFrame); + + appProxyLayout->addWidget(m_appEnableFrame); + appProxyLayout->addWidget(m_appLine1); + appProxyLayout->addWidget(m_proxyTypeFrame); + appProxyLayout->addWidget(m_appLine2); + appProxyLayout->addWidget(m_ipAddressFrame); + appProxyLayout->addWidget(m_appLine3); + appProxyLayout->addWidget(m_portFrame); + appProxyLayout->addWidget(m_appLine4); + appProxyLayout->addWidget(m_userNameFrame); + appProxyLayout->addWidget(m_appLine5); + appProxyLayout->addWidget(m_pwdFrame); +// appProxyLayout->addWidget(line5); +// appProxyLayout->addWidget(m_appBtnFrame); + + connect(m_appEnableBtn, &KSwitchButton::stateChanged, this, &Proxy::onappProxyEnableChanged); + connect(m_appEnableBtn, &KSwitchButton::stateChanged, this, &Proxy::setAppProxyState); + connect(m_proxyTypeComboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(onAppProxyConfChanged())); + connect(m_ipAddressLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onipEditStateChanged())); + connect(m_ipAddressLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onAppProxyConfChanged())); + connect(m_portLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onAppProxyConfChanged())); + connect(m_userNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onAppProxyConfChanged())); + connect(m_pwdLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onAppProxyConfChanged())); + connect(m_ipAddressLineEdit, SIGNAL(textChanged(QString)), this, SLOT(onAppProxyConfChanged())); + + connect(m_proxyTypeComboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(onAppProxyConfEditFinished())); + connect(m_ipAddressLineEdit, SIGNAL(editingFinished()), this, SLOT(onAppProxyConfEditFinished())); + connect(m_portLineEdit, SIGNAL(editingFinished()), this, SLOT(onAppProxyConfEditFinished())); + connect(m_userNameLineEdit, SIGNAL(editingFinished()), this, SLOT(onAppProxyConfEditFinished())); + connect(m_pwdLineEdit, SIGNAL(editingFinished()), this, SLOT(onAppProxyConfEditFinished())); +// connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(onCancelBtnClicked())); +// connect(m_saveBtn, SIGNAL(clicked()), this, SLOT(onSaveBtnClicked())); +} + +void Proxy::setAppListFrameUi(QWidget *widget) +{ + //应用列表 + m_appListFrame = new QFrame(widget); + m_appListFrame->setMinimumSize(QSize(550, 0)); + m_appListFrame->setMaximumSize(QSize(16777215, 336)); + m_appListFrame->setFrameShape(QFrame::Box); + QVBoxLayout *appListLayout = new QVBoxLayout(m_appListFrame); + appListLayout->setContentsMargins(16, 23, 16, 16); + appListLayout->setSpacing(16); + + m_allowAppProxyLabel = new QLabel(m_appListFrame); + m_allowAppProxyLabel->setText(tr("The following applications are allowed to use this configuration:")); //允许以下应用使用该配置: + m_appListWidget = new QListWidget(m_appListFrame); + m_appListWidget->setMinimumHeight(240); + m_appListWidget->setBackgroundRole(QPalette::Base); + m_appListWidget->setFocusPolicy(Qt::FocusPolicy::NoFocus); + m_appListWidget->setFrameShape(QFrame::Shape::Panel); + + appListLayout->addWidget(m_allowAppProxyLabel); + appListLayout->addWidget(m_appListWidget); + + QPalette mpal(m_appListWidget->palette()); + mpal.setColor(QPalette::Base, qApp->palette().base().color()); + mpal.setColor(QPalette::AlternateBase, qApp->palette().alternateBase().color()); + m_appListWidget->setAlternatingRowColors(true); + m_appListWidget->setPalette(mpal); +} + +void Proxy::appProxyInfoPadding() +{ + QStringList proxyInfo; + proxyInfo.clear(); + proxyInfo = getAppProxyConf(); + + m_proxyTypeComboBox->setCurrentText(proxyInfo.value(0)); + m_ipAddressLineEdit->setText(proxyInfo.value(1)); + m_portLineEdit->setText(proxyInfo.value(2)); + m_userNameLineEdit->setText(proxyInfo.value(3)); + m_pwdLineEdit->setText(proxyInfo.value(4)); +} + +void Proxy::appListPadding() +{ + QMap appList ; + appList.clear(); + appList = getAppListProxy(); //获取应用代理配置 + + //遍历应用列表 + for (auto index : appList.keys()) { + QStringList appInfo = appList.value(index); + QVariant isChecked = appInfo.value(2); + bool flag = isChecked.toBool(); + + AppListWidget *appWidget = new AppListWidget(index, m_appListWidget); + appWidget->setAppName(appInfo.value(0)); + appWidget->setAppIcon(QIcon::fromTheme(appInfo.value(1)).pixmap(24, 24)); + appWidget->setAppChecked(flag); + + QListWidgetItem *appListWidgetItem = new QListWidgetItem(m_appListWidget); + appListWidgetItem->setSizeHint(QSize(m_appListWidget->width(),36)); + appListWidgetItem->setFlags(Qt::NoItemFlags); + m_appListWidget->addItem(appListWidgetItem); + m_appListWidget->setItemWidget(appListWidgetItem, appWidget); + } +} + +bool Proxy::getipEditState(QString text) +{ + if (text.isEmpty()) { + return true; + } + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + bool match = false; + match = rx.exactMatch(text); + + return match; +} + +void Proxy::onipEditStateChanged() +{ + if (!getipEditState(m_ipAddressLineEdit->text())) { + m_ipAddressFrame->setFixedHeight(88); + m_ipHintsLabel->show(); + } else { + m_ipHintsLabel->hide(); + m_ipAddressFrame->setFixedHeight(60); + } +} + +void Proxy::onAppProxyConfChanged() +{ + if (!getipEditState(m_ipAddressLineEdit->text()) || m_portLineEdit->text().isEmpty()) { + return; + qDebug() << "onAppProxyConfChanged return"; + } + + if (m_ipAddressLineEdit->text().isEmpty()) { + return; + } else { + m_appProxyInfo.clear(); + m_appProxyInfo.append(m_proxyTypeComboBox->currentText()); + m_appProxyInfo.append(m_ipAddressLineEdit->text()); + m_appProxyInfo.append(m_portLineEdit->text()); + if (!m_userNameLineEdit->text().isEmpty() && !m_pwdLineEdit->text().isEmpty()) { + m_appProxyInfo.append(m_userNameLineEdit->text()); + m_appProxyInfo.append(m_pwdLineEdit->text()); + } else { + m_appProxyInfo.append(""); + m_appProxyInfo.append(""); + } + + qDebug() << m_appProxyInfo << Q_FUNC_INFO << __LINE__; + } +} + +void Proxy::onAppProxyConfEditFinished() +{ + if (!m_ipAddressLineEdit->hasFocus() && !m_portLineEdit->hasFocus()) { + setAppProxyConf(m_appProxyInfo); + } +} + +void Proxy::onappProxyEnableChanged(bool enable) +{ + m_proxyTypeFrame->setVisible(enable); + m_ipAddressFrame->setVisible(enable); + m_portFrame->setVisible(enable); + m_userNameFrame->setVisible(enable); + m_pwdFrame->setVisible(enable); + m_appListFrame->setVisible(enable); + m_appLine1->setVisible(enable); + m_appLine2->setVisible(enable); + m_appLine3->setVisible(enable); + m_appLine4->setVisible(enable); + m_appLine5->setVisible(enable); +} + +#if 0 +void Proxy::onCancelBtnClicked() +{ + appProxyInfoPadding(); +} + +void Proxy::onSaveBtnClicked() +{ + if (!checkIsChanged(m_appProxyInfo)) { + return; + } else { + QStringList conf; + conf.clear(); + conf.append(m_proxyTypeComboBox->currentText()); + conf.append(m_ipAddressLineEdit->text()); + conf.append(m_portLineEdit->text()); + conf.append(m_userNameLineEdit->text()); + conf.append(m_pwdLineEdit->text()); + setAppProxyConf(conf); + } +} + +void Proxy::setBtnEnable() +{ + m_cancelBtn->setEnabled(true); + + if (getipEditState(m_ipAddressLineEdit->text()) && !m_portLineEdit->text().isEmpty()) { + if (!m_ipAddressLineEdit->text().isEmpty()) { + m_saveBtn->setEnabled(true); + } + } else { + m_saveBtn->setEnabled(false); + } +} +#endif + +void Proxy::setAptProxySlot() +{ + mAptBtn->blockSignals(true); + QHash preaptinfo = getAptProxy(); + bool prestatus = preaptinfo["open"].toBool(); + AptProxyDialog *mwindow = new AptProxyDialog(pluginWidget); + mwindow->exec(); + if (getAptProxy()["open"].toBool() && !prestatus) { // open值为true,用户点击了确定按钮,进行配置文件的写入,提示用户重启系统 + setAptInfo(); + } + if (getAptProxy()["open"].toBool() && prestatus) { + if (getAptProxy()["ip"].toString() == preaptinfo["ip"].toString() && getAptProxy()["port"].toString() == preaptinfo["port"].toString() && prestatus){ //点击了编辑按钮,且在设置IP和端口号的弹窗中,点击了取消或者关闭按钮 + line_7->show(); + mAPTFrame_2->show(); + } else { + setAptInfo(); + } + } + if(!getAptProxy()["open"].toBool() && !prestatus){ // 点击了APT开关按钮,但是在设置IP和端口号的弹窗中,点击了取消或者关闭按钮 + mAptBtn->setChecked(false); + } + mAptBtn->blockSignals(false); +} + +void Proxy::manualProxyTextChanged(QString txt){ + //获取被修改控件 + QObject * pobject = this->sender(); + QLineEdit * who = dynamic_cast(pobject); + + //获取控件保存的用户数据 + GSData currentData = who->property("gData").value(); + QString schema = currentData.schema; + qDebug()<set(key, QVariant(txt)); + + delete setting; + setting = nullptr; +} diff --git a/plugins/proxy/proxy.h b/plugins/proxy/proxy.h new file mode 100644 index 00000000..48d9cc30 --- /dev/null +++ b/plugins/proxy/proxy.h @@ -0,0 +1,285 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef PROXY_H +#define PROXY_H + + +#include +#include +#include + +#include +#include +#include "certificationdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "interface.h" +#include "titlelabel.h" +#include "hoverwidget.h" +#include "applistwidget.h" + +#include "kswitchbutton.h" +#include "kpasswordedit.h" + +using namespace kdk; + +/* qt会将glib里的signals成员识别为宏,所以取消该宏 + * 后面如果用到signals时,使用Q_SIGNALS代替即可 + **/ +#ifdef signals +#undef signals +#endif + +#include +#include + +struct GSData +{ + QString key; + QString schema; +}; + +typedef enum{ + NONE, + MANUAL, + AUTO +}ProxyMode; + +//自定义类型使用QVariant需要使用 Q_DECLARE_METATYPE 注册 +Q_DECLARE_METATYPE(ProxyMode) +Q_DECLARE_METATYPE(GSData) + +namespace Ui { +class Proxy; +} + +class Proxy : public QObject, CommonInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface") + Q_INTERFACES(CommonInterface) + +public: + Proxy(); + ~Proxy(); + + QString plugini18nName() Q_DECL_OVERRIDE; + int pluginTypes() Q_DECL_OVERRIDE; + QWidget * pluginUi() Q_DECL_OVERRIDE; + void plugin_leave()Q_DECL_OVERRIDE; + const QString name() const Q_DECL_OVERRIDE; + bool isShowOnHomePage() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + bool isEnable() const Q_DECL_OVERRIDE; + +public: + void initUi(QWidget *widget); + void initSearchText(); + void retranslateUi(); + void setupComponent(); + void setupConnect(); + void initProxyModeStatus(); + void initAutoProxyStatus(); + void initManualProxyStatus(); + void initIgnoreHostStatus(); + void initDbus(); + void initAppProxyStatus(); + + void manualProxyTextChanged(QString txt); + int _getCurrentProxyMode(); + void _setSensitivity(); + bool getAptProxyInfo(bool status); + static void setAptProxy(QString host ,QString port ,bool status); // apt代理对应的配置文件的写入或删除 + static QHash getAptProxy(); + void setAptInfo(); + void reboot(); // 调用重启接口 + + void setFrame_Noframe(QFrame *frame); + QFrame *setLine(QFrame *frame); + + bool getAppProxyState(); //获取应用代理开启状态--调用Dbus + void setAppProxyState(bool state); //设置应用代理开启状态--调用Dbus + static QStringList getAppProxyConf(); //获取应用代理配置信息--调用Dbus + void setAppProxyConf(QStringList list); //设置应用代理配置信息--调用Dbus + static QMap getAppListProxy(); +// bool checkIsChanged(QStringList info); + +private: + void setAppProxyFrameUi(QWidget *widget); + void setAppListFrameUi(QWidget *widget); + void appProxyInfoPadding(); + void appListPadding(); + bool getipEditState(QString text); + + QString pluginName; + int pluginType; + QWidget * pluginWidget; + + TitleLabel *mTitleLabel; + TitleLabel *m_appProxyLabel; + TitleLabel *mAptProxyLabel; + QLabel *mUrlLabel; + QLabel *mHTTPLabel; + QLabel *mHTTPPortLabel; + QLabel *mHTTPSLabel; + QLabel *mHTTPSPortLabel; + QLabel *mFTPLabel; + QLabel *mFTPPortLabel; + QLabel *mSOCKSLabel; + QLabel *mSOCKSPortLabel; + QLabel *mIgnoreLabel; + QLabel *mAptLabel; + QLabel *mAPTHostLabel_1; + QLabel *mAPTHostLabel_2; + QLabel *mAPTPortLabel_1; + QLabel *mAPTPortLabel_2; + + QLabel *mCertificationLabel; + QLabel *mUserNameLabel; + QLabel *mPwdLabel; + + QLabel *m_appEnableLabel; + QLabel *m_proxyTypeLabel; + QLabel *m_ipAddressLabel; + QLabel *m_ipHintsLabel; + QLabel *m_portLabel; + QLabel *m_userNameLabel; + QLabel *m_pwdLabel; + QLabel *m_allowAppProxyLabel; + + QFrame *mProxyFrame; + QFrame *mEnableFrame; + QFrame *mSelectFrame; + QFrame *mUrlFrame; + + QFrame *mHTTPFrame; + QFrame *mHTTPSFrame; + QFrame *mFTPFrame; + QFrame *mSOCKSFrame; + QFrame *mIgnoreFrame; + QFrame *mCertificationFrame_1; + + QFrame *m_appEnableFrame; + QFrame *m_appProxyFrame; + QFrame *m_proxyTypeFrame; + QFrame *m_ipAddressFrame; + QFrame *m_portFrame; + QFrame *m_userNameFrame; + QFrame *m_pwdFrame; +// QFrame *m_appBtnFrame; + QFrame *m_appListFrame; + + QFrame *mAPTFrame; + QFrame *mAPTFrame_1; + QFrame *mAPTFrame_2; + + QFrame *line_1; + QFrame *line_2; + QFrame *line_3; + QFrame *line_4; + QFrame *line_5; + QFrame *line_6; + QFrame *line_7; + QFrame *line_8; + QFrame *m_appLine1; + QFrame *m_appLine2; + QFrame *m_appLine3; + QFrame *m_appLine4; + QFrame *m_appLine5; + + QRadioButton *mAutoBtn; + QRadioButton *mManualBtn; + KSwitchButton *mEnableBtn; + KSwitchButton *mAptBtn; + QPushButton *mEditBtn; + QCheckBox *mCertificationBtn; + + QButtonGroup *mProxyBtnGroup; + + QLineEdit *mUrlLineEdit; + QLineEdit *mHTTPLineEdit_1; + QLineEdit *mHTTPLineEdit_2; + QLineEdit *mHTTPSLineEdit_1; + QLineEdit *mHTTPSLineEdit_2; + QLineEdit *mFTPLineEdit_1; + QLineEdit *mFTPLineEdit_2; + QLineEdit *mSOCKSLineEdit_1; + QLineEdit *mSOCKSLineEdit_2; + QLineEdit *mUserNameLineEdit; + QLineEdit *mPwdLineEdit; + QLineEdit *m_ipAddressLineEdit; + QLineEdit *m_portLineEdit; + QLineEdit *m_userNameLineEdit; + + KSwitchButton *m_appEnableBtn; + QComboBox *m_proxyTypeComboBox; + KPasswordEdit *m_pwdLineEdit = nullptr; +// QPushButton *m_cancelBtn; +// QPushButton *m_saveBtn; + QListWidget *m_appListWidget = nullptr; + + QTextEdit *mIgnoreLineEdit; + + QGSettings * proxysettings; + QGSettings * httpsettings; + QGSettings * securesettings; + QGSettings * ftpsettings; + QGSettings * sockssettings; + QGSettings * aptsettings; + + QFileSystemWatcher *mfileWatch_1; + QFileSystemWatcher *mfileWatch_2; + + QDBusInterface *mAptproxyDbus; + QDBusInterface *m_appProxyDbus; + + bool isExistSettings = false; + bool settingsCreate; + bool mFirstLoad; + QStringList m_appProxyInfo; + QStringList m_appCheckedList; + +private slots: + void setAptProxySlot(); //处理apt代理前端交互逻辑 + void onappProxyEnableChanged(bool enable); //IP地址无效提示 + void onipEditStateChanged(); //IP地址无效提示 + void onAppProxyConfChanged(); //应用代理配置信息变化 + void onAppProxyConfEditFinished(); +// void onCancelBtnClicked(); +// void onSaveBtnClicked(); +// void setBtnEnable(); +}; + +#endif // PROXY_H diff --git a/plugins/proxy/proxy.pro b/plugins/proxy/proxy.pro new file mode 100644 index 00000000..2e5ab27e --- /dev/null +++ b/plugins/proxy/proxy.pro @@ -0,0 +1,52 @@ +#include(../../../env.pri) + +QT += widgets dbus + +TEMPLATE = lib +CONFIG += plugin + +TARGET = $$qtLibraryTarget(proxy) +DESTDIR = ../.. +target.path = $$[QT_INSTALL_LIBS]/ukui-control-center +trans.files = translations/* +trans.path = /usr/share/kylin-nm/proxy/ + +INCLUDEPATH += \ + $$PROJECT_COMPONENTSOURCE \ + $$PROJECT_ROOTDIR \ + /usr/include/ukcc/interface \ + /usr/include/ukcc/widgets + +LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt -lukcc + +##加载gio库和gio-unix库,用于获取和设置enum类型的gsettings +CONFIG += link_pkgconfig \ + C++11 +PKGCONFIG += gio-2.0 \ + gio-unix-2.0 \ + gsettings-qt \ + kysdk-qtwidgets + +#DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + applistwidget.cpp \ + aptproxydialog.cpp \ + proxy.cpp + +HEADERS += \ + applistwidget.h \ + aptinfo.h \ + aptproxydialog.h \ + proxy.h \ + certificationdialog.h + +FORMS += + +INSTALLS += target \ + trans + +TRANSLATIONS += \ + translations/zh_CN.ts \ + translations/tr.ts \ + translations/bo_CN.ts diff --git a/plugins/proxy/translations/bo_CN.qm b/plugins/proxy/translations/bo_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..67dad16605f47748233a872799f5566ac49d932a GIT binary patch literal 3755 zcma)9U1%It6uwFJC)vs7+TufnAXh0Ng&#qIr_8Zq9>ir`3?q|2sjJ0iKkt64E{gXvLjWE{!F^lS-GZy`b zMdyw)#twVe*b6Lr;wodE@36gZ{=-=8N_+OTQN}tpw(tD`*Y;mK24`WPc(mhY?IuGzsXqFj_A7Ghk>&g-L!uR=e`>2+jIlJ zACK+5jo;hO#R_-+#`}@DQ81Gu1jPMViL;SJ-41lX0K)9bz@{8Q&d9Lsr&+tW_<;hMwU@`g( zsb)bd$MLl%RdF-6b!cImp_Z+gHZp#gr}-ER$TS7h0=`WFPT}Ktvc&ZORD8%Xb;F)* zh1CsCD5$PsnLcJzqD#8h!@&%jfJ@RfN%f+Ho36!vI^bT{GS`AI@Mar)$RQ?I<}58G zKt$&G2Y7~W4GBb2Ro9~60tf^CdouG&GCmK5a(@X(``{9B=Ev7bNTO;>IR(&GEx~0r zd42|5PU9q@E$R_9cGAQ4pQ&RYlW)~$=9%o9uGQs-U7Pg_G zrpaA~;|fa`#*As%T2YiN$8{bNv$zp%Ni~IKYCpN6{w*6qCDnrUT#GZiSB*lyLVsw+!|L{EfJ_g=&`XcHN$Xl4k1 z0B`7$sGK}wS_VBR3!loK2%!WKd4ZB0t57#uasFCK71>bJriKx)$*7JqZ`s9=2lr_3 z0Ri<$)Y>RuqLGL=4Fj=Rgn)Zj)eb%UkZIov({ad=_^eBbSo32`$YzYp7qt-509a@Y z4es;mHNkt}xeJvr-Y|0VR!y3^EFZO&Bb^^b)@Y#6w3f{peEDTTd2GDX;I4a*mbWZd z?1CumknfujEfv&B{0-RRSIU7`XjC>d+Uo@!9`A`7{xjBm2)!3}G*mo$`a1@us9b}? zv~!R4V%0!(g{=Fe7QFX|;ZGf>l^>C;Iv3`0Q4f|b#>!e$y$Yj&71jS;Ajy3(K;1e8hrj~bbD&^7875gO4e0TBvr>S zXF^m8IW4_5<8{T*8sUp2yWqImY|}|Y9eSnE>+Q(v#}^TR!k?GTgwjl%dZm1`Aeo*_ z;6okXlLQI7)egCHqNE8G8&`!EQ6WmIBl4PN3b$&TXv~(b3)L(NQ`3r$z_O9o1U5cm z1W$4Ast3`jbzLij*Mpb9Xi*YWUt^lBZ651+1V)QT3cb%;=jsEFvPODptR(nO{gy_M zpHmvO-r%D*Pok#${G}*F-71%@d1Mg5HdaDMsF*h@J@JC6V$QfF!x07AtY@m2H|W)y zLs|bmkagdcMuVsod00>ivVq)q8!>W60ff|oz$QU}w?PieOg8^-V0o!}`5u>rOf!CE z!>Rj{ + + + + AptProxyDialog + + + Set Apt Proxy + Apt ངོ་ཚབ་ བཙུགས་པ། + + + + Server Address + ཞབས་ཞུའི་ས་གནས། + + + + Port + གྲུ་ཁ། + + + + Cancel + ཕྱིར་འཐེན། + + + + Confirm + གཏན་འཁེལ་བྱ་དགོས། + + + + Proxy + + + Proxy + ཚབ་བྱེད་མི་སྣ། + + + + Start using + བཀོལ་སྤྱོད་བྱེད་འགོ་ཚུགས། + + + + Proxy mode + ཚབ་བྱེད་དཔེ་དབྱིབས། + + + + Auto + རང་འགུལ་གྱིས་རླངས་ + + + + Manual + ལག་དེབ། + + + + Application Proxy + ཉེར་སྤྱོད་ངོ་ཚབ། + + + + System Proxy + མ་ལག་གི་ཚབ་བྱེད་ + + + + Auto url + རླངས་འཁོར་གྱི་དྲ་ཚིགས། + /Proxy/Auto url + + + + Http Proxy + HTTP ཚབ་བྱེད་མི་སྣ། + /Proxy/Http Proxy + + + + Https Proxy + HTTPS ཚབ་བྱེད་མི་སྣ། + /Proxy/Https Proxy + + + + Ftp Proxy + FTP ཚབ་བྱེད་མི་སྣ། + /Proxy/Ftp Proxy + + + + Socks Proxy + SOCKS ཚབ་བྱེད་མི་སྣ། + /Proxy/Socks Proxy + + + + + + + + Port + གྲུ་ཁ། + + + + List of ignored hosts. more than one entry, please separate with english semicolon(;) + སྣང་མེད་དུ་བཞག་པའི་བདག་པོའི་མིང་ཐོ། འཇུག་སྒོ་གཅིག་ལས་བརྒལ་ན་དབྱིན་ཡིག་གི་ཕྱེད་ཀ་དང་ཁ་གྱེས་རོགས། (;) + + + + Apt Proxy + APT ཚབ་བྱེད་མི་སྣ། + /Proxy/Apt Proxy + + + + + Open + སྒོ་ཕྱེ་བ། + + + + Server Address : + ཞབས་ཞུའི་ཡོ་བྱད་ཀྱི་གནས་ཡུལ + + + + Port : + གྲུ་ཁ། + + + + Edit + རྩོམ་སྒྲིག + + + + The apt proxy has been turned off and needs to be restarted to take effect + ངོ་ཚབ་ཀྱི་སྒོ་བརྒྱབ་ཟིན་པས་ཡང་བསྐྱར་ནུས་པ་ཐོན་པར་བྱ་དགོས། + + + + + Reboot Later + རྗེས་སུ་ཡང་བསྐྱར་ཐེངས་གཅིག་ལ་བསྐྱར་ + + + + + Reboot Now + ད་ལྟ་བསྐྱར་དུ་ལས་ཀ་བྱེད་དགོས། + + + + The system needs to be restarted to set the Apt proxy, whether to reboot + མ་ལག་འདི་བསྐྱར་དུ་འགོ་ཚུགས་ནས་Aptཡི་ཚབ་བྱེད་འཕྲུལ་ཆས་གཏན་འཁེལ་བྱེད་དགོས་པ་དང་། བསྐྱར་དུ་འགོ་འཛུགས་དགོས་མིན་ + + + + Proxy type + ངོ་ཚབ་ཀྱི་རིགས་དབྱིབས། + + + HTTP + HTTP + + + socks4 + རྐང་འབོབ་4 + + + socks5 + རྐང་འབོབ་5 + + + + IP address + IPས་གནས། + + + + + Required + བླང་བྱ་བཏོན་པ། + + + + Invalid IP Address + གོ་མི་ཆོད་པའི་IPས་གནས། + + + + Username + སྤྱོད་མཁན་གྱི་མིང་། + + + + + Optional + བསལ་འདེམས་ཀྱི་རང་བཞིན། + + + + Password + གསང་གྲངས། + + + + Cancel + ཕྱིར་འཐེན། + + + + Save + གྲོན་ཆུང་བྱེད་དགོས། + + + + The following applications are allowed to use this configuration: + གཤམ་གྱི་ཉེར་སྤྱོད་གོ་རིམ་ཁྲོད་དུ་བཀོད་སྒྲིག་འདི་བཀོལ་ཆོག་པ་སྟེ། + + + diff --git a/plugins/proxy/translations/tr.ts b/plugins/proxy/translations/tr.ts new file mode 100644 index 00000000..9bb74840 --- /dev/null +++ b/plugins/proxy/translations/tr.ts @@ -0,0 +1,215 @@ + + + + + AptProxyDialog + + + Set Apt Proxy + + + + + Server Address + + + + + Port + + + + + Cancel + + + + + Confirm + + + + + Proxy + + + Proxy + + + + + Start using + + + + + Proxy mode + + + + + Auto + + + + + Manual + + + + + Application Proxy + + + + + System Proxy + + + + + Auto url + + /Proxy/Auto url + + + + Http Proxy + + /Proxy/Http Proxy + + + + Https Proxy + + /Proxy/Https Proxy + + + + Ftp Proxy + + /Proxy/Ftp Proxy + + + + Socks Proxy + + /Proxy/Socks Proxy + + + + + + + + Port + + + + + List of ignored hosts. more than one entry, please separate with english semicolon(;) + + + + + Apt Proxy + + /Proxy/Apt Proxy + + + + + Open + + + + + Server Address : + + + + + Port : + + + + + Edit + + + + + The apt proxy has been turned off and needs to be restarted to take effect + + + + + + Reboot Later + + + + + + Reboot Now + + + + + The system needs to be restarted to set the Apt proxy, whether to reboot + + + + + Proxy type + + + + + IP address + + + + + + Required + + + + + Invalid IP Address + + + + + Username + + + + + + Optional + + + + + Password + + + + + Cancel + + + + + Save + + + + + The following applications are allowed to use this configuration: + + + + diff --git a/plugins/proxy/translations/zh_CN.qm b/plugins/proxy/translations/zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..61541952469117d11d954d015d6ea0a14a58a445 GIT binary patch literal 2357 zcma)7U1%It6uz6x?oKAV8|s6G67VWgBGe?P(3c3d>u$Qx&Z4a65bJD{Sx^z7Z9p{75PiY z5keyys}Mo{lZy!X6DaxO-v|j0*U8WKB2p-2=K)GyGN$M?sQ$2 zN&R98%-<#bum}7MG&b%Ups;@~bToV~@V15CoCtxP+3=;;INw6kA!8Ec<)-;7;2-+1 z>8)iy*gezq_9GC#Fs%XkFZCc1LDbR~A3JWfy7ab1i^aT_R+wh!o4WoAOCa*B=(onWFfb8;sx=7~ZHrlhEt3L|)2 zV>ysz^BT>;X+cXHc|&jQy3v3D0{^zN0T~!Oola!G{)vmpLa|}NE$9{U^w{qwubYzw%GBxn@b?a8r zV;k*D + + + + AptProxyDialog + + + Set Apt Proxy + 设置APT代理 + + + + Server Address + 服务器地址 + + + + Port + 端口 + + + + Cancel + 取消 + + + + Confirm + 确定 + + + + Proxy + + + Proxy + 代理 + + + + Start using + 启用 + + + + Proxy mode + 代理类型 + + + + Auto + 自动 + + + + Manual + 手动 + + + + Application Proxy + 应用代理 + + + + System Proxy + 系统代理 + + + + Auto url + 配置URL + /Proxy/Auto url + + + + Http Proxy + HTTP代理 + /Proxy/Http Proxy + + + + Https Proxy + HTTPS代理 + /Proxy/Https Proxy + + + + Ftp Proxy + FTP代理 + /Proxy/Ftp Proxy + + + + Socks Proxy + SOCKS代理 + /Proxy/Socks Proxy + + + + + + + + Port + 端口 + + + + List of ignored hosts. more than one entry, please separate with english semicolon(;) + 忽略的主机列表,请使用英文分号(;) + + + + Apt Proxy + APT代理 + /Proxy/Apt Proxy + + + + + Open + 开启 + + + + Server Address : + 服务器地址: + + + + Port : + 端口: + + + + Edit + 编辑 + + + + The apt proxy has been turned off and needs to be restarted to take effect + APT代理已关闭,需要重启才能生效 + + + + + Reboot Later + 稍后重启 + + + + + Reboot Now + 立即重启 + + + + The system needs to be restarted to set the Apt proxy, whether to reboot + 设置APT代理需要重启系统后生效,是否重启系统 + + + + Proxy type + 代理类型 + + + + IP address + IP地址 + + + + + Required + 必填 + + + + Invalid IP Address + 无效的IP地址 + + + + Username + 用户名 + + + + + Optional + 选填 + + + + Password + 密码 + + + + Cancel + 取消 + + + + Save + 保存 + + + + The following applications are allowed to use this configuration: + 允许以下应用使用该配置: + + + diff --git a/plugins/wlanconnect/deviceframe.cpp b/plugins/wlanconnect/deviceframe.cpp new file mode 100644 index 00000000..be13ca78 --- /dev/null +++ b/plugins/wlanconnect/deviceframe.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "deviceframe.h" +#include + +#define LAYOUT_MARGINS 18,0,8,0 +#define FRAME_HEIGHT 58 +#define LAYOUT_SPACING 16 +#define RADIUS 6.0 + +DeviceFrame::DeviceFrame(QString devName, QWidget *parent) : QFrame(parent) +{ + this->setFrameShape(QFrame::Box); + this->setFixedHeight(FRAME_HEIGHT); + QHBoxLayout *deviceLayout = new QHBoxLayout(this); + deviceLayout->setContentsMargins(LAYOUT_MARGINS); + setLayout(deviceLayout); + deviceLayout->setSpacing(LAYOUT_SPACING); + + deviceLabel = new QLabel(this); + dropDownLabel = new DrownLabel(devName, this); + + deviceLayout->addWidget(deviceLabel); + deviceLayout->addStretch(); + deviceLayout->addWidget(dropDownLabel); +} + +DeviceFrame::~DeviceFrame() +{ + +} + +void DeviceFrame::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + painter.setBrush(pal.color(QPalette::Base)); + + QRect rect = this->rect(); + QPainterPath path; + path.addRoundedRect (rect, RADIUS, RADIUS); + QRect temp_rect(rect.left(), rect.top() + rect.height()/2, rect.width(), rect.height()/2); + path.addRect(temp_rect); + painter.drawPath(path); + QFrame::paintEvent(event); +} + diff --git a/plugins/wlanconnect/deviceframe.h b/plugins/wlanconnect/deviceframe.h new file mode 100644 index 00000000..d6300e36 --- /dev/null +++ b/plugins/wlanconnect/deviceframe.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DEVICEFRAME_H +#define DEVICEFRAME_H +#include +#include +#include +#include +#include +#include +#include "../component/DrownLabel/drownlabel.h" + +class DeviceFrame : public QFrame +{ + +public: + DeviceFrame(QString devName, QWidget *parent = nullptr); + ~DeviceFrame(); +public: + //仅设备名称+下拉label + QLabel * deviceLabel = nullptr; + DrownLabel *dropDownLabel = nullptr; + +protected: + void paintEvent(QPaintEvent *event); + +private: + int frameSize; + +}; + +#endif // DEVICEFRAME_H diff --git a/plugins/wlanconnect/itemframe.cpp b/plugins/wlanconnect/itemframe.cpp new file mode 100644 index 00000000..503e3b2b --- /dev/null +++ b/plugins/wlanconnect/itemframe.cpp @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "itemframe.h" +#include + +#define LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +ItemFrame::ItemFrame(QString devName, QWidget *parent) +{ + deviceLanLayout = new QVBoxLayout(this); + deviceLanLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); + lanItemFrame = new QFrame(this); + lanItemFrame->setFrameShape(QFrame::Shape::NoFrame); + lanItemFrame->setContentsMargins(LAYOUT_MARGINS); + + lanItemLayout = new QVBoxLayout(this); + lanItemLayout->setContentsMargins(LAYOUT_MARGINS); + lanItemLayout->setSpacing(1); + addWlanWidget = new AddNetBtn(true, this); + + deviceLanLayout->setSpacing(1); + setLayout(deviceLanLayout); + lanItemFrame->setLayout(lanItemLayout); + + deviceFrame = new DeviceFrame(devName, this); + deviceLanLayout->addWidget(deviceFrame); + deviceLanLayout->addWidget(lanItemFrame); + deviceLanLayout->addWidget(addWlanWidget); + + //下拉按钮 + connect(deviceFrame->dropDownLabel, &DrownLabel::labelClicked, this, &ItemFrame::onDrownLabelClicked); +} + +ItemFrame::~ItemFrame() +{ + +} + +void ItemFrame::onDrownLabelClicked() +{ + if (!deviceFrame->dropDownLabel->isChecked) { + lanItemFrame->show(); + deviceFrame->dropDownLabel->setDropDownStatus(true); + } else { + lanItemFrame->hide(); + deviceFrame->dropDownLabel->setDropDownStatus(false); + } +} + +void ItemFrame::filletStyleChange() +{ + if (lanItemLayout->isEmpty()) { + return; + } + + for (int i = 0; i < lanItemLayout->count(); ++i) { + QLayoutItem *it = lanItemLayout->itemAt(i); + WlanItem *itemFrame = (WlanItem*)(it->widget()); + if (i != lanItemLayout->count()-1) { + itemFrame->setHalfFillet(false); + } else { + itemFrame->setHalfFillet(true); + } + } +} diff --git a/plugins/wlanconnect/itemframe.h b/plugins/wlanconnect/itemframe.h new file mode 100644 index 00000000..ee947279 --- /dev/null +++ b/plugins/wlanconnect/itemframe.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef ITEMFRAME_H +#define ITEMFRAME_H +#include +#include +#include "deviceframe.h" +#include "../component/AddBtn/addnetbtn.h" +#include "wlanitem.h" + +class ItemFrame : public QFrame +{ + Q_OBJECT +public: + ItemFrame(QString devName, QWidget *parent = nullptr); + ~ItemFrame(); + //单设备整体layout + QVBoxLayout * deviceLanLayout = nullptr; + //单设备名称+下拉按钮Frame + DeviceFrame * deviceFrame = nullptr; + //单设备列表Frame + QFrame * lanItemFrame = nullptr; + //单设备列表layout + QVBoxLayout * lanItemLayout = nullptr; + //单设备item列表 + QMap itemMap; + //已激活uuid + QString uuid = ""; + //新建无线连接 + AddNetBtn * addWlanWidget = nullptr; + void filletStyleChange(); + +private slots: + void onDrownLabelClicked(); +}; + +#endif // ITEMFRAME_H diff --git a/plugins/wlanconnect/translations/bo.qm b/plugins/wlanconnect/translations/bo.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/wlanconnect/translations/bo.qm @@ -0,0 +1 @@ + + + + + AddNetBtn + + + Add Others + + + + + Add WiredNetork + + + + + WlanConnect + + + + WlanConnect + + + + + + WLAN + + + + + + open + + /wlanconnect/open + + + + + Advanced settings + + /wlanconnect/Advanced settings" + + + + ukui control center + + + + + ukui control center desktop message + + + + + No wireless network card detected + + + + + + + connected + + + + + card + + + + diff --git a/plugins/wlanconnect/translations/bo_CN.qm b/plugins/wlanconnect/translations/bo_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..8f72b8c98bf103ffa46bc94a91a9a83a4f20018c GIT binary patch literal 1046 zcmZ`&&ubGw6rQw6f2}%5Em-t0LGj#EK@jZ5c&fyN)@@M?iL;X$5@*Zqw1v`x2Tz`) zv|^zsy?E-SIeF3KEc7B?{SSm5{0IErY-+Y-J?zfBo%g=)d*8gh_r<^d{p@i6G=H;O zJNo*oz!)pDT(8PlrpU%Vyuo_L#v9)l8_^?oqZ!6VXLF0apNR80{r(T~S?={)R7O~u43*ZTX)c|7$JL2*90!}Ll z+^ep?S=UneB2vaQ^_qouR@!y_AkbP#V+o3Yc?WqFfUNRuyCxf|St<{d)QE>n%APiKYe{LTfLBmH@M3U{S?V&i;x_1qDap%| z6bC0|d^!Jd>KdHbg(D7sV#^68AtG2;I#t9%!Uxx0Y3#=NEIqZ;<3Q>&oYMSC{t5DE zo|nKm;F#WMZ8QZ`nlNY!skBjHDrFhhMx#zp+mPw}i_b68!xSCiI}NtOhb53h@sD)z Xm${W90RtAbOt3CqVf5;2YDm&wUbx;H literal 0 HcmV?d00001 diff --git a/plugins/wlanconnect/translations/bo_CN.ts b/plugins/wlanconnect/translations/bo_CN.ts new file mode 100644 index 00000000..0d7ff07a --- /dev/null +++ b/plugins/wlanconnect/translations/bo_CN.ts @@ -0,0 +1,73 @@ + + + + + AddNetBtn + + + Add Others + དྲ་རྒྱ་གཞན་དག་ནང་ཞུགས་དགོས། + + + + Add WiredNetork + + + + + WlanConnect + + + + WlanConnect + ཝུའུ་ལན་འབྲེལ་མཐུད། + + + + + WLAN + སྐུད་མེད་ཅུས་ཁོངས་ཀྱི་དྲ་བ། + + + + + open + སྒོ་ཕྱེ་བ། + /wlanconnect/open + + + + + Advanced settings + སྔོན་ཐོན་གྱི་སྒྲིག་བཀོད། + /wlanconnect/Advanced settings" + + + + ukui control center + ཝུའུ་ཁི་ལན་གྱི་ཚོད་འཛིན་ལྟེ་གནས། + + + + ukui control center desktop message + ངོས་ལེབ་ངོས་ཀྱི་བརྡ་ཐོ་ཚོད་འཛིན་བྱ་དགོས། + + + + No wireless network card detected + སྐུད་མེད་དྲ་རྒྱའི་བྱང་བུ་མ་རྙེད་པ། + + + + + + connected + འབྲེལ་མཐུད་བྱེད་པ། + + + + card + བྱང་བུ། + + + diff --git a/plugins/wlanconnect/translations/tr.qm b/plugins/wlanconnect/translations/tr.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/plugins/wlanconnect/translations/tr.qm @@ -0,0 +1 @@ + + + + + AddNetBtn + + + Add Others + + + + + Add WiredNetork + + + + + WlanConnect + + + + WlanConnect + + + + + + WLAN + + + + + + open + + /wlanconnect/open + + + + + Advanced settings + + /wlanconnect/Advanced settings" + + + + ukui control center + + + + + ukui control center desktop message + + + + + No wireless network card detected + + + + + + + connected + + + + + card + + + + diff --git a/plugins/wlanconnect/translations/zh_CN.qm b/plugins/wlanconnect/translations/zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..79c6584951bbd386b30c54349b5df22a72bd100c GIT binary patch literal 664 zcmcE7ks@*G{hX<16=n7(EZlq7iGhJ3fPwWu9FX3}z&4|Wfq_wxfjw;>kgi~|EEWaQ zw^_XpTmjOata;Nu1JyCGHgo~iG30Wj*@O5dT++!P{u`b*l9zz$7GyFoFzGP^MR2{hdtZGX zT)m)UN?BrFa%ze~acW6PW?nj28+Uk4VxDt;US4W)30R{*x>m-4T<;)*)CYC@>jQ%m z;RY!Br7s#L(hw%ILfpDW( z!hIb5h*phkBvwrwoxzz5@i-2bv&1um=))DW + + + + AddNetBtn + + + Add Others + 加入其它网络 + + + + Add WiredNetork + + + + + WlanConnect + + + + WlanConnect + 无线局域网 + + + + + WLAN + 无线局域网 + + + + + open + 开启 + /wlanconnect/open + + + + + Advanced settings + 高级设置 + /wlanconnect/Advanced settings" + + + + ukui control center + 控制面板 + + + + ukui control center desktop message + 控制面板桌面通知 + + + + No wireless network card detected + 未检测到无线网卡 + + + + + + connected + 已连接 + + + + card + 网卡 + + + diff --git a/plugins/wlanconnect/wlanconnect.cpp b/plugins/wlanconnect/wlanconnect.cpp new file mode 100644 index 00000000..e9a59c70 --- /dev/null +++ b/plugins/wlanconnect/wlanconnect.cpp @@ -0,0 +1,1101 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wlanconnect.h" +#include "ui_wlanconnect.h" + +#include +#include +#include +#include +#include +#include +#include + +#define WIRELESS_TYPE 1 + +#define SCANTIMER 20 * 1000 +#define UPDATETIMER 5 * 1000 + +#define SPACING 8 + +#define EXCELLENT_SIGNAL 80 +#define GOOD_SIGNAL 55 +#define OK_SIGNAL 30 +#define LOW_SIGNAL 5 +#define NONE_SIGNAL 0 + +#define SIGNAL_EXCELLENT 1 +#define SIGNAL_GOOD 2 +#define SIGNAL_OK 3 +#define SIGNAL_LOW 4 +#define SIGNAL_NONE 5 +#define ICON_SIZE 16,16 + +const QString WIRELESS_SWITCH = "wirelessswitch"; +const QByteArray GSETTINGS_SCHEMA = "org.ukui.kylin-nm.switch"; + +const QString KWifiSymbolic = "network-wireless-signal-excellent"; +const QString KWifiLockSymbolic = "network-wireless-secure-signal-excellent"; +const QString KWifiGood = "network-wireless-signal-good"; +const QString KWifiLockGood = "network-wireless-secure-signal-good"; +const QString KWifiOK = "network-wireless-signal-ok"; +const QString KWifiLockOK = "network-wireless-secure-signal-ok"; +const QString KWifiLow = "network-wireless-signal-low"; +const QString KWifiLockLow = "network-wireless-secure-signal-low"; +const QString KWifiNone = "network-wireless-signal-none"; +const QString KWifiLockNone = "network-wireless-secure-signal-none"; + +const QString KWifi6Symbolic = "ukui-wifi6-full-symbolic"; +const QString KWifi6PlusSymbolic = "ukui-wifi6+-full-symbolic"; + +const QString KWifi6LockSymbolic = "ukui-wifi6-full-pwd-symbolic"; +const QString KWifi6PlusLockSymbolic= "ukui-wifi6+-full-pwd-symbolic"; + +const QString KWifi6Good = "ukui-wifi6-high-symbolic"; +const QString KWifi6PlusGood = "ukui-wifi6+-high-symbolic"; + +const QString KWifi6LockGood = "ukui-wifi6-high-pwd-symbolic"; +const QString KWifi6PlusLockGood = "ukui-wifi6+-high-pwd-symbolic"; + +const QString KWifi6OK = "ukui-wifi6-medium-symbolic"; +const QString KWifi6PlusOK = "ukui-wifi6-high+-medium-symbolic"; + +const QString KWifi6LockOK = "ukui-wifi6-medium-pwd-symbolic"; +const QString KWifi6PlusLockOK = "ukui-wifi6+-medium-pwd-symbolic"; + +const QString KWifi6Low = "ukui-wifi6-low-symbolic"; +const QString KWifi6PlusLow = "ukui-wifi6+-low-symbolic"; + +const QString KWifi6LockLow = "ukui-wifi6-low-pwd-symbolic"; +const QString KWifi6PlusLockLow = "ukui-wifi6+-low-pwd-symbolic"; + +const QString KWifi6None = "ukui-wifi6-none-symbolic"; +const QString KWifi6PlusNone = "ukui-wifi6+-none-symbolic"; + +const QString KWifi6LockNone = "ukui-wifi6-none-pwd-symbolic"; +const QString KWifi6PlusLockNone = "ukui-wifi6+-none-pwd-symbolic"; + +const QString KLanSymbolic = ":/img/plugins/netconnect/eth.svg"; +const QString NoNetSymbolic = ":/img/plugins/netconnect/nonet.svg"; + +const QString KApSymbolic = "network-wireless-hotspot-symbolic"; + +const QString IsApConnection = "1"; + + +#define ACTIVATING 1 +#define ACTIVATED 2 +#define DEACTIVATING 3 +#define DEACTIVATED 4 + +#define NO_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_MARGINS 0,0,0,8 + +bool intThan(int sign1, int sign2) +{ + return sign1 < sign2; +} + +void WlanConnect::showDesktopNotify(const QString &message) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QList args; + args<<(tr("ukui control center")) + <<((unsigned int) 0) + <load("/usr/share/kylin-nm/wlanconnect/" + QLocale::system().name()); + QApplication::installTranslator(translator); + + pluginName = tr("WlanConnect"); + pluginType = NETWORK; +} + +WlanConnect::~WlanConnect() +{ + if (!m_firstLoad) { + delete ui; + ui = nullptr; + } + delete m_interface; +} + +QString WlanConnect::plugini18nName() { + return pluginName; +} + +int WlanConnect::pluginTypes() { + return pluginType; +} + +QWidget *WlanConnect::pluginUi() { + if (m_firstLoad) { + m_firstLoad = false; + + ui = new Ui::WlanConnect; + pluginWidget = new QWidget; + pluginWidget->setAttribute(Qt::WA_DeleteOnClose); + ui->setupUi(pluginWidget); + qDBusRegisterMetaType>(); + m_interface = new QDBusInterface("com.kylin.network", "/com/kylin/network", + "com.kylin.network", + QDBusConnection::sessionBus()); + if(!m_interface->isValid()) { + qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message()); + } + initSearchText(); + initComponent(); + } + return pluginWidget; +} + +const QString WlanConnect::name() const { + + return QStringLiteral("wlanconnect"); +} + +bool WlanConnect::isEnable() const +{ + return true; +} + + +bool WlanConnect::isShowOnHomePage() const +{ + return true; +} + +QIcon WlanConnect::icon() const +{ + return QIcon::fromTheme("network-wireless-signal-excellent-symbolic"); +} + +QString WlanConnect::translationPath() const +{ + return "/usr/share/kylin-nm/wlanconnect/%1.ts"; +} + +void WlanConnect::initSearchText() { + //~ contents_path /wlanconnect/Advanced settings" + ui->detailBtn->setText(tr("Advanced settings")); + ui->titleLabel->setText(tr("WLAN")); + //~ contents_path /wlanconnect/open + ui->openLabel->setText(tr("open")); +} + +bool WlanConnect::eventFilter(QObject *w, QEvent *e) { + if (e->type() == QEvent::Enter) { + if (w->findChild()) + w->findChild()->setStyleSheet("QWidget{background: palette(button);border-radius:4px;}"); + } else if (e->type() == QEvent::Leave) { + if (w->findChild()) + w->findChild()->setStyleSheet("QWidget{background: palette(base);border-radius:4px;}"); + } + + if (w == m_wifiSwitch) { + if (e->type() == QMouseEvent::MouseButtonRelease) { + if (!getSwitchBtnEnable()) { + showDesktopNotify(tr("No wireless network card detected")); + } else { + m_interface->call(QStringLiteral("setWirelessSwitchEnable"), !getSwitchBtnState()); + return true; + } + } + } + + return QObject::eventFilter(w,e); +} + +void WlanConnect::initComponent() { + m_wifiSwitch = new KSwitchButton(pluginWidget); + ui->openWIifLayout->addWidget(m_wifiSwitch); + ui->openWIifLayout->setContentsMargins(0,0,8,0); + ui->detailLayOut_3->setContentsMargins(MAIN_LAYOUT_MARGINS); + ui->verticalLayout_3->setContentsMargins(NO_MARGINS); + ui->verticalLayout_3->setSpacing(8); + ui->availableLayout->setSpacing(SPACING); + + m_wifiSwitch->installEventFilter(this); + + //开关 + initSwtichState(); + + //获取设备列表 + getDeviceList(deviceList); + if (deviceList.isEmpty()) { + qDebug() << "[WlanConnect]no device exist when init, set switch disable"; + setSwitchBtnState(false); + setSwitchBtnEnable(false); + } + initNet(); + + if (!getSwitchBtnState() || deviceList.isEmpty() || !m_interface->isValid()) { + hideLayout(ui->availableLayout); + } + + // 有线网络断开或连接时刷新可用网络列表 + connect(m_interface, SIGNAL(wlanactiveConnectionStateChanged(QString, QString, QString, int)), this, SLOT(onActiveConnectionChanged(QString, QString, QString, int)), Qt::QueuedConnection); + //无线网络新增时添加网络 + connect(m_interface, SIGNAL(wlanAdd(QString, QStringList)), this, SLOT(onNetworkAdd(QString, QStringList)), Qt::QueuedConnection); + //删除无线网络 + connect(m_interface, SIGNAL(wlanRemove(QString, QString)), this, SLOT(onNetworkRemove(QString, QString)), Qt::QueuedConnection); + //网卡插拔处理 + connect(m_interface, SIGNAL(deviceStatusChanged()), this, SLOT(onDeviceStatusChanged()), Qt::QueuedConnection); + //信号更新处理 改为每过固定时间 主动获取 +// connect(m_interface, SIGNAL(signalStrengthChange(QString, QString, int)), this, SLOT(updateStrengthList(QString, QString, int))); + //网卡name处理 + connect(m_interface, SIGNAL(deviceNameChanged(QString, QString, int)), this, SLOT(onDeviceNameChanged(QString, QString, int)), Qt::QueuedConnection); + connect(m_interface, SIGNAL(wirelessSwitchBtnChanged(bool)), this, SLOT(onSwitchBtnChanged(bool)), Qt::QueuedConnection); + + connect(m_interface, SIGNAL(timeToUpdate()), this, SLOT(updateList()), Qt::QueuedConnection); + //高级设置 + connect(ui->detailBtn, &QPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + runExternalApp(); + }); + + //定时20s扫描 + m_scanTimer = new QTimer(this); + m_scanTimer->start(SCANTIMER); + connect(m_scanTimer, &QTimer::timeout, this, &WlanConnect::reScan, Qt::QueuedConnection); + reScan(); + +// m_updateTimer = new QTimer(this); +// m_updateTimer->start(UPDATETIMER); + +} + +void WlanConnect::reScan() +{ + qDebug() << "time to rescan wifi"; + if (m_interface->isValid()) { + qDebug() << "[WlanConnect]call reScan" << __LINE__; + m_interface->call("reScan"); + qDebug() << "[WlanConnect]call reScan respond" << __LINE__; + } +} + +//更新列表顺序 +void WlanConnect::updateList() +{ + if (!getSwitchBtnState()) { + return; + } + qDebug() << "update list"; + if(m_interface->isValid()) { + qDebug() << "[WlanConnect]call getWirelessList" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getWirelessList")); + qDebug() << "[WlanConnect]call getWirelessList respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "getWirelessList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + QMap> variantList; + dbusArg >> variantList; + + if (variantList.size() == 0) { + qDebug() << "[WlanConnect]updateList " << " list empty"; + return; + } + + QMap>::iterator iter; + + for (iter = variantList.begin(); iter != variantList.end(); iter++) { + if (deviceFrameMap.contains(iter.key())) { + QVector wifiList = iter.value(); + resortWifiList(deviceFrameMap[iter.key()], wifiList); + deviceFrameMap[iter.key()]->filletStyleChange(); + } + } + } +} + +void WlanConnect::resortWifiList(ItemFrame *frame, QVector list) +{ + if(nullptr == frame || frame->lanItemLayout->count() <= 0 || list.isEmpty()) { + return; + } + qDebug() << "begin resort" << frame->deviceFrame->deviceLabel->text(); + + int frameIndex = 0; + int listIndex = 1; + if (list.at(0).size() > 1) { + if (frame->itemMap.contains(list.at(0).at(0))) { + frame->lanItemLayout->removeWidget(frame->itemMap[list.at(0).at(0)]); + frame->lanItemLayout->insertWidget(0, frame->itemMap[list.at(0).at(0)]); + qDebug() << "active resort insert position 0" << list.at(0).at(0); + frame->itemMap[list.at(0).at(0)]->isAcitve = true; + frame->itemMap[list.at(0).at(0)]->uuid = list.at(0).at(3); + frame->uuid = list.at(0).at(3); + frame->itemMap[list.at(0).at(0)]->statusLabel->setText(tr("connected")); + if (list.at(0).size() > 5) { + updateIcon(frame->itemMap[list.at(0).at(0)], list.at(0).at(1), list.at(0).at(2), list.at(0).at(4), list.at(0).at(5).toInt()); + } + frameIndex ++; + } + } else { + qDebug() << " no active connection when resort"; + if (!frame->uuid.isEmpty()) { + QMap::iterator itemIter; + for (itemIter = frame->itemMap.begin(); itemIter != frame->itemMap.end(); itemIter++) { + if (itemIter.value()->uuid == frame->uuid ) { + WlanItem * item= nullptr; + item = itemIter.value(); + qDebug() << "a active connect missing when resort"; + itemIter.value()->uuid.clear(); + itemActiveConnectionStatusChanged(item, DEACTIVATED); + break; + } + } + } + frame->uuid.clear(); + } + + for ( ; listIndex < list.size(); listIndex++) { + if (frameIndex > frame->lanItemLayout->count() - 1) { + return; + } + if (frame->itemMap.contains(list.at(listIndex).at(0))) { + frame->lanItemLayout->removeWidget(frame->itemMap[list.at(listIndex).at(0)]); + frame->lanItemLayout->insertWidget(frameIndex, frame->itemMap[list.at(listIndex).at(0)]); + qDebug() << "custom resort " << list.at(listIndex).at(0) <<" insert position" << frameIndex; + if (frame->itemMap[list.at(listIndex).at(0)]->isAcitve) { + frame->itemMap[list.at(listIndex).at(0)]->isAcitve = false; + frame->itemMap[list.at(listIndex).at(0)]->uuid.clear(); + frame->itemMap[list.at(listIndex).at(0)]->statusLabel->setText(""); + } + if (list.at(listIndex).size() > 4) { + updateIcon(frame->itemMap[list.at(listIndex).at(0)], list.at(listIndex).at(1), list.at(listIndex).at(2), list.at(listIndex).at(3), list.at(listIndex).at(4).toInt()); + } + frameIndex++; + } else { + qDebug() << "not find " << list.at(listIndex).at(0) << " in current list, ignore"; + } + } + qDebug() << "resort finish"; +} + +void WlanConnect::updateIcon(WlanItem *item, QString signalStrength, QString security, QString isApConnection, int category) +{ + qDebug() << "updateIcon" << item->titileLabel->text(); + + int sign = setSignal(signalStrength); + bool isLock = true; + if (security.isEmpty()) { + isLock = false; + } else { + isLock = true; + } + + QString iconamePath; + if (isApConnection == IsApConnection) { + iconamePath = KApSymbolic; + } else { + iconamePath = wifiIcon(isLock, sign, category); + } + QIcon searchIcon = QIcon::fromTheme(iconamePath); + if (iconamePath != KLanSymbolic && iconamePath != NoNetSymbolic) { + item->iconLabel->setProperty("useIconHighlightEffect", 0x10); + } + item->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(ICON_SIZE)))); + qDebug() << "updateIcon" << item->titileLabel->text() << " finish"; +} + +//wifi strength update +//void WlanConnect::updateStrengthList(QString deviceName, QString ssid, int strength) +//{ +// return; +// if(!m_wifiSwitch->isChecked()) { +// return; +// } +// qDebug()<<"[WlanConnect]Update wireless network signal strength:" << deviceName <::iterator iters; +// for (iters = deviceWlanlistInfo.deviceLayoutMap.begin(); iters != deviceWlanlistInfo.deviceLayoutMap.end(); iters++) { +// if (iters.key() == deviceName) { +// qDebug() << "[WlanConnect] updateStrengthList find " << deviceName << " in deviceWlanlistInfo.deviceLayoutMap"; +// if (iters.value()->lanItemLayout->layout() != NULL) { +// WlanItem* item = nullptr; +// QMap::iterator iter; +// for (iter = deviceWlanlistInfo.wlanItemMap.begin(); iter != deviceWlanlistInfo.wlanItemMap.end(); iter++) { +// if (iter.key() == ssid) { +// item = iter.value(); +// break; +// } +// } +// isLock = item->isLock; +// //remove the item from layout +// iters.value()->lanItemLayout->removeWidget(item); +// //get position +// int index = sortWlanNet(deviceName,ssid, QString::number(strength)); +// //add the item to new position +// qDebug()<<"更新后位置:"<iconLabel->setProperty("useIconHighlightEffect", 0x10); +// } +// item->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(24, 24)))); + +// iters.value()->lanItemLayout->insertWidget(index, item); +// } +// } +// } +//} + +//device add or remove================================= +void WlanConnect::onDeviceStatusChanged() +{ + qDebug()<<"[WlanConnect]onDeviceStatusChanged"; + QEventLoop eventloop; + QTimer::singleShot(300, &eventloop, SLOT(quit())); + eventloop.exec(); + QStringList list; + getDeviceList(list); + + QStringList removeList,addList; + + //remove的设备 + for (int i = 0; i< deviceList.size(); ++i) { + if (!list.contains(deviceList.at(i))) { + qDebug() << "[WlanConnect]onDeviceStatusChanged " << deviceList.at(i) << "was removed"; + removeList << deviceList.at(i); + } + } + + //add的设备 + for (int i = 0; i< list.size(); ++i) { + if (!deviceList.contains(list.at(i))) { + qDebug() << "[WlanConnect]onDeviceStatusChanged " << list.at(i) << "was add"; + addList << list.at(i); + } + } + + for (int i = 0; i < removeList.size(); ++i) { + removeDeviceFrame(removeList.at(i)); + } + + for (int i = 0; i < addList.size(); ++i) { + addDeviceFrame(addList.at(i)); + } + deviceList = list; + if (deviceList.isEmpty()) { + setSwitchBtnState(false); + setSwitchBtnEnable(false); + } else { + setSwitchBtnEnable(true); + initSwtichState(); + } + + if (!getSwitchBtnState()) { + hideLayout(ui->availableLayout); + } else { + showLayout(ui->availableLayout); + } +} + +void WlanConnect::onDeviceNameChanged(QString oldName, QString newName, int type) +{ + if (WIRELESS_TYPE != type || !deviceFrameMap.contains(oldName) || !deviceList.contains(oldName)) { + qDebug() << "[WlanConnect]onDeviceNameChanged no such device " << oldName; + return; + } + + if (deviceFrameMap.contains(newName) && deviceList.contains(newName)) { + qDebug() << "[WlanConnect]onDeviceNameChanged already has device " << newName; + return; + } + + qDebug() << "[WlanConnect]onDeviceNameChanged " << oldName << "change to" << newName; + + //shan chu chong jian + removeDeviceFrame(oldName); + removeDeviceFrame(newName); + + getDeviceList(deviceList); + if (deviceList.contains(newName)) { + addDeviceFrame(newName); + initNetListFromDevice(newName); + } +} + +void WlanConnect::onSwitchBtnChanged(bool state) +{ + if (getSwitchBtnState() == state) { + return; + } + + setSwitchBtnState(state); + if (!getSwitchBtnState()) { + hideLayout(ui->availableLayout); + } else { + showLayout(ui->availableLayout); + } +} + +//activeconnect status change +void WlanConnect::onActiveConnectionChanged(QString deviceName, QString ssid, QString uuid, int status) +{ + if (!getSwitchBtnState()) { + return; + } + if (uuid.isEmpty()) { + return; + } + WlanItem * item= nullptr; + //device ssid 有可能均为空 + if (deviceName.isEmpty() || ssid.isEmpty()) { + if (status == ACTIVATING || status == ACTIVATED) { + return; + } + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (uuid == iter.value()->uuid) { + QMap::iterator itemIter; + for (itemIter = iter.value()->itemMap.begin(); itemIter != iter.value()->itemMap.end(); itemIter++) { + if (itemIter.value()->uuid == uuid ) { + item = itemIter.value(); + if (status == DEACTIVATED) { + itemIter.value()->uuid.clear(); + } + break; + } + } + break; + } + } + } else { + if (!deviceFrameMap.contains(deviceName)) { + return; + } + for (int i = 0; i < deviceFrameMap[deviceName]->itemMap.size(); ++i) { + if (deviceFrameMap[deviceName]->itemMap.contains(ssid)) { + item = deviceFrameMap[deviceName]->itemMap[ssid]; + if (status == ACTIVATED || status == ACTIVATING) { + deviceFrameMap[deviceName]->itemMap[ssid]->uuid = uuid; + deviceFrameMap[deviceName]->uuid = uuid; + if (status == ACTIVATED) { + deviceFrameMap[deviceName]->lanItemLayout->removeWidget(item); + deviceFrameMap[deviceName]->lanItemLayout->insertWidget(0,item); + deviceFrameMap[deviceName]->filletStyleChange(); + } + } else if (status == DEACTIVATED) { + deviceFrameMap[deviceName]->itemMap[ssid]->uuid.clear(); + deviceFrameMap[deviceName]->uuid.clear(); + //todo 断开后排序 现在等下次更新列表 自动排序 + } + break; + } + } + } + + if (nullptr != item) { + itemActiveConnectionStatusChanged(item, status); + } +} + +//wifi add=============================================================== +void WlanConnect::onNetworkAdd(QString deviceName, QStringList wlanInfo) +{ + qDebug()<<"[WlanConnect]onNetworkAdd "<< deviceName << " " << wlanInfo; + if(!getSwitchBtnState() || deviceName.isEmpty()) { + return; + } + + if (!deviceList.contains(deviceName)) { + qDebug() << "[WlanConnect]onNetworkAdd not contain " << deviceName << "then add"; + deviceList.append(deviceName); + addDeviceFrame(deviceName); + onNetworkAdd(deviceName, wlanInfo); + return; + } + + bool isLock = true; + if (wlanInfo.at(2) == "") { + isLock = false; + } else { + isLock = true; + } + + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (deviceName == iter.key()) { + addOneWlanFrame(iter.value(), deviceName, wlanInfo.at(0), wlanInfo.at(1), "", isLock, false, WIRELESS_TYPE, wlanInfo.at(3), wlanInfo.at(3).toInt()); + } + } + +} + +//wifi remove ============================================================= +void WlanConnect::onNetworkRemove(QString deviceName, QString wlannName) +{ + //开关已关闭 忽略 +// if (!m_wifiSwitch->isChecked()) { +// qDebug() << "[WlanConnect]recieve network remove,but wireless switch is off"; +// return; +// } + //当前无此设备 忽略 + if (deviceName.isEmpty() || !deviceFrameMap.contains(deviceName)) { + qDebug() << "[WlanConnect]recieve network remove,but no such device:" << deviceName; + return; + } + qDebug()<<"[WlanConnect]Wifi remove device:" << deviceName << ",wlan name:" << wlannName; + QMap::iterator iter; + for (iter = deviceFrameMap.begin(); iter != deviceFrameMap.end(); iter++) { + if (deviceName == iter.key()) { + removeOneWlanFrame(iter.value(), deviceName, wlannName); + } + } +} + +//获取设备列表======================================================= +void WlanConnect::getDeviceList(QStringList &list) +{ + if (!m_interface->isValid()) { + return; + } + qDebug() << "[WlanConnect]call getDeviceListAndEnabled" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getDeviceListAndEnabled"),1); + qDebug() << "[WlanConnect]call getDeviceListAndEnabled respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "[WlanConnect]getWirelessDeviceList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + QMap map; + dbusArg >> map; + list = map.keys(); +} + +void WlanConnect::initSwtichState() +{ + if (!m_interface->isValid()) { + return; + } + + QDBusMessage result = m_interface->call("getWirelessSwitchBtnState"); + qDebug() << "[WlanConnect]call getWirelessSwitchBtnState respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "[WlanConnect]getWirelessSwitchBtnState error:" << result.errorMessage(); + return; + } + + bool state = result.arguments().at(0).toBool(); + setSwitchBtnState(state); +} + +//初始化整体列表和单设备列表 +void WlanConnect::initNet() { +// int count = 1; + //先构建每个设备的列表头 + for (int i = 0; i < deviceList.size(); ++i) { + addDeviceFrame(deviceList.at(i)); + } + //再填充每个设备的列表 + for (int i = 0; i < deviceList.size(); ++i) { + initNetListFromDevice(deviceList.at(i)); + } +} + +//初始化设备列表 网卡标号问题? +void WlanConnect::initNetListFromDevice(QString deviceName) +{ + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName; + if (!getSwitchBtnState()) { + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName << " switch off"; + return; + } + if (!deviceFrameMap.contains(deviceName)) { + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName << " not exist"; + return; + } + if (!m_interface->isValid()) { + return; + } + qDebug() << "[WlanConnect]call getWirelessList" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getWirelessList")); + qDebug() << "[WlanConnect]call getWirelessList respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "getWirelessList error:" << result.errorMessage(); + return; + } + auto dbusArg = result.arguments().at(0).value(); + QMap> variantList; + dbusArg >> variantList; + if (variantList.size() == 0) { + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName << " list empty"; + return; + } + QMap>::iterator iter; + + for (iter = variantList.begin(); iter != variantList.end(); iter++) { + if (deviceName == iter.key()) { + QVector wlanListInfo = iter.value(); + //处理列表 已连接 + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName << " acitved wifi " << wlanListInfo.at(0); + addActiveItem(deviceFrameMap[deviceName], deviceName, wlanListInfo.at(0)); + //处理列表 未连接 + for (int i = 1; i < wlanListInfo.length(); i++) { + qDebug() << "[WlanConnect]initNetListFromDevice " << deviceName << " deacitved wifi " << wlanListInfo.at(i); + addCustomItem(deviceFrameMap[deviceName], deviceName, wlanListInfo.at(i)); + } + } + } + return; +} + +//高级设置 +void WlanConnect::runExternalApp() { + QString cmd = "nm-connection-editor"; + QProcess process(this); + process.startDetached(cmd); +} + +//根据信号强度分级+安全性分图标 +QString WlanConnect::wifiIcon(bool isLock, int strength, int category) { + if (category == 0) { + switch (strength) { + case SIGNAL_EXCELLENT: + return isLock ? KWifiLockSymbolic : KWifiSymbolic; + case SIGNAL_GOOD: + return isLock ? KWifiLockGood : KWifiGood; + case SIGNAL_OK: + return isLock ? KWifiLockOK : KWifiOK; + case SIGNAL_LOW: + return isLock ? KWifiLockLow : KWifiLow; + case SIGNAL_NONE: + return isLock ? KWifiLockNone : KWifiNone; + default: + return ""; + } + } else if (category == 1) { + switch (strength) { + case SIGNAL_EXCELLENT: + return isLock ? KWifi6LockSymbolic : KWifi6Symbolic; + case SIGNAL_GOOD: + return isLock ? KWifi6LockGood : KWifi6Good; + case SIGNAL_OK: + return isLock ? KWifi6LockOK : KWifi6OK; + case SIGNAL_LOW: + return isLock ? KWifi6LockLow : KWifi6Low; + case SIGNAL_NONE: + return isLock ? KWifi6LockNone : KWifi6None; + default: + return ""; + } + } else { + switch (strength) { + case SIGNAL_EXCELLENT: + return isLock ? KWifi6PlusLockSymbolic : KWifi6PlusSymbolic; + case SIGNAL_GOOD: + return isLock ? KWifi6PlusLockGood : KWifi6PlusGood; + case SIGNAL_OK: + return isLock ? KWifi6PlusLockOK : KWifi6PlusOK; + case SIGNAL_LOW: + return isLock ? KWifi6PlusLockLow : KWifi6PlusLow; + case SIGNAL_NONE: + return isLock ? KWifi6PlusLockNone : KWifi6PlusNone; + default: + return ""; + } + } +} + +//根据信号强度分级 +int WlanConnect::setSignal(QString lv) { + int signal = lv.toInt(); + int signalLv = 0; + + if (signal > EXCELLENT_SIGNAL) { + signalLv = 1; + } else if (signal > GOOD_SIGNAL) { + signalLv = 2; + } else if (signal > OK_SIGNAL) { + signalLv = 3; + } else if (signal > LOW_SIGNAL) { + signalLv = 4; + } else { + signalLv = 5; + } + return signalLv; +} + +//隐藏 +void WlanConnect::hideLayout(QVBoxLayout * layout) { + for (int i = layout->layout()->count()-1; i >= 0; --i) { + QLayoutItem *it = layout->layout()->itemAt(i); + ItemFrame *itemFrame = qobject_cast(it->widget()); + itemFrame->hide(); + } +} + +//显示 +void WlanConnect::showLayout(QVBoxLayout * layout) { + for (int i = layout->layout()->count()-1; i >= 0; --i) { + QLayoutItem *it = layout->layout()->itemAt(i); + ItemFrame *itemFrame = qobject_cast(it->widget()); + itemFrame->show(); + } +} + +//获取应该插入哪个位置 +int WlanConnect::sortWlanNet(QString deviceName, QString name, QString signal) +{ + qDebug() << "[WlanConnect]call getWirelessList" << __LINE__; + QDBusMessage result = m_interface->call(QStringLiteral("getWirelessList")); + qDebug() << "[WlanConnect]call getWirelessList respond" << __LINE__; + if(result.type() == QDBusMessage::ErrorMessage) + { + qWarning() << "getWirelessList error:" << result.errorMessage(); + return 0; + } + auto dbusArg = result.arguments().at(0).value(); + QMap> variantList; + dbusArg >> variantList; + QMap>::iterator iter; + for (iter = variantList.begin(); iter != variantList.end(); iter++) { + if (deviceName == iter.key()) { + QVector wlanListInfo = iter.value(); + for (int i = 0; i < wlanListInfo.size(); i++) { + if (name == wlanListInfo.at(i).at(0)) { + return i; + } + } + } + } + return 0; +} + +void WlanConnect::activeConnect(QString netName, QString deviceName, int type) { + if (!m_interface->isValid()) { + return; + } + qDebug() << "[WlanConnect]call activateConnect" << __LINE__; + m_interface->call("activateConnect",type, deviceName, netName); + qDebug() << "[WlanConnect]call activateConnect respond" << __LINE__; +} + +void WlanConnect::deActiveConnect(QString netName, QString deviceName, int type) { + if (!m_interface->isValid()) { + return; + } + qDebug() << "[WlanConnect]call deActivateConnect" << __LINE__; + m_interface->call("deActivateConnect",type, deviceName, netName); + qDebug() << "[WlanConnect]call deActivateConnect respond" << __LINE__; +} + + +//处理列表 已连接 +void WlanConnect::addActiveItem(ItemFrame *frame, QString devName, QStringList infoList) +{ + if (frame == nullptr) { + return; + } + if (infoList.size() == 1) { + return; + } + + bool isLock = true; + if (infoList.at(2) == "") { + isLock = false; + } else { + isLock = true; + } + addOneWlanFrame(frame, devName, infoList.at(0), infoList.at(1), infoList.at(3), isLock, true, WIRELESS_TYPE, infoList.at(4), infoList.at(5).toInt()); +} + +//处理列表 未连接 +void WlanConnect::addCustomItem(ItemFrame *frame, QString devName, QStringList infoList) +{ + if (frame == nullptr) { + return; + } + bool isLock = true; + if (infoList.at(2) == "") { + isLock = false; + } else { + isLock = true; + } + addOneWlanFrame(frame, devName, infoList.at(0), infoList.at(1), "", isLock, false, WIRELESS_TYPE, infoList.at(3), infoList.at(4).toInt()); +} + +//增加设备 +void WlanConnect::addDeviceFrame(QString devName) +{ + qDebug() << "[WlanConnect]addDeviceFrame " << devName; + ItemFrame *itemFrame = new ItemFrame(devName, pluginWidget); + ui->availableLayout->addWidget(itemFrame); + itemFrame->deviceFrame->deviceLabel->setText(tr("card")+/*QString("%1").arg(count)+*/":"+devName); + deviceFrameMap.insert(devName, itemFrame); + + connect(itemFrame->addWlanWidget, &AddNetBtn::clicked, this, [=](){ + if (m_interface->isValid()) { + qDebug() << "[NetConnect]call showAddOtherWlanWidget" << devName << __LINE__; + m_interface->call(QStringLiteral("showAddOtherWlanWidget"), devName); + qDebug() << "[NetConnect]call setDeviceEnable Respond" << __LINE__; + } + }); + +} + +//减少设备 +void WlanConnect::removeDeviceFrame(QString devName) +{ + qDebug() << "[WlanConnect]removeDeviceFrame " << devName; + if (deviceFrameMap.contains(devName)) { + ItemFrame *item = deviceFrameMap[devName]; + if (item->lanItemFrame->layout() != NULL) { + QLayoutItem* layoutItem; + while ((layoutItem = item->lanItemFrame->layout()->takeAt(0)) != NULL) { + delete layoutItem->widget(); + delete layoutItem; + item = nullptr; + } + item->itemMap.clear(); + } + delete item; + item = nullptr; + deviceFrameMap.remove(devName); + } +} + +//增加ap +void WlanConnect::addOneWlanFrame(ItemFrame *frame, QString deviceName, QString name, QString signal, QString uuid, bool isLock, bool status, int type, QString isApConnection, int category) +{ + if (nullptr == frame) { + return; + } + + bool bApConnection = (isApConnection == IsApConnection); + + if (frame->itemMap.contains(name)) { + qDebug() << "[WlanConnect]Already exist a wifi " << name << " in " << deviceName; + return; + } + //设置单项的信息 + int sign = setSignal(signal); + WlanItem * wlanItem = new WlanItem(status, isLock, pluginWidget); + QString iconamePath; + if (bApConnection) { + iconamePath = KApSymbolic; + } else { + iconamePath = wifiIcon(isLock, sign, category); + } + if (iconamePath != KLanSymbolic && iconamePath != NoNetSymbolic) { + wlanItem->iconLabel->setProperty("useIconHighlightEffect", 0x10); + } + QIcon searchIcon = QIcon::fromTheme(iconamePath); + wlanItem->iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(ICON_SIZE)))); + wlanItem->titileLabel->setText(name); + if (status) { + wlanItem->statusLabel->setText(tr("connected")); + frame->uuid = uuid; + wlanItem->uuid = uuid; + } else { + wlanItem->statusLabel->setText(""); + } + + connect(wlanItem->infoLabel, &GrayInfoButton::clicked, this, [=]{ + // open detail page + if (!m_interface->isValid()) { + return; + } + qDebug() << "[WlanConnect]call showPropertyWidget" << __LINE__; + m_interface->call(QStringLiteral("showPropertyWidget"), deviceName, name); + qDebug() << "[WlanConnect]call showPropertyWidget respond" << __LINE__; + }); + + connect(wlanItem, &QPushButton::clicked, this, [=] { + if (wlanItem->isAcitve) { + deActiveConnect(name, deviceName, type); + } else { + activeConnect(name, deviceName, type); + } + }); + //记录到deviceFrame的itemMap中 + deviceFrameMap[deviceName]->itemMap.insert(name, wlanItem); + int index; + if (status) { + index = 0; + } else { + index = sortWlanNet(deviceName, name, signal); + } + qDebug()<<"insert " << name << " to " << deviceName << " list, postion " << index; + frame->lanItemLayout->insertWidget(index, wlanItem); + frame->filletStyleChange(); +} + +//减少ap +void WlanConnect::removeOneWlanFrame(ItemFrame *frame, QString deviceName, QString ssid) +{ + if (nullptr == frame) { + return; + } + + if (frame->itemMap.contains(ssid)) { + qDebug() << "[WlanConnect]removeOneWlanFrame " << deviceName << ssid; + frame->lanItemLayout->removeWidget(frame->itemMap[ssid]); + delete frame->itemMap[ssid]; + frame->itemMap.remove(ssid); + frame->filletStyleChange(); + } +} + +void WlanConnect::itemActiveConnectionStatusChanged(WlanItem *item, int status) +{ + if (status == ACTIVATING) { + item->startLoading(); + } else if (status == ACTIVATED) { + item->stopLoading(); + item->statusLabel->clear(); + item->statusLabel->setMinimumSize(36,36); + item->statusLabel->setMaximumSize(16777215,16777215); + item->statusLabel->setText(tr("connected")); + item->isAcitve = true; + } else if (status == DEACTIVATING) { + item->startLoading(); + } else if (status == DEACTIVATED) { + item->stopLoading(); + item->statusLabel->clear(); + item->statusLabel->setMinimumSize(36,36); + item->statusLabel->setMaximumSize(16777215,16777215); + item->isAcitve = false; + } +} + diff --git a/plugins/wlanconnect/wlanconnect.h b/plugins/wlanconnect/wlanconnect.h new file mode 100644 index 00000000..8754219f --- /dev/null +++ b/plugins/wlanconnect/wlanconnect.h @@ -0,0 +1,195 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef WLANCONNECT_H +#define WLANCONNECT_H + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "hoverbtn.h" +#include "itemframe.h" +#include "wlanitem.h" +#include "kwidget.h" +#include "kswitchbutton.h" + +using namespace kdk; + +namespace Ui { +class WlanConnect; +} + + +class WlanConnect : public QObject, CommonInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.kycc.CommonInterface") + Q_INTERFACES(CommonInterface) + +public: + WlanConnect(); + ~WlanConnect(); + + QString plugini18nName() Q_DECL_OVERRIDE; + int pluginTypes() Q_DECL_OVERRIDE; + QWidget * pluginUi() Q_DECL_OVERRIDE; + const QString name() const Q_DECL_OVERRIDE; + bool isShowOnHomePage() const Q_DECL_OVERRIDE; + QIcon icon() const Q_DECL_OVERRIDE; + bool isEnable() const Q_DECL_OVERRIDE; + QString translationPath() const Q_DECL_OVERRIDE; + +private: + void initComponent(); + void runExternalApp(); + void initSearchText(); + + void showDesktopNotify(const QString &message); + + //点击item 连接/断开 + void activeConnect(QString netName, QString deviceName, int type); + void deActiveConnect(QString netName, QString deviceName, int type); + + + + int sortWlanNet(QString deviceName, QString name, QString signal); + void updateIcon(WlanItem *item, QString signalStrength, QString security, QString isApConnection, int category); + void resortWifiList(ItemFrame *frame, QVector list); + + + //单wifi图标 + int setSignal(QString lv); + QString wifiIcon(bool isLock, int strength, int category); + + + //开关相关 + void hideLayout(QVBoxLayout * layout); + void showLayout(QVBoxLayout * layout); + + + //获取设备列表 + void getDeviceList(QStringList &list); + //初始化设备wifi列表 + void initNet(); + void initNetListFromDevice(QString deviceName); + //处理列表 已连接 + void addActiveItem(ItemFrame *frame, QString devName, QStringList infoList); + //处理列表 未连接 + void addCustomItem(ItemFrame *frame, QString devName, QStringList infoList); + //增加设备 + void addDeviceFrame(QString devName); + //减少设备 + void removeDeviceFrame(QString devName); + //增加ap + void addOneWlanFrame(ItemFrame *frame, QString deviceName, QString name, QString signal, QString uuid, bool isLock, bool status, int type, QString isApConnection, int category); + //减少ap + void removeOneWlanFrame(ItemFrame *frame, QString deviceName, QString ssid); + + + //单个wifi连接状态变化 + void itemActiveConnectionStatusChanged(WlanItem *item, int status); + + void initSwtichState(); + inline void setSwitchBtnEnable(bool state) { + if (m_wifiSwitch != nullptr) { + m_wifiSwitch->setCheckable(state); + } + } + inline bool getSwitchBtnEnable() { + if (m_wifiSwitch != nullptr) { + return m_wifiSwitch->isCheckable(); + } + } + + inline void setSwitchBtnState(bool state) { + if (m_wifiSwitch != nullptr) { + m_wifiSwitch->blockSignals(true); + m_wifiSwitch->setChecked(state); + m_wifiSwitch->blockSignals(false); + } + } + inline bool getSwitchBtnState() { + if (m_wifiSwitch != nullptr) { + return m_wifiSwitch->isChecked(); + } + } + + +protected: + bool eventFilter(QObject *w,QEvent *e); + +private: + Ui::WlanConnect *ui; + + QString pluginName; + int pluginType; + QWidget *pluginWidget; + + QDBusInterface *m_interface = nullptr; + + //设备列表 + QStringList deviceList; + //设备名 + 单设备frame + QMap deviceFrameMap; + + //QVector wlanSignalList; +// DeviceWlanlistInfo deviceWlanlistInfo; + + QTimer * m_scanTimer = nullptr; +// QTimer * m_updateTimer = nullptr; +private: + KSwitchButton *m_wifiSwitch; + bool m_firstLoad; + +private slots: + + void onNetworkAdd(QString deviceName, QStringList wlanInfo); + void onNetworkRemove(QString deviceName, QString wlannName); + void onActiveConnectionChanged(QString deviceName, QString ssid, QString uuid, int status); + + void updateList(); + void onDeviceStatusChanged(); + void onDeviceNameChanged(QString, QString, int); + + void onSwitchBtnChanged(bool); + + void reScan(); + + +}; +#endif // WLANCONNECT_H diff --git a/plugins/wlanconnect/wlanconnect.pro b/plugins/wlanconnect/wlanconnect.pro new file mode 100644 index 00000000..0864f9f6 --- /dev/null +++ b/plugins/wlanconnect/wlanconnect.pro @@ -0,0 +1,54 @@ +QT += widgets network dbus gui core +TEMPLATE = lib +CONFIG += plugin + +include(../component/drownlabel.pri) +include(../component/addbtn.pri) + +TARGET = $$qtLibraryTarget(wlanconnect) +DESTDIR = ../.. +target.path = $$[QT_INSTALL_LIBS]/ukui-control-center +trans.files = translations/* +trans.path = /usr/share/kylin-nm/wlanconnect/ + +INCLUDEPATH += \ + $$PROJECT_COMPONENTSOURCE \ + $$PROJECT_ROOTDIR \ + /usr/include/ukcc/interface \ + /usr/include/ukcc/widgets + +LIBS += -L$$[QT_INSTALL_LIBS] -lgsettings-qt -lukcc + +CONFIG += c++11 \ + link_pkgconfig \ + +PKGCONFIG += gsettings-qt \ + kysdk-qtwidgets \ + +#DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + deviceframe.cpp \ +# drownlabel.cpp \ + itemframe.cpp \ + wlanconnect.cpp \ + wlanitem.cpp + +HEADERS += \ + deviceframe.h \ +# drownlabel.h \ + itemframe.h \ + wlanconnect.h \ + wlanitem.h + +FORMS += \ + wlanconnect.ui + +INSTALLS += target \ + trans + +TRANSLATIONS += \ + translations/zh_CN.ts \ + translations/tr.ts \ + translations/bo.ts \ + translations/bo_CN.ts diff --git a/plugins/wlanconnect/wlanconnect.ui b/plugins/wlanconnect/wlanconnect.ui new file mode 100644 index 00000000..fa8cfe41 --- /dev/null +++ b/plugins/wlanconnect/wlanconnect.ui @@ -0,0 +1,192 @@ + + + WlanConnect + + + + 0 + 0 + 885 + 700 + + + + WlanConnect + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + WLAN + + + true + + + + + + + 1 + + + 0 + + + + + + 0 + 60 + + + + + 16777215 + 50 + + + + QFrame::Box + + + + 18 + + + 0 + + + 9 + + + 0 + + + + + 16 + + + + + + 118 + 0 + + + + open + + + + + + + Qt::Horizontal + + + + 523 + 20 + + + + + + + + + + + + + + + + + 1 + + + + + + + 8 + + + + + + 120 + 36 + + + + + 16777215 + 36 + + + + Advanced settings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + TitleLabel + QLabel +
titlelabel.h
+
+
+ + +
diff --git a/plugins/wlanconnect/wlanitem.cpp b/plugins/wlanconnect/wlanitem.cpp new file mode 100644 index 00000000..01d8b269 --- /dev/null +++ b/plugins/wlanconnect/wlanitem.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wlanitem.h" +#include +#define FRAME_SPEED 150 +#define LIMIT_TIME 60*1000 +#define TOTAL_PAGE 8 +#define RADIUS 6.0 + +#define THEME_QT_SCHEMA "org.ukui.style" +#define MODE_QT_KEY "style-name" + +WlanItem::WlanItem(bool bAcitve, bool isLock, QWidget *parent) + : isAcitve(bAcitve), isLock(isLock), QPushButton(parent) +{ + this->setMinimumSize(550, 58); + this->setProperty("useButtonPalette", true); + this->setFlat(true); + QPalette pal = this->palette(); + QColor color = pal.color(QPalette::Button); + color.setAlphaF(0.5); + pal.setColor(QPalette::Button, color); + this->setPalette(pal); + QHBoxLayout *mLanLyt = new QHBoxLayout(this); + mLanLyt->setContentsMargins(16,0,16,0); + mLanLyt->setSpacing(16); + iconLabel = new QLabel(this); + titileLabel = new FixLabel(this); + statusLabel = new QLabel(this); + statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); +// statusLabel->setMinimumSize(36,36); + infoLabel = new GrayInfoButton(this); + mLanLyt->addWidget(iconLabel); + mLanLyt->addWidget(titileLabel,Qt::AlignLeft); + mLanLyt->addStretch(); + mLanLyt->addWidget(statusLabel); + mLanLyt->addWidget(infoLabel); + + loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic")); + + waitTimer = new QTimer(this); + connect(waitTimer, &QTimer::timeout, this, &WlanItem::updateIcon); + +} + +WlanItem::~WlanItem() +{ + +} + +void WlanItem::updateIcon() +{ + if (currentIconIndex > 6) { + currentIconIndex = 0; + } + statusLabel->setPixmap(loadIcons.at(currentIconIndex).pixmap(16,16)); + currentIconIndex ++; +} + +void WlanItem::startLoading() +{ + waitTimer->start(FRAME_SPEED); + loading = true; +} + +void WlanItem::stopLoading(){ + waitTimer->stop(); + loading = false; +} + +void WlanItem::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + painter.setBrush(pal.color(QPalette::Base)); + + QRect rect = this->rect(); + +#if 0 + if (!useHalfFillet) { + painter.drawRect(rect); + } else { + QPainterPath path; +// path.addRoundedRect (rect, RADIUS, RADIUS); +// QRect temp_rect(rect.left(), rect.top(), rect.width(), rect.height()/2); +// path.addRect(temp_rect); + //设置起点 + path.moveTo(rect.topLeft().x(), rect.topLeft().y()); + path.lineTo(rect.bottomLeft().x(), rect.bottomLeft().y() - RADIUS); + //绘制圆角 圆弧以外切圆的270度位置为起点,逆时针画圆弧运行90度结束 + path.arcTo(QRect(QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 180, 90); + path.lineTo(rect.bottomRight().x() - RADIUS, rect.bottomRight().y()); + //画圆弧 + path.arcTo(QRect(QPoint(rect.bottomRight().x() - (RADIUS * 2), rect.bottomRight().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 270, 90); + path.lineTo(rect.topRight()); + path.lineTo(rect.topLeft()); + painter.drawPath(path); + } +#endif + + painter.drawRect(rect); + QPushButton::paintEvent(event); +} diff --git a/plugins/wlanconnect/wlanitem.h b/plugins/wlanconnect/wlanitem.h new file mode 100644 index 00000000..035daccf --- /dev/null +++ b/plugins/wlanconnect/wlanitem.h @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef WLANITEM_H +#define WLANITEM_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fixlabel.h" +//#include "infobutton.h" +#include "../component/AddBtn/grayinfobutton.h" + +class WlanItem : public QPushButton +{ +public: + WlanItem(bool bAcitve, bool isLock, QWidget *parent = nullptr); + ~WlanItem(); +public: + QLabel * iconLabel = nullptr; + GrayInfoButton * infoLabel = nullptr; + FixLabel * titileLabel = nullptr; + QLabel * statusLabel = nullptr; + QString uuid = ""; + + void setHalfFillet(bool flag) {useHalfFillet = flag; repaint();} +public: + void startLoading(); + void stopLoading(); + bool isAcitve = false; + bool loading = false; + bool isLock = false; + + + +protected: + void paintEvent(QPaintEvent *event); + +private: + QTimer *waitTimer = nullptr; + QGSettings *themeGsettings = nullptr; + bool useHalfFillet = false; + QList loadIcons; + int currentIconIndex=0; + +private slots: + void updateIcon(); + +}; + +#endif // WLANITEM_H diff --git a/res.qrc b/res.qrc new file mode 100644 index 00000000..7646d2b3 --- /dev/null +++ b/res.qrc @@ -0,0 +1 @@ + diff --git a/res/g/close_black.png b/res/g/close_black.png new file mode 100644 index 0000000000000000000000000000000000000000..237e555213079ed8a44c34bd702e94bf8999d310 GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3Q#@T9Lp(a)PCm$aK!L|~|6JX7 ziRzoHU*w4$Z02oKd$3fMziQ>d^he@-k1hVUc1Q^>y(SeFAOG6)7Nbm?=Uj%O9>b5V zANBiZ?R^wdhxDIGZJktT*?6`2Rt#2l<1Kr2q>FVdQ&MBb@ E0JbGncmMzZ literal 0 HcmV?d00001 diff --git a/res/g/close_white.png b/res/g/close_white.png new file mode 100644 index 0000000000000000000000000000000000000000..0943a4bb87ef3488385d4707b140c5a951fc95c1 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3@t!V@As(G?FFSHI81T4UJUF@P zzjseZNRQ$LS0}HT>~|wx=r43~Nr|tSqawJby8k7!1Uvi3^7TqGN6&6w^}+s$UXbL! zV|QPq%l-`axn}!n+VQL3tX%_z{rS5))-WDm4HDBb@?X&K7iblOr>mdKI;Vst0D5XS AbpQYW literal 0 HcmV?d00001 diff --git a/res/g/down_arrow.png b/res/g/down_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c7a343b36b90adec3fa8dbba3bc48ff71c181568 GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)Q!3HEdXMMW?q%1sL978x}#`bvfF(~jbrT_YB zC&Pa&;|WvZ=G}{Du`o=%s41GDE*_})V9h7C2Gh3ZiCs)rik}|Wxx80o=2z)yeM}Q)7{6;vDQqZnMg~r~97{yydLQ)bE))v1LL)_jHC9NF>)m^BLVM@+T#IoT z=v>fbMx9xdY*|hC!;iR#II=_|Y}N_?xJ5UH#7RQ3B`#U~SR%{Rxwk-_e;D87a_{rp z^Lw7(^K}QB8td|Mi*gYJ$@ABHo8fyId~z&i1VQVk8csl=Q1^xO&5ESQc?}@dq7nv} zKf-r_X26R*J10N|f*3!NgCRW>Xy61TV&&5|)en#^?}lckPWv3mcGnbHyry?Kat)i@vSrJl;oKjF z0m*#v@w-ipEBlB05@`PR?AGjK!R&$eEMgnd^4Ht-Gw48Y$>68oPWCkzicaT<*U^VM zcIEq2O3Y5x{rl`mK~`$z@t#DY@X%`aV{`x9^i*h*Y2D4NmWf+;@5(zAC0=|gQR(R& zLRQ^)^Oyyl%{@Hf$tv%iykxljyXOv?YVG~IFn=RDv^4l@4tB%D-LsDi>YC~g&b%== zg6>@V}O-D&9mpkeiS{PeFmAlJ zZ%i#Pg}1lY7a2>`b>m3;9cpaWe9cE8Kb7SUO2|-Qeth=9^tR;LAB^{cnAx{!4YFcv W=xE!cJr~pePrt9x`&CW*-v0n!l=BGy literal 0 HcmV?d00001 diff --git a/res/h/no-pwd-wifi.png b/res/h/no-pwd-wifi.png new file mode 100644 index 0000000000000000000000000000000000000000..dbec54a3af0844bb65373f4cf2204601d77d81ea GIT binary patch literal 1643 zcmV-x29)`UP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+P#)xlG`8*h5zdmJpz&d!EvxLGrd8N--k_{#L1@X zWT$3gu!1G=K0!jupWlss;S$G*e6SRAj1HI2K1;zMx$W9|c7DB&2X`6V*=hd*Zk?jn z?J+K6et|t)Uob!H)4iQ+9)8kr#Jl75(jK{w>qv4qQrYZ0o+*zPO1xRl_{com4(G>b zZxEvf_){TSl+~?w*&->j(5wahb{FXu#WwYF@lD?SqBiepiirK}@NoFJ#JuSGP&Ctz%A z%V^0JH-lQmQYUf~9x@9QZ|u2p;l|6_&pabVFN+v@ky&)LB{j)1uTXq%+{6fEswS|S zK~7j0Mb!AI=3gc2%* z?c+lTF<3|;hY~gV7-EbT`#Dui&0DZ&X34UZq{*j{VzQJ{P9;lL9AklU%$8HmxfBE~ zzQ9+(`~t%ylTLmLQ=Du{Q=ZC<@|pb{<~ZA&<~)}wRV$7FsK)i5|+5w zl9s%bhFWXddP5TxaI8D5(ZPmZ8I`+=+ppUsyupo!yn(m)r>Ip5-Rb$Wcf46Xd9)yCL_; z?FqG7*5g)JKz$cNQ=E{B?S~0VDw0b7U3#mhcVGOzqc)vNlAiiVr}JtweJalA=|zxq zX1Vke%j)jwvt?bw(mS-CWliT{Ki7_ah8e`Z@&6>N?~|j?!9Uc|H^9HDqj&4(_!Yff zh6lIwUip1pM;|TgADi|?J~!?zR(fBR<6e7RhEHGmDx>FS@^kM<0dOCdq zeYk0V;#cI~+5FGL|9jayX!OAuaC*~zEjIq`WcmwyL(y25*2Dn-00D$)LqkwWLqi~N za&Km7Y-IodD3N`UJxIeq9K~N#OI0ckb`WvMP@OD@Uv$(e6rn<>6nNgNw7S4z7YA_yOYL>ZIr*CH}7|w21NGxF7HCJ?`ECLcPp1t7{z4blXfN z;$kMdDh6NC0|5a{BPKJ;n3JR=Jjd5Pe0;r&@+|Lje~vyiXEDGh63;Tjw23!}XEtqv z^FDEy6=jw9oOsNn3lcwaU2*x1bD_xs&kURC)I4#RSS)m~(!s1~YQ$5-5mnPEU&y$u za^B*sm8-0EPyWJCPG4E(I?Z7uu!to{5TT%o63Va9w{N zIRg5(fs5<5rtATiJHX(RA)9hj^3xRZdEotwz9|a~+ycF8Zf~u9oIU_)>MD5y92^3p z1VyY4_ zG}IO#3mAduf=4IUTd`Pl%Eww>c8PtZW;EhbD_W8cMi5u-Ale;FtFtvVvvs^09$L9w zt5{N&6eWE~IvLIj39#EzkergG=wSQac5RVNZUU3@hi3_jAEEg=Kz?;A9N!Jh=4bLF ple9dP_YlGl&`J7rwY>V9^#`z*R8XiZJfHvo002ovPDHLkV1n_*0C)fZ literal 0 HcmV?d00001 diff --git a/res/h/right-pwd.png b/res/h/right-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbc00d18e3edae496bed96128b6fef1e1ff046f GIT binary patch literal 1398 zcmaJ>ZD<>19KWV9%OdHz&ds)?dR(Vwy34)fa=p7X_VU&)YTB3vTSQCmRDDz3%)O{#BIPQ6# z`~Cj^-~a779_#LMI+`5_f;c0GLUH)5tGsp_g4CpXTDst-$qe_Ky?WBjO9nvvsxAXG zl97f$97yW;=$D`!L26%5C;H9)=re+%XWUW+<1S>fkc}Yi9fho<3@0j?{@ z1ct6b%wZq4E~-BoLxZ{jP_LWC70Sb*ZM>WE@*K?^KxvX<36du$1}7?&5cz!Go%gtPV~C)5o+n6}plKW;@Z7j&N(EfYwN@>JKu$5z zSu?F`XvLx=>tm)5gG$#!$Yi6@O~YDlBT+DAL_x|Dl$#_nnMz!1=$sh`|I64ColA^o z0TBl|eaui`J(8_eGR)n*9aVr(jnHGHVNs-!kgkknfM!NQJ`DbGt7%nWNS;(Bki->` zq;X1OXk6ks1y8bV3=i65hGp2QovrwRFdN`J92cfonxev-KM)RdvSF6>!fG%cf0Y~2 za;Bsypz1pfeQ$8v?#UH`29QkMNa*@VwF_b?-PCg_J&Oi|m8!R)uD-OU>iOLMN}1N9 z4gn+m5>Pu0J%g_0Sx9f8!OO~On?&-stgsvoJdA{MBuT>flO8}OWs>od*aly{D}U>K z3Qu4h*{U2tp-9?Gl3rYqR1T*oz~MYE%Q(+a6zgSaPNEfzfD(yH>)h2!)g#!SmF4DO zz|H1p0S(TR0SD*GyYsu@?3N-Sf1>b{e49^QM63_ah}QZ=i?zNrcG`Jq-g3NbId`9k z6ho&brUaY)kD*E9(Mh%VaXmWGIQRZPh}^Vio~}a&maNxK*Nj?AyDa6Wi>po%S-Ra` zb6paVTJ*VOvHA1jzR`x#H^o)qQX`Lkf9$D!fk(uv6ogIfu333iT(Fg2B)>R1<+QE5 zEG`^VnPn%c_@Do_HL~n)`N1}Qplf=tRzBidY*ZI^x^B$Ab`Tju?LQ+C%_38%CQc(i z-u%jXvQS$-I5D%g^jPh=$Lr5q?Bq;edIfwtvV7fY%9Izm+mh&iJ$EGE&43_ zsiUmL_I|gt-F5j5+pkZYkkH?6*yN6se8DCz-D)UZEUsdSzaBdAX0!N8-5J-zrH?GP zT3ko!T=8PRqjV?mnK%$rCp&v~B(m6*j@ib)?Pbrz^3KRE`-ev@+uyS7n8aF6jWo|) z{$<;WCl&dVVg}9(?r(S?{z2?*@%q1X{T<5+5!0FAHC38(AQw*dwpfD9)yhp633rFi I1_mep0|fTVc>n+a literal 0 HcmV?d00001 diff --git a/res/h/show-pwd.png b/res/h/show-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..08c4de5105349165d8f21927d596272a8fbdbdee GIT binary patch literal 1289 zcmaJ>Z)h837{4^3?NV#wl;PG1FV{LO>~i;B?k;z?X1SWAHnOxOOIZ;+dVk(DM|*ea z-E~QevbOF+gyJ8DP{%$DWatN(AN0dO#7*--ncq}!Q$#Wt4Ag?)5G>3$ZBqB4?BKZf zdG7f=&+qy7zBxJmQg8T3m>`JW>{vRFzkT>U(A`N8flIZ~n^-vPXQutrPSLNZE+R$@ zM?)ZMsdFfgRAYJZTQp1%!3$<#+Mmvyl6A+5s!f|{)hc5&K@2CWWmTU?KG4vdX(!07 z&%Y#rX(Y%qe2&SLQ>bK)t+?p)%6LIvnb#$QOr8Y8RT(?5kgtNOwP1U4H9_w9mGQZ$ zrb)14;?F0@T~gDzNsw|}1o)^x=`bdOxD}hKDQrP`%eJppDcc)pdq^Wscg?bI zIyPu}R5fSGPmq}DZVFa8m)mn}d#ys@lF?PQOv5NcTUIl#9c$0eqyK5_YwZ=5%ZSb+ z&slPH+>hcw8;ooB_&`lV%toGYP23c9A?@f(7P9?pIzi$;QNuK3j*%EcMMX+SMV5jp z$5N^!>QqsPa}tVcoWKcfKl|ZD$i#VxWiwDq57rroU5$TiO) zW7Ksluv2H*+=qi?@Tz1Wfr{}Oq7dR@lon@oN{I1Nj2BeB$i>MP-gu;byK{;)IFE9h zj;uq5}_1dyW5{lj})qRwBNV3=7{xwPdzb7M3fEXsebT!DB2NGz`J*qI|pmatN-*U z1pJB%EFK>l>M2~6BM&g=)A z8?S-4h{k)$W#S-l`@;kE8RgZ!`uWxCPu5P1G{6TJ*RF?Z$snX74@25H@Mqxu<(~Q< z%E!Hb9sOYqT)emLpY3YA49*hu@04Gcw{KI(3<=*$b-}C&Q z-&fu>Wu=8li4zh507=C~=5qcEV{g0!0D<_knH0Yn&siK?1?%E!$p8cLXqIANv6rl3 z${CVgviL`41^}W)kKMsJY$bXp>y?u+8+pj<=g|PnFoyi3a}mQqimCGW46^&*pOirl zZII1X+fbXofN^_@mIj!LrKNV~(nU@kEi>lA86iDS;AJ=xhP>6jpgv@f4f5*wb?jIn zgM%jAB7^LuD2J^K7O(*Zs^tXYRN`8w(aDtrj;e@h5JQzZ1*%mjRS2roql8|qfkTgs z_ZFaC`f{^%$QQpe$lM&~*DDmYwYBnEm7EP!DU>=L&w(j04B;)1;1VB4h7ezH(lCRW z2|5EFKj&e6FvdtyYz=3S@k(EY;Pu;VuZVrYp+xa1Q-nyrLMcZTUT-X}LF*t_&ipUq zjn+Z?50Ulg+1%sOkljE^fe8)W<+IqjkK z1c7Nt21OCA8dD>v7S|z^i>47Zp~W>C%B3S*^f1qx@Jb9*=3}TL`yRq--ip;11Q?QI19q0J9`1rNH_Nd>H|vK51%p+G z*>gQUnyn2^iIwSP)Mh5&`IMop0oDr#^Q`y0K?6o;odiv(5iRbb5K@ElD-D4mIviIy zwK^TDa=Bzfc>1;cz3fx|gpb2NEJv?GDUA}-I1v}-R3S8j(}>RLq!6u2>mq0!NzkZ9 zrr;$iVy*L9D-9p<{TW-n8Vr8(YP1+1KTiREaCVzdwDI!@i_LlV&~@thz<^PNRSL&k z+P>w*S$EbxvuxvwF3=-9Q<64rV5K_@D6?i|+`g|t(Q-gFoxHO&VZFnfCjo-Sox-#u zrW;PMJ00{d`%>IpXN^9IYd;z-ogVHrCri&)Swzhs9ya(YDF_@9;r&eML{oo#S-T)@ z>M8LCaYyQbTLydEm=6**&N3x9@Qlgf8%^oYOxMBG-^05=YkX_+>cvZr3eLw!Zkg;T z6dk#entJzk+43=4OLL>`U|&MY)rY1!Y4*MF6>D^U9IVN>s5bWt%L1av!=}k}lpGns zZKe&$jUB>8see9@XkE&bmO{8WzQ&YXVQrn)9Pf^+zFO$RsZ<~}rR)`DNfHI;BuAo_ zjO?u@&*}80XZe-((o=s6qjyJlj~dzYgS0tq=lFTj`TB-HoiTf5!8&6RYWusY4O{io6E;@l(p2CsG#remQ=8F}U(vT9d`=1f=xs?bHvXGY>B&pC)yukjgl%n^JEUVy z&Dl@Rz5ou1OTxd6ZPp0-E8u1cWrVq-I;*;TTgh2hyX#JXS#dqW&gGF#$BOo?eJ9=( zeD!l7yS`w>JJMz3{ukXjd%fQtSU+KP31iL~aq#r)ftJG46F_Hg>8?;>mMeBc6abMW}Y)ULjGkFbFpSL@x;5*)7vMlJ#VnV z{@MJt3ol;x0sVyJ5&0FKZQGH5lV|+=^E@h?0U&8iK0)Fx#z5Z4(>gGIP2xxL2lBv? zWlo-w&k0E02!N7v;uj@xj;i*c`#`gGJcfJ(){Fuqp*=Gd0D`E^Wwb zc@Lj6jzPw39>ox*XLo}&n(t7ZY}*Y+Z!S8=lxOa88O6{=n@*U^iRW}1Qt}zjR4Tk| zSEB$^&s^GNO9JvHK`Ik3Iq8Q3Yl3{ya^19-uNf8?M0Wl!q6R_cXxFrJtRsO3LUiWX vaqYWk0{4VhUM#(T(e^61!3H~*{R%JuC^^iA98IB*00000NkvXXu0mjfEs*jS literal 0 HcmV?d00001 diff --git a/res/hw/wifi-high-pwd.png b/res/hw/wifi-high-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..81a4d11eae658f9d1775a78a233b6daa81665433 GIT binary patch literal 682 zcmV;b0#*HqP)J*%sn%6A(NTd#D3WVU&pD#yBt1dfLS05{4p*sz<=Nw=)dhQy{1lpq;o(4 z$R|8pA9xasN+uXVya3Dtxs)mkc?Y<6B@#Huh4`<7cmQ;XftFd7XPQdo`Q0Y+fIW}S z1Q?|3kUEmFo8;JtH$xQ*=9R>`iINYLbJ=7qjx9J2(&&%a5_6Hgq}8}W?0%LDt4i`$ z5_cTID)9u^MaNHOQ;VH0XUWv5l zl(}v86j`3ln0?z?jdAzDElZ*U)GX_)%wUVqSErBK8;zbqmIU3jch}$xYjP-d}$10 zYJJMbn(hrqTyfkJE^7uUd%)S4y2ju3uQ-V%Nnk4T%Qi{irxIxT`n?M<0E3ACR401l Q=>Px#07*qoM6N<$f>UEHK>z>% literal 0 HcmV?d00001 diff --git a/res/hw/wifi-high.png b/res/hw/wifi-high.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec5305256852940cf8f0d26993a3194e30d0228 GIT binary patch literal 605 zcmV-j0;2tiP)%L&}fWrk_Xw0D|g2UHcawz z7j|dn&70Xh5{b2~?Vl|fcH_q7V;YYvumz-mO||76_ypd7@z+`DBQ^mhEdWIzAF;S0 z-~)qsWRi0d?*Q9CI;P5!d;q+F$Rv;el1t)UOX3Nu8dL6>%tm`Md=~hwiM+z+*-C&x z_AOG2j6NKPQOZWVELAM3B`KhXc;guXZmy`RCE%aGg%lL0Ue-?SR>Wu z3g<)=@XZ;J!5NxI2ER$QSFCgqljIkO*;XX-BLBQ&C<$ADtCmFS8=K7VsZzx{pQg#) zV^fWwd!VO+c&x+=Ie0?m9H^S);lKA|?=LYr#``H855guFlfB}D*9P05V+LQvsKRBi zYt{g~Tv1I{FFt7mkkpg?xe|BQC~-K^z=(K$9*EkN^V?81Y_n8n2Jn(nmEcyyT>` zz3<+0&pYoG$JvhU*zizU0}EG=9$iX=J%UTv)j}qO55kZz{k%Ay=O%!n6+%GpEt{JX zB1Re+l~VYSa6s^Ks?5a)geMabWhl;tj|_!pgb^^4GK=LYLMb1=bs{e`r*9;HBsGK7 zv5X^|wkcl;DhAps&eM&_D-m4NSaV>H0%v*jr`(*g3NJ}D?kM-v#e=$#e2&5cLoy$` zAXaGy^QMCIP^yInx-^#wgoyW0vmGlC;3X$|U}gqG?iOA za^7Yo(1!wZ93YX6^An8Mw>pYp%!$E}0Xp*yG7t2l7hAk&+Eun6qX4pc8Fs+ZiI?kZ zNX4tziuw+C7w3V#6IhAfs@$%{mn|MF<+EIxgcI-kFj_1Yr*t_Hq4!Fu_PR^ptTLpG zLvc1C7aSAH1b)_&B=Vf|AtUKM5x69T+Ov?K+b)4#_>3;s=!oyRyL0OL#t{Cd-T&GR zg*BTm$Hf!we_XEASi2vrwG9m_G@*in?ps3U23;B%(sWc#4>V!8mcI6X{;$|(*bpc< l8y;H%|3#paHSSA*0RRED|0o143K9SS002ovPDHLkV1jDj9b5na literal 0 HcmV?d00001 diff --git a/res/hw/wifi-low.png b/res/hw/wifi-low.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe8bdede28c3af2566a5bdce14a7430e9e1e827 GIT binary patch literal 589 zcmV-T0SvL1!-t<0!oemN1)3Q=r{r#feTQip-BN06iKl`a^oT?NZ|&Acq2VWtJTIIjEs=H z($hNG-I+IUXU2A%deq~OMnn7*#@gX;TYlJu0jR`H&D0c0=CtG?B+h$bHMbrX}72P)`$U!0->G* zk~k~lfKOs>i3*VHR|W}By3@dX(xAH=4IqF znmm;-H#=Ubw;`PO*-Xp~Ps+7rAttSQl4ZM@Q-C-tAuSzGIlnn1CxAiDeL*E(GjKE% zRPse+I6lX8103+LH{c4_a$nfi4~h3Q=MJBHl_@|KE->Bl=Ov=QtNe>rNRUW9>hXWa bw*UhG-8ai9>hoU@00000NkvXXu0mjf`;7Cz literal 0 HcmV?d00001 diff --git a/res/hw/wifi-medium-pwd.png b/res/hw/wifi-medium-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..221fdbc16c4783fd9744c2c3b06e2baf1804c56e GIT binary patch literal 663 zcmV;I0%-k-P)~!-*T1y?n~!QUun39I$GHjDUBb4~##~cBiQcu;@Ba2Hb?3 z8w0)|ii{IccnjDB@+no8;yvKmM#Qlcm%`hY!V_RXOtj3ZJq0S|^0!Ik1#7xi0!&i1 zNFB&HNV09@D^kU>@ksJK1mqnRTs2rrUJEFJ1&knUV*MQ9@VJQFS1Er zdq5Ztj0Ita)W*z25c^>~ZpaN3jyi^((YHWipF}5?Ub|eg9%Vc|av{w3DN}4i@|nQ5 z7|&(S+qeX}RA9;%h@ZsyA;#+_dKJ@{Bg2p-Tuy)^;J{eY25x``)(nmJLBV#al75V& z@D)&+6Dq|oQ1JTKzJ@3+g-?y?H$p~*&_k4{&C8vODZrEZ-Q*5C2FVH)I_A`u;bybh zAuf9=^xkot)}k#CgEivDvACG9#nwpsWUix0qL=uf~OV1kPagE~0iP)NFTkVF|+G{$q2Q_{RV`eC6i zeaXp#zW44u_uPBiXBhd&$3Krk+>I+&FD9lkum%)?in8Ss_y*pA$!;EnpKcQ>rY^J>U&QrjZ2TTpVv}98Ve5gmTYh4y32VxyIirks;0u zv;=5mUn8~1=;GiwN!YMgriyiCNdkC+y~&IKH@B3i#o@C~wuD4VRJ5+BA+|lAz+u3- zEWTpVofFkMWj2XbM&*-!*QtfG78MQ#dG8Ytc1`BF@5`eUcC(J z9b6dfLSmR0{Yj3F{v<|Rj0uBvaL}Qebm;&Ibf^PHe9wGMp2xNHsD_10zLd7_-uv#m z?_F`6{n(Ek4^=m?b^GMer9(I-xP(J3WI^~OObOZ7^~JI=0Tk^L0)lV3xQvi6s>rB{ z!e@k2g4a-GE}jyeO+=KTI2S%Q6wV1VAeSXyN>~$e;B)vfr59u^$WNu9NkaiCQb2JOZd^bS3O9+O%t~W)S{;7iKpLMk0_l9avvad+ zdtSG?_0OwU_rZ&ocOO3?a0&E*p?c&K_y#t>?&tabt2F^8je!J+8Wy(&QXnfM(<@1Q z3)}#HOO+*g2CP6NuOxuvlK9S%IA>Km%DtD_x}Jc)G5>2KYn)j+2{6c`Lu!#R#ldZp zvJo$&iiz5i0_KRf+Y{i!6IHb&T)1RwNF<=5iBdyiX9a;LE4gfbU^6{X)fHv-i2bWr_dF})QHH#B+-sTf)_}1)fUzblKom%A4~TKL>Of3lev1we z_Zvkb68WpzaD2c(nM-C$Jmi_sF%xF4dC)(=e4>I#fMr=Ha8F=JW@L3##F*2%1PrD3 zXh_pUcanLdx5m6e(`Xd)uxEFJHJW2qrQ0^+=*?B<1jU`Vc^Sp5rcNiU^u%lRHbn9f zhlzH0(XImrF&Wjn4XcIg?RgFloX>FG>ei{&uK)u87;efOb}a+t00000NkvXXu0mjf Dw#D`T literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-full-pwd.png b/res/hw/wifi6+-full-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..b2936c6ff2aa2775e8f4ae0fff7edc8c99850598 GIT binary patch literal 737 zcmV<70v`Q|P)2-0w5w*vnG zuumo;@8BsT(KUhBYG>QMiQ^?mzzNZbHxHwcvm{Lp zj2V$Y70|viIsh&L5n<#$E7HzRtrYjf&S}C@Ww`Q^aEQLVrV9AYg!y1A0AmS07Y?@} zkJ}1KMHxCGw*Y$ZNMz`nK0AzBl5jb30ly67$5bm`?K}++Y1;35BW97*@lBl&9mJS~ z0vnm`N#%W@;mQ()_(FP+c+&et(z`IjEOhi>qb-q&dF{98D3Th zQ*h6B9mjRH@Irm-i;XJb#z^l(+LCz(8ntEik}crGX8;~G7{^4+L13Utm?>h3B)+sH z+LT+WLnmmIZC!9|Uuy3k$1enamXLVo7LA;`2`Dj=Zf$u89Z0;S>w6^`xiiEbWWo0q z;UDV86S;%MyEQerITdls9M~qDzxR9pGdiU0L!gthV6Q0tC(zNnP5)6Be*_o+12h}Z Tr+8sl00000NkvXXu0mjf&gfD_ literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-full.png b/res/hw/wifi6+-full.png new file mode 100644 index 0000000000000000000000000000000000000000..faf2297d3393d2879d7983736a79d77d563f3521 GIT binary patch literal 665 zcmV;K0%rY*P)N=HZN=zw29?Cgx49oW$sJ3A>UV@G9t>+CV>O};P$8+K;r&f{|L-Mihr z(=h(oOx20wxQ?a;w|Qs-Uz(=5sFJ`bgV)fwaB9~KPJ|r%wgHJ{r37GC4E_$V2cgIf zyh%z_P2il{=k3{;<{BjYs$)PApxs8K1VEdtMxhuu8NJQ98^S-~G(Y_6Uqpq25TKqI z3%PA_yT~E|0&&Vu^vyjy$Rcy1{T%@8$Eh#k!w}ix6jYby&EOv(IfL7|1OOZ+^lJ$V zZwg zhf)Ex+ZF*cc#Fr>ZfsGcWIxde08WZD;4+(t*c=2qQUO(n>e@P_hEFLeV!$Is60(5o zh13D?B0&*S?va&N){v#R#_Uv0SaTXiS`fMz^K-I*zL`=y$PB<-0-rMu9fNO{EhHIf zsE7;!G|@;n7z=(~MkPt8m}tX03Gor|j-%AuaG%EKJr>2x;OcmpSBUmv6od@c6T{QY z_dvm&SuAmz>w%?}-X|`-EAb7@wb?BFX`$#Rdrx9%dA##4}I3 zj`M7#Nj=ny4QIkYl-}vSBin_K3(j*7@}i{+hcBJ-ui_nn^?;-!>Z$6s(^`KdZfQYh zYbjZ+0_v>!#bc<8<>3F-95mpLcC@POTYv!oNuKLC$u!D_00000NkvXXu0mjf8~H6@ literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-high-pwd.png b/res/hw/wifi6+-high-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..684d51f6dc7435225c1e194cf547baaf7cb32f66 GIT binary patch literal 781 zcmV+o1M>WdP)KtdT%#%$#$v>R)-ZcVptZGQnC8G~4|RG0;IBMeB00Y&QKfl8qRid59_9=xl* zULD8Au~_(|Pv<+^_uhT?zVGZH_{SEyi}`%Mj;051X=nyN4Z|?0lfat58)&xSY*T@g zP#5=RAaPnN0oYT4e+Jkq6OkA2HX~6tfk$db*LxF&DM-Y1YrqlUYNw0@K--E&Ar0I) z_}J0qclb~EH~7WX?&f6~0<=h5F;>4V4FpR_G`)61#Lm&2QB!$j*1Y}@U}I@ug66qM zB_>z%!GYfnB+O?INKNpUY{V0Co@U1A#jt8yKhFKH!}T8v(c49)Shk)7V69%M>Yl zooNJsbKVna!5N8lMC4B;G=*s0n}^YenUZGp1M~+b3*MUN-%&3BPBOBEdU&EpI6JYW zxFO}cnvg0Dr`}dT-)sRV-UM*Jz;hI03<5o6!pNOBD)D1WqDs28>5J~O zZ0iHZjnb_;R^i9WZek5vy1P-IHFwR9DAAo4`l@=`KzXNWz>GW!+6&%J)B?vBlK zeJ^wiOp}BaHE=CBfA35G8LiUF5UAxWC>6#31ZtYM=pS|ROMn3Y?Eorc#^$Gw00000 LNkvXXu0mjfb*fvX literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-high.png b/res/hw/wifi6+-high.png new file mode 100644 index 0000000000000000000000000000000000000000..0ffb9ff97c0f67677a387d78d19bc1922e075957 GIT binary patch literal 705 zcmV;y0zUnTP)E8Sv;Kk{8;zD0$(C@-h9DY3aB)bmh7gMETsmLezTWdk`fTyS z<@@p8`_6gyo_pU5h5p$bGwJvHQ4DE#j9Wc;-Eo{+kOUS99>$P`%h)Ek5K7@%4Ixl1jJmXqQP~78VC&`5wXTNiFGivL{o#vEL!Udz#7y*6T>b^)l{{lMy!ko z{S9P9*bgA``YVDzYLejAJZwFa(hD4VPVHPXdXI1ov;<#)?|{gfUj!uou9PEyd#W@; z`pxaRi3CI3p^M!CY#HM!!3~i(_C;?uc;-b%z`Si*fC--FUXx=?H7Py!Gy#Cixm9Yx zm=H^n$X6#+jVNlJBhe^JNvgLmVqH{KaH;OU61@Pp=20!8hb>0JSXH;;FqLn5LYrmS zwNjDAURfR7_XvPIa|}NMnXbB5z>|zZ1J_#4q>aRffF^PPpd*V!1bgitAEOCL7)@kY zy0$(l@SKjuudm@W4TPjhN=&IS3Hj#0J}@m45fUt~wvPw?4~+O`E<>DQLvqz+QT~~P z8{kd#jNI>HuRIX}9#k4u|1=R^ajZY0A>eXY!9(GV0gcHs=fgfme%7=?ePA~mRziUd z%{S+hC_4);jd)*nCV#X5N{CP8uXs#gTac2XJknAb`>a0_cP-Jytda~i0w&iOPPokZ n)p^hwn4RF}Hn*VcQ-A>gGkN*T*iXyW00000NkvXXu0mjf;IB69 literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-low-pwd.png b/res/hw/wifi6+-low-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..c2b8ece57dc7ace0d2e090410110f8dd619bf927 GIT binary patch literal 780 zcmV+n1M~ceP)Mmw>yJY;}h~)4>gR(GY{7DcL*Lw&L(_#yn-W|I z#dtOYiL*)xK%No&E5MGGMP5TAu|(Ab_Sp7*`6digkVvYI0Y^Y~I}u9&G@>Ba)sXvifH{%n44HyHLXkL<3 zUu8?2Gcy|0Imk$0e*=-5-z<19Ckbx)HSIPjL<4i_y~C&^ zi7hmnbfM^$c_rnJ=b5MBDuw<&psAfmP=5R;1QZcT!+n=&;`34j=s#!XhKcAgO`YnB z$8_89ffpjch4wxE^@#-DMWGwf67XGj$e0M9vcKse=Jolq!zfE`jHxedv0)~(ROubE zw!}QpoJeiy{f!G`;cWn)=Xg&_@dyMuEN(q_-mt_EG>I}%9*Jf>m$J7sEw^{6r#lpHpR*n~4C0wQVD>TrN&S-Ftc}2 z(eMub2Yv%@|NXMwO+$c|RVo^KE~^Hj0VHx>EQ(kQ;hHt|KQgo4^AW%rs(~wn4UsxE z-BKO0Gjj4S$gr?~fyn(c1)ub!z`b$C`%l$AV9~Fto$pew3AaFV@I3qzh^+Kefcej| z9Rb`itr^*!`(vksByP!RKLECfxGZo-q=+(;0D00K)0|SK1c~?C-x}LsPf&J zkf;rBy;N*su5K3o91wsh`OSK;9e{TUUXcn7{B|9WdXV%XV2QB$n;wZA=8`9u(TF4# z5ayLa`hxdLq8)ep-iG5e<$Fz1J7ZCPn+gF#gl$-IoyMGxL_qm-GUvRCZb|CIo_K1v zxe$0N0$QjP$ZyD4c$cZZhz5YKxJ$;X@V3VD0b;?N54w!{*}W(ArGMC{6N={OZH~L3 z^6=7-@8zfRMGK%ZeJo$aDS`Q&ux~CTURXOw%TemJUPwIa-G&9tO-BK#z}xdck6YM% mJ({+WgowP`yS-ieC%^!A3;4sy^DuS*0000WdP)tq*3zs|Z&CEOJ-LE$j1eYwKyO_`CTQD7HOH)(mVHk#Kodnhe-hk;sX)}S7 zP=b3?kT|TB0OX#)KLhNw@yKInOi$EJ;HK>0EH+`7fkeOV9B>4<+X+1Z&{*Cmlmlze zKel!G4f+Fm0zLitWM@`}03}i=h8oApfnWuRrf0WBYz%YEoLWX^-5c)%Y^WR@9=82>}=00q|ad=h%w-Aka~B8@TgEEq-W8RLSy~y68UJ zwmxv|T+I2hAy}G_7&AnB*!8{vicAyon^OMwKnaPwq-%L48MrgV9%Q-W3hrmDUupP= zG55X~k^;-5VZ|IcOE^FFrT>gBQpylm3ocpy6R3+o(Ld_+mjD9*bEGOI9BBY100000 LNkvXXu0mjfOT}Zk literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-medium.png b/res/hw/wifi6+-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..bb9d50dd28adb1737cc04758f0425a18753d6133 GIT binary patch literal 712 zcmV;(0yq7MP)0kpcZ!nNLlt7B{9C~i~ zynQiwCNEw5;N!dZzWeSu_xtr;5d3Ee-C!^nEW*^FB`x)!Ct(;i^CU1Q@B&N>rA-7* zLRCELfy7C!1R(1I{|2x<CN@6Od@+odb>lZ`-9O09uwe#>#;w zJ7*OQe?oslub|gAA7A&g5THZ~MN9Ltav&H%qUhOW5$nKQGN^vbCccheafIWkKE^tR=8SBiqQ@nF+J>YIzBe1}0T5HReOp~(X zR3QMA=N>5+oRC;WME-O_(})(mbLfo*OVZrFj(I($3IciH3c#I|YGFRC$rDbFY%4A( z^IcC!REAwI6fxEs=HRy}4q!-rFdu9MU@yTd@X!a_3_- zA&CW;rwSo;!P}DP#{HpR!)c1*{YtKO!lXQ&2?0ZdWw_!hjWM5y01k}Q9p9-TMdmSk z!U4M}fZFCAhGaesJQD#NMBv>~^)J~5U_H|x(FkxJw&g8%O#@47Omz8bmapM`()L`< z8#X>Qw%UGXnbw$q;=&SoSlY^+4j0mvkksB=hxv ui#5z=O*e7-MlfrcX~I3qqvR#G0t^7U4*89EJ|VRL0000d`ag%{zc2{>hZ)e`jo}%c9C3b`5a=8uDh3;x;4n2$Gcu*#QO*yZ^971VRIVYe5 zzs&*StW*GyS91Oh&OVrkyo0tGiLwDam+jx?CXQ2p=#|X@2Y{!&VkF?St!QN8z{dNp z9Swg%e?c#yvzw!XMIHc@hEg%qye$qyYd|zT+Y+!T%!HhJ2+XE8{|IM8ao_^xtw0S- zwImrUqbXeg42k_6K(6ma@J>z2xi_wQ?<97DO+Se{r;6SfY8_ReJJ8nvvbQP%%zuOB z2*-0%nvp%ZKX#E&h^JD@2+r!T&*a45D3r+~EBOre|p=m_h-ad>*k0ohNe~kHYpb8>I;1Z6ffodTiUMdn!PHZc#iutZ5 zq$zR$;1OmX6{2(7}1>jja?yHR(HiG_?vn8sKGS$B04$jEb(hg9x%NVR?l&7%Ld&$?v3g6Q z3(X08OaE_Dz>Vv0Jj(DKTk!+{x@vBHci*VR4=soyEU)X*2@2b`K5*<>o9lT~@E{>E zXNpFyyU9_*G$Fq!g}(=KNW~*v%`3^s-68fO3(gCKe@FSf*JSj)kYw0q5EtaYE#ds! v=l*B(n34y;M)bt;A3#|Evi_qU{1#vU5i}|SF|;p&00000NkvXXu0mjfC&Ez? literal 0 HcmV?d00001 diff --git a/res/hw/wifi6+-none.png b/res/hw/wifi6+-none.png new file mode 100644 index 0000000000000000000000000000000000000000..fa20a4c21199767fca8635b068559eb7f5d5747e GIT binary patch literal 690 zcmV;j0!{siP)h48i-56+LYgZQ&=esMF}}gKGOl|j=XtSl zVA#FQW#{diH?!w?e{8;)OeT{R3|06lmqzew-}f6y0$615G=>AXi~)lSpbCB)0mOBp z0AM=|eurSEijhNjNtj3)zy`;QkKFiv01&mLHDCb9X`h4%1TB$`nKZC)a$Dx~8U6zA z!3VELTjMAI#Fm+gCZ9{xfHwt1&Ke5@*2mBlO??Mu(Rw~ZuqHL|h+&_g8md|*}~^aD0Mr*^K$UI(rNrQmt^E`Y3uF(CP0mU2Ykkt$73 zpWL1sCP;CgF4jV@C5&qfZh#c9E_%Dce+HTXbK0r|X7DQ49yzY6CZ*?2lK^npw@xh> z6JTWmdGCa(5v^GJ2pcsiNp<>TJRdu%z#{`a1nxVkMf9*uCXCf}D^64SrY8g}!zU{h z2Ux4AjrSY`NJ<_=54r;It^_ZWg(iOM`f(dc2mlR4)Zei{b#SsJBf|L}sOm~a4*AIcGEYW4Hl1!EXlWSgHp-pBU8knEp{_WqAvNr(+ Y0J1apw@37?)&Kwi07*qoM6N<$f*(61SpWb4 literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-full-pwd.png b/res/hw/wifi6-full-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..427b721e730fe2c2acc8dbbddec10207cf96ae7b GIT binary patch literal 762 zcmVfL7?U+gV29vsJPzUVToPOerTA|R5{pI&z&;TC z4q!i3M2_HzM51W|dwk9xb7RaBB&JPkz!H$%t|SrwO&ATY23n^#BRt+RGTL(ZAGplV z|DN<#!6F3c$XO^-0GTEM0-M0i$u~dXv**aPoZmBmJ-ECpebliOK7s!R=?T13NdUmP z=e_NGa}3{ycd;`gj`w#Q8^A?3g_<9;!mgP5LANCkA>z3q| zh!4P-CnBPWUz~5Pt6OoK>}*dE(8ZhYxAHD2`mEY?m5J)d@N-=OAR*wF#E~>iO+_9L zsN}e2B?$O80G&G|QjE=>97YbXOgbwO(1kC|3~|CpC7zz}$=46c2wXdhWZX#>SOG$2 z$X@VB9^b#OYDCt?y6*AeekeFAKq6%O!pgJe^AX@K4!PLWNsZ{@BX<`&QMzF3Eu4Ok z=yie!lnC-Huo5I)LCwnqf{&O}SK+pSbv(qpIWIeotE{LJBoCXRs+=)UQ; zq(Bz#0r)sz-h*~PpwDWWGh#7Ye6C5 zRxMrIGNcbwS?q|e|THY0DrtBnO4W*3;+NC07*qoM6N<$f|2B0NB{r; literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-full.png b/res/hw/wifi6-full.png new file mode 100644 index 0000000000000000000000000000000000000000..a4bcdcea9ab739e80acc79e184f078e6df1a5d02 GIT binary patch literal 690 zcmV;j0!{siP)S4%fxSHK1^;tPC!Sa4+Xh&+D8?cd})J={x70oo;95 z-g)o7H=8W`&*uDKwOZ}s(T8{RY6+h?=ZYo?JQjEhj{%&|Yk`wc5C2<&#H>*Quzi95 z0N5uJk=O8?k!YI0Gd;iDB0Z)LZT`&>=%@vKP26j%r4e@xQ$XJ`hf5AC_ z{`+`ukt{-h4ug#{15j8JAh1e29M^n=PwyhL6Z|~|*k9+^=%bGH;OFq4Abk$+R1yI2 zJTh(tYu>>R;9Z=|(J_9icSmsQrZn^0s<11iFPeh4ns^G}r76v0kr{4!e1I{9Zv-A{ z%eF6)-uXkmg_!9umh;$W|%xLQp1P^Tld?VTo_F*(8EJ<@JF5FYZynB*g zDLw!fk%&+epEciG*S6x8*!iA7(AlF8-#KQAUYRysWmNqber78GBnW;f9HwF7D)M+J zCAVu<0>R${=qw=7!@KFN%P0Wmq|q7yUBtqy5a)_i9_a}$WBp(qfvaGXLMJH_D}ZE9 z)C+FNWBv20M&xa5>mCaaQo&ULjF9gOi^!gLM?j|-XtPO>8tUSOPS*~ibfMN;2K^wn z`y>%qBgj!=B`{q{&C4Z%50%qU;l6=&BE+IOUw0i>Sy?4WT{b7Ca>oDk!-1NBj}qq% zw(>=PI22^5a-D9xS54yWKy;nD?b_W(6S^ldf3a-+SIt%h_h1j!l>HH4 Y0LCWt0l+@|sQ>@~07*qoM6N<$f=i}0DF6Tf literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-high-pwd.png b/res/hw/wifi6-high-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..9458bb970cc7fbf130a12eb92232b0dbd47e9394 GIT binary patch literal 803 zcmV+;1Kj+HP)C$1kP$m9?xTG|l8>FLi7lVWZG@O*?3XmKZU?~Xm9(o%M z>$C6da7x2SqrE%t&U-uab~dS0uGj+iFqur&F>J!?`ZR|3gCK~@B(N&*H4Hm&j;X*& zsEOakAkirNG)>`YVvcCp|C%L$oIJf9JqT1i7l1G+6SfkhYJXR>lkjps|L8L`TXq`%Zzzn zu;$ZL9{|uZmEZutV{+H{`rNVnlfATu;12>wudVFpfvob++G$J*sGM(`H^I`T-=nEt;mBM+E> zhboITYUFiRnz5#-3~p<*#<@>yHl}VvFW89}B-T#ig2E%2=Mwe>d91%THFrjgwt3#e z!be5HX`IV7c-&PP{Fw7Ipk3@JSjQ_3b@5oc3%x9{JYB3w%o=7gvT+I#m?6l+f+vCH zD%8A!g5WLH)K|D`-SrG&nKjS5jAmJqCrFU2i=;a_ZS|I>E;MJn;(N=KfPotT-YYQg zk9I)7wey}b7OKS$EQ!h``g|mjWf};y^aqap7V-O{C73HnyeB%YT>})FmToOA(g*S^ z^h8(p+ci==bbniV-_xaz;fz`z>vh+jb924tSsYwa15?e))qdgsjQ*u9LSUtG#rB^- hSppyCxTG{44U*~H#ULR84JV~>0aD@uECt29C%uh^ z^__h_>q3)}M!WXy&U-uaX74JM|7^}r#^doShD~@we~sWh=Ulf;0!sp4#t_3f4g^j@ zO*|WcM6Xl=u!jQw02}rDE#H!opAo>%-2{kp1%u?{X1F*g{ zkYLynsUn?Fm!E?Sh5ZdgeoZCd!TlU0wp0#lpOx<4J|F;YVOW7z4RBTK`RoqMjCJ3! z=j+5h0HEh8!2y6rrZsm(W`Ew}1B`_33f$TdeheZ*OQ6YmtNy+dHl>3E1PXTph*YHu zON5%}gT%lE7tw04pV?@$B^4}^E;f`g?}^rbpk5HTn?i(Td7zSbdvCAeWu4gH2?Xuk zeD#TQmT22t)3b~%eFQ%QnNvf8;E$viX5hrlNFPu8TBj^x1b+#j!+=Dc>Hp_t6aW*j zrLtI~M&72S8GD+_;I>9I2!W8!TX1Un9bbaj$$PT`Tvo`ii#9{cZ4tj&mVWaclh z@o`>o8rO0UraLM_7;}0Cbc$HP+Cgckizhl=Eyxnf)4`s^>|rJ&8z&cm3_-SXb^^+*6r!S_|uP~raSZln-Pt@*5%QI;jM1PPK2k&LI+yt2TR8pB&T*Tq-zMN5H6WQ%_l z&j}m~GEuvB=8jd6cr6fJqv&<*7SV*>6SSSIJ}+AXS0}h@ySB3IuK)u8%@O-fU)mko P00000NkvXXu0mjfBf3fX literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-low-pwd.png b/res/hw/wifi6-low-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..9b647b416290a5db6d5a493476fab8412d107f16 GIT binary patch literal 806 zcmV+>1KIqEP)?cL1GW7)wsA0#mi-hfp?R z4xD4yCa5Bn&?L_RMiToJK(1B-Fv`s{Kx{J{nvUu2YaM z>^b?X4?xi?hTs5-XR0*!2xdR8`A{Z+9#grdDflyhOf`V6#GCOqm9WJ;I0t~j)c_!M z=7k0#IWYo=*tZ%{%i1sA=t)T`s~*tZHL`^9n(HO;E+BZ~03u;|&OL@c=vKT&i%m}u zrNet~zW$&qAF8;fkyv;Jj&ubuS2k&Ycwp?OxUWS}wSp0tGy5Y8L{r><<1n%m%c6~h z1d3g5ri&Zgvu^E^wVz!5pqhYu(-I;APF%4y#Bah8!E{t}YEtG=Rsa!QzpQ)h!Yo8E z9|5FIPu3_i`99zXLz}|JR%lw}rj;8Lh9}k?kCoHVaxwu(NXU(hm2hfzywn>}it>)* z5SlY7h3-3m$%%NB=QLbJS7{09=y(x(OP2?lAvxmvMMAJFFDO3Fux^<<0ASjApZAS` zEq^Dp>Wc70NCdRN52c@eclk*ishJoYi`h(%iZBMtUgqV0@czr-I!Mj8Xu_Z zyT|9ix?5bDyQTF$E>wmNFUaZnj?-OO-&59`<2{WA{w;H0hY8oSW1sua=wDJE02S|! k=|6z70A&4-82lDs0670F%iMM)%>V!Z07*qoM6N<$g07QkU;qFB literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-low.png b/res/hw/wifi6-low.png new file mode 100644 index 0000000000000000000000000000000000000000..5217b8dce2f190e6225c2da25878dfede940876d GIT binary patch literal 755 zcmVHQt@JxpLl>>q6y`m%dC!P zok~S~ZTFvJ LHlRWoGEiw+Uaa5*kmt860>W+^A=Mr^d5j?+dd@Y^ zc;|>jcK~yBSb!)n&>oO>8<`C)6023{0C9g}NJJukQ5$Y$7%270OoQE@O4$$FQXQ#S*8=t?8K||Z3ys94ioEe*RJ(;OG+sK@Ev75x2A|LNTl>c9l*y0YW?G#LIMEaz-5808WrOL~zhr+ODfJLnjhz))ud)|P^epv#}0|G8*JqBpZHoH(B zu&b%S1HNunQQ#d3_>wHBqEwJ0`^2}eQGK^60av9Cp?N5ssr52UnvQ91U+^_OyH>+N?-rWKO>Ie lSe?0$=;2saO5m>m0|0sLBMH_!jr9Nk002ovPDHLkV1hL(Pt*Va literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-medium-pwd.png b/res/hw/wifi6-medium-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..c157f572606fd99da5db7f539f577ecbb455b210 GIT binary patch literal 812 zcmV+{1JnG8P)LmUJW^}Au79lPYa4-sjbw~qQ-q1oC&;}yL@5pz{ z>Gi#r_g;N;@xbBc{yOJ7Kktj@T{9W`W3gB?Fl>QaT$+LV#+Y7_0LoOpf?)?NV@Tx! zsExfDK=ca*0D3^>U!m-^^2lRwAf6~1z#Wd=i`Wgek200%I$A}*k(91eWAP0tw1QKU|0oLmEtPT%U)B$jC04h zbM#jqfTAZ1!2uM{RB7%J%zjq$p-cd+QMslm_#=Q!HGsCnoAI}mu*EzW0YL6*0FWy4 zLIaVU7yv|QoJQ1e?u$1%Qj*H5n{;=DEMYw7c}ctz2tJJfB4N4DJC@$+R=h%sZBG!T z{Tt6ef2S*Nskkm9vG5o?)D^&7*`xvDfw5WQz6L>6az>oNH>f-)OkCCHT4&9AO zpfJkKba9P$R-Jot_Cr)ZD90e*bcBe2qo~+g;-2u3VAfT0s#E5>v;c;5{hzwmE=)rN z^BzE&^kjuHDD1MyF(QARMXAMDOLSil<+J)7JN|CQx zx~5C>QcmN2C+S*FNy-yGvEP=?dYG#WV`BY^(?=3>Wxajgmr>7LF$XRZ&W(NMe@6e3 qvH&P~*G&Hb6a^sd|A^ji0R{j^H7saq1{}ly0000TYxZ literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-medium.png b/res/hw/wifi6-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..a44f85a7cb322883071a39924807f57ba47d5658 GIT binary patch literal 742 zcmVe$Wx32}4Oty^`gQ}HioM#s9j6zU>@4n{$+4rw4uh8AkTHV`qMBj?K3 z+n4mc&=;3}@NwUdd%tt;_v_wF=0A(`52MkjjA0#G)u#cp>6|-AlR#GBa~SGSjy-{s z&>H>?K%$u{0mzELzX9y6@yIi1jh;xGz$1KpgOYb%1KqesZaEz^z{STt27`n`y zSaWox4*=-7La+_sfho;Rk$IVP`v4=M2LiX!hkgQ)z9q26cq{(C64sRm9T1qh8bBnk zys$)=6D^SFxu6l1gZ1=AgC%Kpbx-cjNg2iq&1d4B!0>4V5r$=1YrO2+Ry?O2`<_71 z=H1s{e#({iO(pkVF9A`n4{z&qx`GD%(m zFjn(&F~MnUEBJh74z6khF_zg literal 0 HcmV?d00001 diff --git a/res/hw/wifi6-none-pwd.png b/res/hw/wifi6-none-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2973e501869a294a439cbb407f67c00f9c97e8 GIT binary patch literal 789 zcmV+w1M2*VP)t6EN}#o1qxB#h__+9 z-qU?JhnoxxtGnBsc{}rFcIA2ZEWY`%TCF-5cA-!BY5^VlzCWrGK%LIFFuaD!n9#WZ z8sOUkAjXvffV`sf?{M~BMdS^%FOjGkz;lknzq#@K1R##8=70epyS#rVCvTM2RMt! zfeQ?K1XZRILh2G=gxF^QGT#WmI5)omVvp(2a>8(58-s8VU}!=c%5j79m?dTQj%&{j~MQNDrvmtd?DT?3{M?EBrPww#>hwAinq99(-Xw$ z_`$nxKN-r$Dz8~0J3NQRx&p|R9d1A(F!3|O*CD8&WCoUGe{6vWCHyxIBg?T&+D;)* z;tDfE+~S(1wNB=KcJ+gL3i2Jxh!{9^<<@5QxXh!6SAC^hMy1d}{B*(lpcL2b&^C9mWZMOJG zgYfRq=bI#%Qvl$A7aaYrFYk+{U?U;%JZHHk%28XjbS*cYYb7@ySfp#%?HVDzGIvYs zeNw6nQ*v#>8|gY%$9tBH{5x{sRFZ|EwUrG@GHSeC~KY*$LBlGQ+0m7gR=oS zaE0NJpo&yNNL>Jo5c>i^rYiwh=k^;Q4w()uUm5P1H3$a*hAn7KIj(WN%rzy=Sa*p% z!@v3f933$QJvg4L((Dq<>%7N@GXeCJ&b3USrvNh10QM!{%)hOK1M=Vs018(FfYitf z4MaFG0EpN)ji}-5muMVINvcylVz>jUq;baeLcD7j9(#aDT6Vd|$_L$wH+W*(6U1r% z;hQf%7|O>guW2GDyo5%&0?3s;9zY^6GAZF}5L8ew0}HZ0azKO<{y#1w$FVGGClDz1 zg_$9)bI+EuPu70+^@C~x@;%3h7#R9;YlU;75y7-na|&tmBrAZ3q5oC)I)qt-U_Jpz zlaUN)GxNkfyyMowxP)X?F^nCXdi$7AKxwVg}=5(wGOSP2(y$4h+?r8sYSE};cU zDYEGSCO6_qp4)JhOw$PI>3C7)Uy5)7+RnJHc`q+oAs9(^_g8UF$1WkKEY~=F4h3>b}^-3@?r{{Y!v z$O0q;zDQ|1-1TXqtIf(=>KJ&QT@_#&=qMOM_#V+y5G4u-RFVQk{-fzDTRKNWe$ViC~6KcEngXjg#rH;trzY@X%fYf@h59JgX{y%zv zXoRBjiE{ujloWsz$WQ@faS=(`co6;O`QwGi;=82z;`x{u6+o7;G5U|8HJJaRjkx02KfE#74ndNnQhK7A66zqycgO)pG%vj%WZ<^>~yt wvMpHEz(~tt78(-uXa(H`sO1|#9Do1=00VlOW>+6u+W-In07*qoM6N<$f(T{U5dZ)H literal 0 HcmV?d00001 diff --git a/res/l/network-offline.svg b/res/l/network-offline.svg new file mode 100644 index 00000000..ca9dcea3 --- /dev/null +++ b/res/l/network-offline.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/res/l/network-online.png b/res/l/network-online.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c5fe4a9e8f615f3797004ea6ac57d7e04df539 GIT binary patch literal 406 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oArNM~bhqvg0|TRn zr;B4qL~HV&|Nrd|J1{L{+*)g3(Qxs^&ASiml`ku@xw*ORx&@T1KlcCsn+ORB36_6F zpEk$!&OGes|9k87C4Ulrev3;m;q9?XxWc%YPong|3T8K1gI5dz%`J^TkE@4m{hBK8 zdG*YR69Q$fITMR&-d*upTEWiolOv!9(acFqW=6l^PM)OaqMsi z+-$RP-E)SHdG|veIjoa(u{?0&sB=SOqax##Iu|kViBniR4fj<3t6-cpjh}~yhx^>S zn;#pK*d2814*-Gxg{3PPrYsZTuw;6}5D}2XJpbNav5JDni|pEkjG6oGxDU_%YTsGb z*wpsV)lM;R4j+T7EccYV4c-^;@2^(@`f=L-s$cyN|4LsH`VADZ0*b^v2zJhq;z&qH w&`>y8#@5D}{{77j2ak&x&r1?yfmSjwFjeGE;MZZD01RjbPgg&ebxsLQ0K}84g#Z8m literal 0 HcmV?d00001 diff --git a/res/l/network-online.svg b/res/l/network-online.svg new file mode 100644 index 00000000..7f10bfdf --- /dev/null +++ b/res/l/network-online.svg @@ -0,0 +1 @@ +gnome-dev-ethernet32 \ No newline at end of file diff --git a/res/s/conning-a/1.png b/res/s/conning-a/1.png new file mode 100644 index 0000000000000000000000000000000000000000..cd0fafa97f8b8adf20fafd14b3cba792d1097270 GIT binary patch literal 351 zcmV-l0igbgP)k*&3LlzRM;| zVGsIxa;SY{#pP4002ovPDHLkV1hWclYRgI literal 0 HcmV?d00001 diff --git a/res/s/conning-a/2.png b/res/s/conning-a/2.png new file mode 100644 index 0000000000000000000000000000000000000000..38b549a378e574fa0daaf90a0c049b80075a7a12 GIT binary patch literal 3170 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 IM6N<$f>E6dbN~PV literal 0 HcmV?d00001 diff --git a/res/s/conning-a/3.png b/res/s/conning-a/3.png new file mode 100644 index 0000000000000000000000000000000000000000..c002abd0edea76da5e0341be55a1e2f86bca5550 GIT binary patch literal 349 zcmV-j0iyniP)7+J|tQE5Fz16C93sCnNRunsJy9tPULw(t1h z8n6!>0<8qB3!DKbz*Y>L08^k392B4qI|WvN2jDseegNYDZCdUQxVP_4fb9ZrGsXSo zV6`L-B^^r|MDlx*9wl8$>W29k=vLFPMo!M5o!HsbIZO^WhdV$oIPe6V7a$kFX0Ufv z%PFoJ*}q>oufus8ow>4L>@7QN!<)hBUpn-$ci`Ffmu;2mupVGHz?bC~s&u%NgOv)u v!&l(e-sN`{EWEOtpO>mo4E!xVld6Cpx2UO~b0A*x00000NkvXXu0mjfv}lvu literal 0 HcmV?d00001 diff --git a/res/s/conning-a/4.png b/res/s/conning-a/4.png new file mode 100644 index 0000000000000000000000000000000000000000..ec398d051033ea4f75b7897ef0c74ff1ab0d33c0 GIT binary patch literal 3180 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 S?1W_i0000 literal 0 HcmV?d00001 diff --git a/res/s/conning-a/5.png b/res/s/conning-a/5.png new file mode 100644 index 0000000000000000000000000000000000000000..df58230e81f2fb0c4cb45211685c418c97754a4c GIT binary patch literal 355 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 LNkvXXu0mjfo@*3G literal 0 HcmV?d00001 diff --git a/res/s/conning-a/7.png b/res/s/conning-a/7.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcfb6d0d6df2054840e31524d523b4f739ae713 GIT binary patch literal 359 zcmV-t0hs=YP)oTKI)Oh^}+2C_i_hk-R<8JPMn zP+_aUDDVcnyO*N-tw4s;(X7s=X(5--M z1GABLpGrAP_>~&?E2lP`1okY=SPh_^=oO}{r~U|7wEM%TzX9w5TfhO(FWXRI#|FCv zPR-x9Qe6Ufz#Py6#!|ougDn_r2Y9yLl9lS!HVdK6BH(%gR-}Feo&TNDl&$I_(h-sI zz{~5zD)yTqvLYh2+zUhb2F^>iD$+Y}9X7oG@{Q}T13$aca<;M~{M`Tm002ovPDHLk FV1jhAnP>n2 literal 0 HcmV?d00001 diff --git a/res/s/conning-a/8.png b/res/s/conning-a/8.png new file mode 100644 index 0000000000000000000000000000000000000000..01785950998ff739ce9eb250988eae6dad778749 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/res/s/conning-b/1.png b/res/s/conning-b/1.png new file mode 100644 index 0000000000000000000000000000000000000000..31773e94819154003f380009569d191873028b30 GIT binary patch literal 7242 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 CYfy^- literal 0 HcmV?d00001 diff --git a/res/s/conning-b/10.png b/res/s/conning-b/10.png new file mode 100644 index 0000000000000000000000000000000000000000..41e3c140feaaa1d2c49a032dfe591b2c3a350555 GIT binary patch literal 7873 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 Zt-5eh2i^My1$|@#D0Z&4W!B*v{~NsvXjT9K literal 0 HcmV?d00001 diff --git a/res/s/conning-b/11.png b/res/s/conning-b/11.png new file mode 100644 index 0000000000000000000000000000000000000000..1892047880a7f5a71afee58903360d17f7d0776d GIT binary patch literal 7879 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 literal 0 HcmV?d00001 diff --git a/res/s/conning-b/12.png b/res/s/conning-b/12.png new file mode 100644 index 0000000000000000000000000000000000000000..f5515e95fe93e6ecf95a4939d86fa3bd0afc70de GIT binary patch literal 7847 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 EUmuNYuK)l5 literal 0 HcmV?d00001 diff --git a/res/s/conning-b/2.png b/res/s/conning-b/2.png new file mode 100644 index 0000000000000000000000000000000000000000..e227bb8c4f29f1135745b5e344ffb7c5c36d76c8 GIT binary patch literal 7844 zcmeHLdpy(a-=8^?q8vIXGnJCrj2&|b8x}((ha|Io$FPHK+C()`gu9edB$X5$BvC?T zirb-sP^nNWsh%XFqLAl{?s7j*&;9$|uh;YY@3z-)eXjTCeO;gT_4$0R?Yqmv%}GOT zz8VAq(V#e!Ji)&~6K@qI@b`;DB0K~F?b*E6SLjI-!FYTwlNABLgwZ?z28dZq2t@p( z_u%?{@0QNk`OJ@;Az7SI!$%!F^A2{aY1XEgije@m+Y;pIFfS!j2IZmgn@rTVuY#Sn zyfqE_`?6l|6Vx17Z4zMqK^zDSX}7)~I#9I4s;d6xHL0emBf+3B@T(4gZ1eNy@wyl7XwvqCtFce%sUHY-NXpjRH)1~bJzhUh9>|Zr z)lFUzG|;Kof-CRf3_mXJ(E8A`y}{@7RpaQp?*+RDd%_y)L$8~J86RH6JSK*9U)*>r zbmw~WvQD+Ey7>#zh913$dsv_u-#BA`f!9e2ea~<6?Om-Nq0l&qKU%Nr230q|bUqck zyrov|><1ON=HNngb`>xZ{<6PA^^7aZQQVz~7>)QK@;_8ksJ-UnN}r?@pAAN-WX`91 zP|YkoT&L>RQuS@IXAJh6sJwM6>5>n(a+{Ob;=^uuWqQvm^|fwp&=^{xU0nvBJ6khp z-UIi{T=NB518*Q}wFp?K0c_Qo4z0z;TG>v&-@S!qVf_2sDUdxP}H$>RylV_;3!X8p^l}LV74WeLtHtw4-pLTo%S+96( zB%@ta@afaaHf*s#?|imn_4{}?VAd5nX^305=lJy3c$H!1aF^V8&CV*h`hg>B%Ga)| zhCt*JSPl*z6bFYt(jH9q>@9n(oo}wvuifb7LN;0W4)!ALIMGi_ry3hyJ zFTbi%=kL?jbE>{1lhp-3sIK+%QTDOZ9EC&*1fIgZv&Ro=``3th9eYGWi$r~p<7;SV z9%GaWvVgqVk>=?ebmEItV5u-B%EZF!XnNjatGYJp*w||+A58lM+jc(BtFU|of zXj)uNceX$A^_CYZD;fwd1TVDW&74Q;qiVZxcgcy0IrGe0PDj5`DfWFAbTZzr!DE;4 zt`h|B6S0O}{N01PA(uSqg)swqI|rULqT5(A;c;YByX`89nEh+wcFZlDzkI1@slibH zEd1780cz!qK`(t*>6kF;W_?qxs>GEd`Uo2d{OF+x{Sc@Mo)!QN)jzG+aQ-&Wqo zzkMSc(t0$nt=<2liV9a=uZ>N8EN>=~d^6sFWjGDAYO5*A#!{~@SO3@vwGQWS3%6w3 zKv-{0qUH7Vp*P8mfkR@ED1HNUyR~QN$Fw$0?{;Pfo;f_>Pn<@*=95bHyAJz zvw2{ff>ogAE{lf|I%`vMc=NqT{hfuw)~ zOE4Y~fJCEEcmxWKKogMD{lQr(^@le{@LfevPo$W}Lz>1~W-M zsWg$qrAJM$P)OEr&|=15F^FhKydBBX&eD-&Pckm1_Ob?;w^EwU?u^}WK2>`h)J~bpjgAvW~iSQj|iHO z$>p=H;jS!Bl=$bwS{57d64EAwGRLCLQCJKHg~4I*XpH$!&^mxG08@Q}(;Q`Hj-Q-i z(20&9BMnSB7Mm6VAbFgS$q7(Bq5~hG3Ay~WTyBIld}2?q3D?O2f?0hp4WcWTPMav9 zNie{esIKqzWlsx1P7bY*e+B+uOkSZ}5$E6I`3e2OV#gPXxcqQ;zI$*OKo|Zs&#%Bg zm^{JGCJ^$YDgPp<|ADibN=0YTm&=cyw!Rk-IW?MUKM|}+sbH|lk|)yW6DnH61+-1T zR2G0bPEFB6X`B!M?5*GH;txCPSLtewXW#)e4S~jE@d!&C6N3oG0u$+K9*nWDpyB9v z^yC5mU>9(iLJ^G**oAJt!Sri1JD9i9xs$Dx1cjo7AWlZfUG9E9g#9o4_;9`UIYu^|M?jINbCOtH_iWh3H>Yg>98qp2QDuf zY$c&WcM<0=m;VKDioumd2RH)mUu}IlWa<#7-HG6yr)=O|3trvGA9wfnB%Y}A|KQK} z;`k4)08;<6$lucUAG!XK>u)LWx4{2o*FSRoEd~A-_@C_hf0Ik?=eK`=1AZ(Of#2;{ z9&LRKJ{M35c5xy>#wT9KuH~nL7FC|Jp8x_;pEL26gJfmT1&zu=3YDzftvE}WI4{ua zSqcafQAl=c!H1hiVp0R5bn0vcAr&htJ6n`{FFy&j%hEL<&tIPGi#kP$J7)OCAXyfF z=xef_=3+^(rK9TX=7Kfqzmr}V$xf_^B~j&by^s2hL2v^C@Mt@n33KJ0lm zbg`_pI=XYPa_H_|TzO{iCX1?=rlHZhec6L6UyIZ~Z9bBk3o*Utt+0BPW~EvMar89JEndU{fN= zmz?Q)YXl9Wgjj73tgKVC|xy9S0CDf9gD^F>=W_ z-%SdY)!0}PdJpA|T{F9PZ8pmE4iaU%M%m=rIrVFrsNC93*VSxyCvPv?-OMHtO`gw^ zU09p^C{m{T@z@u6{gfrbz3p%JOOD6&ufLmMxB|L*Ft(bF)Ae^$CKMfuM+OpSZMehH z6y_H6s#!LvUb4Kf3hk00(fVq9`qi8h`!=|9LhqTS=k&g7s3@WYR18N;ZDbqOX69S) zi&9v{;{jn^>KB8Cj?T(f&pr`jl9GhJV88bbr?baM%I!`c4+v~Btb*-wrsuRW>Bo+DfNz+-=O z^h#a^^O>1!tISQ-tW@I1E``>e3Rlci^7S{&ZIJ;ToGOW{t{qjJn92do>6)Aj^(K^Ozu)OU{U)9ZDFFB0) z+$pW|(zKDfOU_ER)u((_;O)y-DQB6$P4-`^SuXuF;P(E2lG~{_M{S{3U0#J4@qTm7 zUD6m?uBB`{_9Yd@k!8Q#?iDZDv6rckI@k8ifdTu^ zEM3=q3rCf%*ey><0hVgbGf=Y0y0Ct$zMS0UPhWcCh8onbJZ=qcQ@w1G{M69zs-AdB z|GI!(-SMiGwGMmV86iVSt+&-g^@ER9uiDUW*e)2hGCM6Q@|<_VGs8TyAca@!OUZ@0 zk}ZNB^~-I99h^n&KKJ~nv`n(C3w_=tFD->JWXpt&<^zjrP9=Dkj<{`k57~Ou4*D5- zRPm|O=&|aD<7x+=T$Xx}R#l@0Hl*BgeW=4`>Nw@;ua7&-d)%hh@9p4TsGz<2(fd#5 zmDfS5(h+y$ufvUL^UMTcnMNjlb9jEHZ>_TDKVP-nXO6W`&ly-h(u)k~}yy(vY=5XU}|~*uy_Jlp|M^ zzZ4d14LE8{D{7eMv3|WND*5cn!W2l#$SfDf z<=Zuf18*<6Lx*7%vkjq}8qO_cBW^%O^r;78;ct~RA{TttJyoF#K7D>DE^b-At-3cO zb6JS2*=j$3@#t)h(dmSC^O)QFBz|3q1f8;?%`?BbJH7+tY&P0HW3h4ysrOL*x-!oI z!}mG_!=Qy6T+xl&tzJ^PQzxxcC8G6Q{Xn%_+uK1We@S6>`ex0+cEkm_ zgOt?Dd_7qf@-nok;aGpujR$JpaYgfXTR50PN9WI^K z#xI@Yqqnx^L4b{3+k&(u5ehcPVydVm4_ihPcoB)W?f3O0BO4C1&*+#l(n*zeU&+V| z=SAWCr2K%fxAUY$aW1KKF`EyfauQrFLeC|i#a_>UE-LFH!rEkC<=t*c`t{^CX7r2x z>-xFoQu67YTW;1QMD)1HfGZ}YtzO#S!aAEWrQ5VoZeq=?h4bWO&o6{^V4rCW6#1-% z=;gsiBcoY*tC#iFMRlz=vS6Rdm+#Afd~WO=(HATrWL)v>X;zC4@#)GJp92nuwWLI@ zI9H8n*s!$h9W9_LW5-h61A$lc+jzy!T^;b}Bag~#&XbJQopdDOiWPw`joPACo@b1D zKo>nW*&9nSML$!DRoh0s$u{to#pqgQ@! z=JfI_=jQka4BO!0^B6?ZiPZ2pn-3`Xw54{$w`-Tr@_CC-zSTUw!G6)rh40LFpY3^; zdh2yj(w3ny=}??O4|hv$S63LUQ~q#n{l|c4=M_4p zK=Ms$$C|z(^`BthZjQnM&x#?43~>^A4RplVC$lIe7Mt4>U___QE+{_nYkAnV=5F pC+|L>O84>3vOas%qCE4XZM8|h%NZ+<8ThFTLLs}6&f5oV|8E&tXX*d| literal 0 HcmV?d00001 diff --git a/res/s/conning-b/3.png b/res/s/conning-b/3.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ad1bb108b850c090fc81752e6a0e5a39eec611 GIT binary patch literal 7820 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 literal 0 HcmV?d00001 diff --git a/res/s/conning-b/7.png b/res/s/conning-b/7.png new file mode 100644 index 0000000000000000000000000000000000000000..9f5e23fe712336ec284373b0d460c0b3667da1b1 GIT binary patch literal 7340 zcmeHLeLT}^|DO>>=7)-^**}(_;8!CMv`ve9*YzR`D_jsM2h1DAQFt@uwk&c z$G`6n${IA7oA%o}T3(Xgwk9EPpnMQ{t9AZyt0zC1k;}67`_&oCE;_6CN^R7gH2G1q z%|_sTV`*0Yi!4!7uB*v<>`2@O@SS?wz&~@x79I)d?G6szAy=|KGoU^(b$w%S+<4J5 zf1S-|s`ym#lHmRBt)i!eTelTp$j2g26s+p)dB1d^TBWYyoc*KNhARzeAC?BorLBxk z)umgf>Qz2HgJ3zwlMw ztspatiliH{n$ExV3eR_kT@yMrol!OjIripAFSa2wDmY|~ucPDJ$`iTVgagSv$vL+Y z&?Sp`S33ht!*wFKwojSq3V|i|b4_%;j(XVbv(SqahoLt=I?MPYaAxy)3*mnrbh^Xm?IZQ_T0M<_Oj=&)<+7cb;=P zNBtf1hBwupmR-&!yepzbprI>rUnFU

_{-m9Di;h9Kjv?h>vX&t{ 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 literal 0 HcmV?d00001 diff --git a/res/s/conning-b/8.png b/res/s/conning-b/8.png new file mode 100644 index 0000000000000000000000000000000000000000..429fa4a57dfa6bda6500efa8701ee874279b1b3d GIT binary patch literal 7833 zcmeHLc|6o>+n*VPaL_?%VH#Vd*^FgoY-ubbjD5*cW@R#F#>`k-j8GyimPkTTsT7gO zIxQ-xw5X#{gCt2QIZ5I9S?W0N+k2kpd_M2<-w90<_r9*{o|!!^Bs+zL zOBaGbAO(A(wHxq1aQY>)0QlRJ9f<{jAa7zkd<1UfNGO-bVK7;As34k4hti{%3=k;l z*-(~W+FM=uT`xA;91?0LT<4*(&b)=Tv?@kyt@-NDBk3SdZ*gC+mS+D%@AYBSC8y-y;q*H1|bZYu(qkFKP2)$A%4k=FR+we17g`Z+BbU5l>gsr=L&~O%kiKCVXu% zoynJnyzZMlX&2VrR8zcYo4CY2FK$uz8AImV3$BEuJ<`i;UoCKPct!EAZtltODs0xZ zsloafYgkEA8mPyHs#vk9%kxaFGG%YblzuBq%!f~s{lcrbpM|AIZ9*uXCvg%?+Yzs`i$?S0%KLdZ7D;1Ocp>w@T$>s$IU}IjA1PBC8 zRdhKSe8)Dy3=i_OzLz!z0=xC?gW~px%?u(oHGJ6j;0e9&j>FyxS*S{Fv*;vIsw6{Y zl-le{@U%%k!!Q~xun9SoTmC8+UP?Hh<6}_CVz8Uer099Kvfpj0Q$y^;xHurZ>N4E) zcQ3S4y|m_&zP7X`uZXaJTYI-1ZVTbd#kPxmjJtl!N`BTp>hXSd*Vch>mnGQMwoCCJ z%eo8q;$1`B89DfoivtyRV%%$scRbn=zcipND&03G!ad$F+uZR!o+Lm^ph=QFmt+bG zqR}a&)gNG0*-cm5Rc_0;Ek1IesVs5TFe&`u-FGRS$S}D#jn`AB_W1j}o|NN(UpMsq zzGBPviF=h!Z#xt9Pq~(TEpUG-@ove3iH;A{*YlrK9HQ=Il*sZzH%G$xD8cSvVK4{; zPGAxUF7^b%_o@eKJ$L&-bKPDD>=$=&tM8hGynlb5s zMr%Z(KOMzeTd+`}d{BBS{zaE>;+`<%>Rb>6xo-q5FBuuf=n8Atzv5IhWGp{UzkaCH zSa{g^;b15{LelzDT*~03lW)OUrXo@L$|L3aUziIMA;UXtUt~y(bK;&Gl~z5mAZZHa z!!v8Zzx)z+5JoSJjE*d>sETd9IQ|uE`iOV%6U8We%I+#RKoB%}5w@1|kSChxs_UKnWZk9cqX$M4;d{ zQOpPfn8iY<8IQ)myII@LQ2{IT9o zJ@_8LVSsd_^Eu%>D%~c6&K79RUz9I!qyM4Fe?S4i|3tuLh4beJ9nPmun`RPc(HKY| ztC`T}FKTD+Sw#Hf8V63nNEQWwZ z&2zVB^95u!mHyqG3Amf!C6b6k3H!{W=nwU@+IAaEFhH6?&yp@Z+Im`et z8{dq@g+&%HIJ{7Em?M)N9`y&*gBeP97m%lgLK_>PQN~6lI5gG-Wr#ul0rH~r_&}*o zbD~j*xu9uOye+^;215b%(eu`Kr-#j6&5j=yb4DsCbf)F;Wa_kv z<}f}vf<9XXfR3}bsKI1*5FMDUbA9pM&iqNa(v8q`Itph3#{$&`H$)py;W)AZ1&*Pi z4JmYE0}2(3nc3hU?0gPG5J~3It%88Y0rnZ_+nIfau9~T`)qh4u2GfBc^-)+n3I&_p zUZ@#zdVGFQ&un@=I62|x3oxgNHJ!%iU0^YvCW? z{^@MsV`(Jt-JTssc>(+`uz=!VXAPQ~eiqc9N(U^mT;fJP2qgFG^a~8i$z1{%r3Lm* zHqw1kiZT*%#RfEM02XR*ZRG*{ws~~xUVqOOH!b-=_^%~H>=2th7u#1=x)!D`NGV9Y zw9re|b+tu26J~Kd$x6rK_*hcT@hhuzZJWHci!&r0L1<;!_6;gZ0q$$PSSOZ+z`GC~ z+nxHmHT$>LR%H#`8;N}Nyz7gu-e<;d+a9ero7RaHkeBCcHFnHkt z7gv2dU*%O`y|zV9A2{xmkr8TC)=54msl-80XT9Dn65B=~@9Q1=Y7Nfz(nlIYV&ZlL zqzlypH~c2$u+CO%`~7wG7u}s!{8m!DRvR)Ncft+FTqm1-zl3N6jt)F*cG$2-5{1}$ za18_^R$ux>4(u*+SG)0Sr*Ko?WugypmBh_wp~W5c>uh6o97s&j$@5%doEC8@?Ch&MDp3qt^N)YBpu>tlIT} zW&I4<9oda4ifiYJ)h?nw)?!s#n6RqHtH58*4~N`Ks8a=BwqbJzQxkVFq5Z0c!%c*g z`;S=*th6L5H^rUA9eX0X_TZgo>(^<@>79P{>qJ_BgQVoB!P5o3kCXBOmh$DjDz8*t z5|#TJoL5a!czlhr?Bt+HoVlo#`{nbOVUqar!-|m6r?Fi7ao&j9$qly?MoMVGpJi!?{lzfxit%lW#*~LWM}NC{J0Xo> zbwUknVK=o!T&P?>ks!|^<-cc*jNFs3kS$5q3%4A`iNla#CKNEvjBH2H_r- zoTU19n@V?*q1%LAIi9A%n?gC^AT4%VVA-LCZ!#M$-gqi<$^lPFTIh7uyK8+g67A@H zQ6?L;pVdSbV?;+a#&={8!Ft{{6F$97qR%I`OiFH3AFJ@Vw?phDF4+Adtkk1b=<(>6 zre9;PM4Stb%@DqpzXfUiSTNGK()$BiTrY~d)!67&@1=1^C$Y^At zpX-0+XND;~Tl{$^g!Nm0zQnfm4a4Edw&|CseNb-v!^It{VSXz$Z(Ah2++K1(;{3tg zqjsl{74?wBYF&-3?Yh5@!2o4PYo=h$H}?8>OWZaI{a_=^9B&4B55{1Iz0>wLf*aF> z2(;kt$V#v}A-=*2QvmuV6cosOTRvv@^0VLRSB}EabDzU&Ch=B?AoC?sJ5FsZd;HMC zcaait_o2*=)kR6dU)>Hru%g)tJ)cF#LvpVrqx6g9zH*y3 zWcW-hLC28LqP~W6-2LY{dI3kijdSHHA)R?UlXbv{&hC7F|1;+*;ut+HygWe4-$>B` za(kEd+e2VKMV8j(Q#v<3C{H}84XY&o+Pymr)SfAKGp>UcgkT_Sj?!4yGu=`|kqY_l zGN}r=42g|LxQol=yz}ZZUM_#)tAG<%)HJTBvTj;f(IA7p-npf^MQEa(Ej$~SCH`n> zx_78|wPePHfXcFEW3ueg(ad&aJV&>$OsdKmE((28)>-Hx)0-TOk9js0w>fK#@9vIM zmAY1vxrNFv;yczhJQ|CB^gyVUFnZ;&T^y%(%k>W7{@#aAEG{gslGR3h^9yTnes}fU z^Gi1zjUXE|i0x9_e7h%(gxRT-jB0-~8zy%iDsE9-lBej8r2G!veD&l<)y0#|ZwaT2 z2STM9P6l=D_RDH)A#hdCk6d<%&I=J@!a9zh7aP_-RWQ7AXFvuNYp23$8p?TEu&o7N zeKg%!-Tb|-%}d4J2*#!}t+8=_#<6z@`S}qvDLl%hknMTg#TMk>yO zERf*6J#X65MT&he%`1wecM3=L3rWj8htUK5C}OQbm0urt;2&bNrNS)Vvd83hRn8Kei=TAKhzLbkd;aMQNj7%30ISeI2{ihT5XHbYz?QPOVIx zJYss{>)^@)Y46q{l}$;00aXDKWUW&gcU0;X!|EXo*aeUCQ>!ari2EfqX_s>nb@Gb# zNE{Kh9;8|uZj-gF>7kVF?a+{NA0bPz3BSj5?g$**E;pjF(JMu`?#!yy za;%DjP{xUEZ+Nr}lk%9*)xX=pGET(YzPm`s5Ge&1#^;(y#D>rd$S=15esLmw1Jy1!0y!2ri^dHde2 zxWUyij)lX^&aW{(vPDL-ZTp_q+~Ff1RccEwYzgR(d~4*jvIfZu0e5+;8^7<@d*!)H zuTk#v!j3p8#5e1PJDB8mgDg|Wb+4Zz3M)>(jiC6RPV}g|k9(&B*D`N;c-CgBcggvq zmAcUDAjIbULqlhD24Y4`LdRfG!-o?vtt_#!<>`XkDS_J-DVelQXa|*w_9j^Le!X%O z23>0T>9$Y5xn(W17f+BjNsG)8R`<6R9x`!pw~^iM1y`<2)mC;%J&=2Ru;g7lv4#6) pQD$<&(o4r}f0ymjE6@HETNQU~gp{n74SW^@+1rq;&#w>M`7c-3bVL9E literal 0 HcmV?d00001 diff --git a/res/s/conning-b/9.png b/res/s/conning-b/9.png new file mode 100644 index 0000000000000000000000000000000000000000..95bf53e8a39e85c293f4e6cb828b7719d88a3f98 GIT binary patch literal 7867 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 ZntICyk1btu3jC}FAzM3Im0S4l`X8b*e~$nF literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1.png b/res/s/conning-s/1.png new file mode 100644 index 0000000000000000000000000000000000000000..69747259f43ba4fcf59b7f9f99030b79195ce56a GIT binary patch literal 652 zcmV;70(1R|P)~~~Ie>;OS>h2uC!UN)nF!G1D*zYjvrN`C-Wo62SBM@0 zI7+C~2GIIRkyHZo`VK%@c_Wj&ZgQLB%Or19lX16cYJ4L=;}HO#1Do+=JhU;KGM6ZF zLq|k`>m-RnVt_V2;sC47w1$MwIcsSoiYXm;^D-`&&!+D|Q0f7wQ;B*Il)Ca={`XYh zD|UFz%eVpOy5`(we_%y`(wp7h%+q*+M3b)<+^8!B&iQ=Iy5THI3>i@{DtKIb6E0m> z#uZxp*$~@>N?5()5u3z_v1=9kzdJn2kVaFvJ3C=x#>lP zzI8TqM8b)K{|piel;cm}FLsJ`8XeT1O~`jV)^LK;yp0o! z6vqzPP76GWANa?mtJpVSkrMIs%wv}Nk{}$zC@qO^VX|R|&juN~^xh=CrOjnUG@ni1 zf}kWzu`g?*E0!FM`>Y4#*^VdUW#-itQA<@U5eMXHJW>^xNy(ozA!|2@h!a)2^|nO+tGly$(B*=_I||_xAhl1eW3lVHdy!fHMGnK3bLl3IHDf z;yg=NHk$Vm@Pkl*ZU9`{lBFyF%=0Ww8WEtycK~kHXHoV}YZGH7*9y@Afb)`fgvj(a zkJJ*N)z1KWO36!}rNut8xxYv9#%r=~ROgKf0fJ8ebh&YyXX(-gxJH+FWJp8A15afV zogLt^@S!QV2=_ivmr3F+*?53)jL0@2TdPdA5qcvj>(m5>j9Ed;4+g$VI`~N%lQ83B zfs2?Nxa04lP0X8!$JiU|Ut9wcPkPIh^aoF6W@20CEx^UlM^=PL-(znFJDe-vKKns= zew=nxw{sc$M}n^y<|lq%dtktqokOFg%sC}zQen)4HGva92;cDCwJseJsEEPs{B7Ie zWkbNYMSlGty!V5!(zg$2y$Jz4#(sUmVZXj%nMhK`jyRZVSZV?jwLrd29f3n7ejx-t z)gLRKUKS3)!BdmShw*@Pz*kcyE|EF-ObB8x&(hdotm{M%zSU97kV(EZ_>M+^r8ng3 z%nZH?0rr7GMMHb=3Fl6s$9|m$WL8i7AdGawH~_dAMkAf*bp&EAlnqfEZ*XsR=rNSn*)UavL1o{Njixgp+>$NqW_;0rS`+kVImv6o#rA@K*v3RUkoCHACK#;d&_xS&o-n4sLhny`9~inN7hGxqQI~Pz7)cpvXrf zBHH}BJ6RdNjiUak8_rV1IF~Op^|ut){+<6HY>%2Ncnq&# zU`do*;4!uf21%0}0VZtziBd@*6BVH1dg%Hz&~}Mlm!nlT$SpFA&l?g-F)=X3+ z?ALm=JgH9LnoAjWV^x-`ftS0OC?h_N)Ya!xu4W?s<*2LKf!WwXh~MI7eUtztK@=PgB;u$-6+%!ot*R-eC_H#ne*g+qRfXaQ zRN=vc!cbL1J-ysHRDlFl)x2i*@^Zbx2JUhdeaYqc*nKlQ`|)OTu#8HzRs_%ha1Ef& zN5_iK8-PXNdwZMAM+sD_H34b^XxWlwOaV*+-&>tTfFte#=%}A1*$aTBd^V$GTOoP_ z;4Y%h7{KT^MPdnX)K37)YBZ8$eQen5UnY5@n)G{&Q{x8#f)4={*>Mo~-qHp*CYLDE z=Rib(UX(;G(m{i-*uiQs9UxI;&Uze)d`!cOq`)P1+s&uzmgWF%sl=`8mS*z1{O_o? zT{c)J1#W`5ddzLs2SNgr-mLaPlHd^%1AgrgGgP3>_w>{SXGvno9Tj3aoO`ofMrnbo zFc>Ytc6hvk2aDA{KPQM`c0r?{g`S$j!T1@}|002ov JPDHLkV1i$K3jY8A literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/1.png b/res/s/conning-s/1x/1.png new file mode 100644 index 0000000000000000000000000000000000000000..258bd7041c124bb6bc2d6a23017dda7ea6f8de73 GIT binary patch literal 354 zcmV-o0iFJdP)TldWz7K@i7(97$_vGV5@6x!{Y!fad|g_Zd)Cs47$y zZ_z#g9u(#tfL!hzijM?U)eM>25DH;wm}IiMng4&jx5k;oN!kYbfSygWu7M1gl|`PN zGQ5L0NgKes5x;?XS>!9TwSXQlFh`TJ$PeCukv}bxH(toD3Zj{fJT6Ys57kSgD~>!q zvYJ&Vp$-h&R&HIyy#Y_ai-hyes^gnhGY^QW`_Qsy7TN53cVw`(v#T3hHE|GHie>s`4V*=`+p4-@p`zGKxpjSs zxFs+YaUH$uoUhd15OHIRK33dgKGRv0@b3)#0(JUnF;aq^?f?J)07*qoM6N<$g1B#) ABme*a literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/10.png b/res/s/conning-s/1x/10.png new file mode 100644 index 0000000000000000000000000000000000000000..88398b807950bbadcf6b8c4bb526f11dbcc647f3 GIT binary patch literal 355 zcmV-p0i6DcP)DlRZwuP!NPaz!D9`bLTEmlmp}d^mH^-R8({{R8+30 zs5n3lK$QcePeXTch>zYtkWj;(i>udw< zi^QCDZjUNp!B)G*-a$p;-s%0+-8Tn-CFl~69t#!7I<+H1Lf>1&EE$c}?xW&-|BohU zd;`mYabl@7iH(8BY7U?xV-^3b9NAq0z5%%?920V5p}iQ2*f}xA%F^ml-_E*Z2TlQB-iKoCVAhSJ5lf^Jt!4nRed^c;X3AXlJDl`2&# zPLczpPnX6A0L$(|1xTr=&`94a2#HuCMq1g{{QqaX^XH7c@FCs+cYr;wl-&X~un%KKEx83ins*UUE4e*YZ7%4a8jd^jZfQ(faYHK2sWQDNi%2nUNwH%fkhOKQc&h5*&Y6Fa&t8VT6{q6PR r$OV?pRWnU)X1M=ZroAfp>kNDXG|gQVyJ$F~00000NkvXXu0mjftxc7M literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/12.png b/res/s/conning-s/1x/12.png new file mode 100644 index 0000000000000000000000000000000000000000..60b88e98108d9c79760a34ca42ec6db4f5f0ebbe GIT binary patch literal 364 zcmV-y0h9iTP)bQ>$(QK@>eKq6Trt;bte ztji(~|05!Sb$$TgT?4-WY|0|v>D@hmM*tHgT9!qAj076I(oFI4Om(Lutn4k~tn(lA zb3q+M5ua(#^kpi6Vn>YaiYE>oWYF$o4N`q1e{S*SDzw=8aif_Cl#h5NixM!mFrBk zO+S^DV#KoT(ASl00Zc{Am}l;}qyK@3S*Vm3#9ikxwX&o?X8?bB_;gc~N$O4j0000< KMNUMnLSTYvQJQ-I literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/2.png b/res/s/conning-s/1x/2.png new file mode 100644 index 0000000000000000000000000000000000000000..45eedb2bd3bfb08d5774729b017cb52df375dfd3 GIT binary patch literal 376 zcmV-;0f+vHP)TQ!P&eK@ffIS;TA*oZHO?RaJ$;^8@$;^)Hq=)KxjvLKH&AM~dMm#jp@D9{@%vhGLrtA!6PD+><|`zt-z9u+C2aT+qTyn{+Ie zv`c~flpSbJK0JWC6BKApv7k9kCSv$;zOVCrq!_+L%sU0X0o;k0XCCLCsuK~zWX{1_ zB;${W8F5ro3@^I`L<}c!Dq^lg%qt7FO`Nl%)_EQ&N!vi1T;!~I|8tpoJ`can0Db|j Wpo6xiH*HS<0000LQ>#wIKomU;0#k9v)y-tG3bhKge({Up8{ijEDAfJ} z4ux7(g;|H`2au+9RXmbaC~}%RFr5I|!bzr`*E#n&2gu-jm;+b>;J?(<9zYGC>e{AG z86yGb!v%m-0QUg4UE4hA{tUnZz)FQ~y0+Qz%w!H!(PAVMoOf+=3*cP0*3O3_wOl0g zne$Hpb!)#>uITR$w)1jQ#Lcy-{QQ05(?|YBYGrkBEH)a3*3;IDdP6 zdCzr3EZ@zQolac@c N002ovPDHLkV1hZpoH+mh literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/4.png b/res/s/conning-s/1x/4.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a9a98291b8672a790d8d7c08c04c36f58cdb31 GIT binary patch literal 405 zcmV;G0c!qDlc7$-P!xtgx+NIIt*dL(pl0X;%<}+KQ@j8MHHDg* z;uS#c8K!2yfawD)H}|?J+9p*fa>nV>m1b=GNtd?weE&VC`|kxkij#B(WI&{=TObEk z-r2lO4EqdJ8}ICtAH!>449w#s6@!I$wwAR(3$EfMowwi@=^#$hT?gJ-F?$B4y8a~0 z-T;`jxAx9T%MU=^d0%^HA9bW1GmMio(|MSFR_;z=LW9c8<00000NkvXXu0mjf78|bf literal 0 HcmV?d00001 diff --git a/res/s/conning-s/1x/5.png b/res/s/conning-s/1x/5.png new file mode 100644 index 0000000000000000000000000000000000000000..0595e6b9e934e664cb7f718f3bf1352a70b080e5 GIT binary patch literal 411 zcmV;M0c8G(P)Dlc7!nK@f&Nt^!jr3+CKi4itt{C=3dPDh3P>03KC^ zLiH8EgF;ndz)*7!KsLATT-&4yMdmVXu5c-|lWcO?`@i{jHvew1qLMUw0lGj16u>Z) zzGxDi`A3pwT@lw8amjQtu0Hh3yZFS-9WnY8xg=v$$n%p^uU@%K=^YZ4E-{tCnrm=E`DQ=v}8KoEVjBpAf3qOMJIo_+ux{3$T-0hlTj>eQ+G z1zZ&$fJbqr4s&T*R8egcFsH~%XPa$vgySY@(w%wl&FC~0XzUm06YW89b5q56Tl*jV&<1sS$whJIpmdsudA|nvH%;* zv8KnBa)$0yUQD0k)UPJz0q^t80B!)JUE6GT33P3plARzYp+HcT#b$4shH?V$fX<_!KpjT$?7u|i)SepV;(+Gl

-T zFdrG?@9xCT$@QwT;0^fE#x7`No=Fg!lWT{#Dlc7$;Koms}g#@#rtEii%;MotrgI|S$UqG!|g<8dD zpzy3;1*RVWlNnbBBq$WQ!%Hd6rs;B%rp?SdcV0U8?a`Afs~K<(=v@G-82lqYdnYmY zmoCv7xU!l63j-g3O}E&L@3d~FpRIwx+HAU;UAeNl29AJk}@HjBZl13f7i%7rT{Dlf7-jFc5{G3777pjs)QWJb?QQ;3{2KaFxncDpy${ zU8)S=-UE05gCIMl_W;2coCSvYQIrD+3DkY>oyfbHn(!g6B;88l+1b}#(yrumZu18L zAL2sNgMqJ-j#t2kxUAmETa=voLBKYj%xPb8y0lJ}5qacq$#b@kb6;}Wjlfj5G$RLlP_)pK@`Tn!pe#_VAerM55NKH*VUjnKotsAg{rDT zp?ZKSeDTzCfMzn|#sLWjXg>0_q1z^%Nnf(r$-Mc!|L+Pd84O2b01W{CYiSdJ9e_;? zes@WH85j&l*8m;_t^sUg@bA*y0JxRm`xyM`n*qT~d3w5h@RwB5({qZ!FLEG7)WqOd zm2&1cEr6Fgzg5a>T@dyRz)A&fI`Y2F%{c}?kHNo+8Ph=hS?v-LQ+GY6zo`ev>+bF<@NzsWIV=I#KT*aZTQx}WF38oUXBMfZ5vCo|V$YjTTe<~VR1yq6!# zl;N3E%Nbxh&ndJYJS(l=mWg3=8_zIx|66AOA0_^3E_g0SPyhe`07*qoM6N<$f=s`Y AGynhq literal 0 HcmV?d00001 diff --git a/res/s/conning-s/2.png b/res/s/conning-s/2.png new file mode 100644 index 0000000000000000000000000000000000000000..eb6a4a41cdbe9f7f8e85e5bac32a7e7b8031d080 GIT binary patch literal 709 zcmV;$0y_PPP)z9Km&aOFmxqLTmm?Yqwuj70V+N!1XhJ} z0Jr)%SIM<`R^At~^PNOWGg3-`s!srPH&J8RtKHZluXfWo3hyfkF!&b$J`GRfD7r(iH*+QD>BTsPATBzy|mDMt~%qvNX9CF$-ov4g4%k zu9{?mBz|yX?yFFZwMM`)c+Aq|Ld5(6po@PuA&~nNFzP(v4T}0YFhC&fgP(@ z3Ac_Ffu<#Q6WFmlYeN(#oWF_HzVoaGw9R9f$669t@XOmR5|}ab=N-O}3;yG?>(tX0 zJRXTl`Wv_9SWA4bKd2mJ^HXrnzeA2uZ9pfh<6eL8^(CLncC1ZE#P}RQ0`}_XCL}~m zhnr2i-%!M8)4S7Vv_^michE~h0#s;=jn6%FQoJqPdyjbRvTLEXQQ00000NkvXXu0mjf-p|SCy zp`xLop`oGj7KJ1zBq1H?d^QW3?YoW)?f%|V_Sdr=C5?T1ByD2-?~`OnPe%w;x7R-g zFa~e}paWo3Xt@Ni2CxD!OXBDur1DmPZm&N8a1LM+3QOGpxK85eelGwTzbo`qip|;E zd*4fr&VbLp=HD9RbJd8{0bCFOG`vdUXkFJE)mEnHQjMCl`%pF-FRF^##S{ z!)czSKSKcWEPcqcbZ)I%aa5$vnYC_FtWgQTLUTe4s|svszqZ!h0ywRLs0Ap4$g}iY zC;;34w$@D*#Hm2Z_fG)2z5Ymygt`Jkra^{wx(h%7;*1clq^A6Kguie67cofU=*_MM zp^{Dl_{7KG%1deZ&pAJ5O___5I9hU9ZafXwuwO1;n*=C$OvKx8dj&U^pmqKn(ZlZt zW5c~2+~L}i_c}3Z+g!E?;JrE;p!U!>u)NpEuL6V~pNEk4GL1R~Xam6I*ow55QS&iq z3qZg48lV`lnw0li8)i5#$+RW!wK8h|A27)@Dth=Sm>Dh!e?VNeFaqA=M!fwhxaQ}C zM`n{6YtP3(A`waDzmZNXyQq#i(R4f#Pq}U&2Ik8HG8e1X$NyVywPq7mz zLXe;X%Ubu6Df;ofvex~Qdq&x_bvL79E}0AU^*&d#C9h_s$Nm3%IV}M>{Pi5bA6X14 Ut#fweQUCw|07*qoM6N<$g2muF-2eap literal 0 HcmV?d00001 diff --git a/res/s/conning-s/4.png b/res/s/conning-s/4.png new file mode 100644 index 0000000000000000000000000000000000000000..e8645dc4411745b205930e6cb1bb599deeeaf8c2 GIT binary patch literal 769 zcmV+c1OEJpP)2^(qANQz1l?pgLwN@`mQYDx8?@1+;VaU99cCq;?lyZhdK@7;Uv-k~I# zt#${12jCOGz0AxRfCYd#fN2y4%Q7n;V!&?zjk4nb+yWR!VX&ymfbRgl@$njfue)rv z+9y=x48VCtoe2%eRpbx@ghW(0;es~>V;eN~f`5q${U{9l?AZ4?lRabHOJiI=P2y+$ zUw#|o#sF5aV2u06es3d9;$@n|_r|z$sv-t`F~)sJllaLV>tx9RjA(r}$Pk5r_|>Nh z-F>P>VIYC|!2Kc))=^C+A_vh~JWPhY?GS8LmAb*9vPF7~@`3F7emT0(qa( zB)&_N_XAOR$$;2X00kf4h`Ur7;wsm`?|?3DA%cD<@efrp9AIc93DNC zJ=YaMxx95Es^jSGg3aX|JiB6KQ}Iz?b2+v@j<|8r{^K2Ego z*@*!B!?KGcY*e6H}58zVf7~?*sN$h9d3*ifZU)j4s?!|;s4y;nW_nKwhoP_ME zY;oJVnBYx`JLz5le5QO|W8980?nh(X)vmO2rmLPA;WFnXP2y7h#ont~&NZtH7Eu^n zRbqf;i0o4OM`_{2sBFFv-^%Ba{iSBu-2m_k{G}Ep_)*3U00000NkvXXu0mjfYeHky literal 0 HcmV?d00001 diff --git a/res/s/conning-s/5.png b/res/s/conning-s/5.png new file mode 100644 index 0000000000000000000000000000000000000000..089e6710a7ff22718fba95979002c4822652018f GIT binary patch literal 787 zcmV+u1MK{XP)OY zc%jtljUj-FwR+Cq48S<>y=4*0|3cskfNIW^M*w$$?=AA|9OVF1l+s;DucP^&j&@c=**z-s`b6asGmv_&8I-h=4l zD4fPoI8;iHNW>+{wo-Z)N8#^vtc?&@;9@{P`+@IG(>w%V$l-Zf%xm>Vlim?;iM|{7 z-rSz!t2A&C0ves0F-P=Qv?VqN#7HCw0l#R#_|3^ScPA^Qe*g$&*Js68-YccQ z0XU;4&Ll);{*h(uij&0c*G1AuV#>Iuf~SyZlf-cxg-@b$`1SJgg7f=Db9fh_%|4fO zOeoAAxa9LOE9QG5G3EIn@_t2tvG4HZU0L9k7!2`3MLf{ri}|)wYac=klZq`NaLU1` zY;a4S`1jPYa(KRV+5W`rv+DmMV6d9WNmxeeWr>aD?7VuFCvUbZQA^KXq@o~Mz%K;zI_QJmQ*N@^G zR z{CN*x7DwT#jO9WCuIC2;&H(iFSsaC@DeImRj~;|f9EFQK`v*C|vf~Q?=jO2(yDi`> zYXTDPyPkh1I$0h`^#FH00?;wL5hKeS!fOwRcU;f!ki2?L^oD8P*djpi34j(A$8i+S z3wHg3fO*yhaLtW~2L?$JP7b&%yetErCDgs7EwMQv#x?=Qd}P1}Wlu6?!Ost&je#LC zBGy_qA#gqaiU)4VomT-b6oO6}j=MMtZ#EvFTlBP#>juZSC&s)z*HCB(&Uk(JOUz4< zm@}g`m=0Z|=~9&Ab%QCLOT>a zXPy5dpjh2aA=*XiWr@XdDr?s)$x_^iSS-iHBWQ|%!J1nF-3AFL)=~((@aCjJ0*dt_ z1hl~n*vafvh@l~vIZO$CL0mMjd&Q6!-%7LKp4UFxsGSIH_bukWe0{vXy|&wjk{U;H zK-%rY$B*~7&pJsk^~UUqq#;?qdu$=PWjEAe@0MB@WB@TkNEPr2Z7=O>KUs>0>|TQ$ z52-e~SL^2NPo?Ycvb82)Lf#qmB(x z_0cS0bZa=xAz%m8Qp4$Q#`ASI8%Lo`JjpfkzpN`ao&)#-t`Pv^GBc1y00000NkvXX Hu0mjfMl2^Y literal 0 HcmV?d00001 diff --git a/res/s/conning-s/7.png b/res/s/conning-s/7.png new file mode 100644 index 0000000000000000000000000000000000000000..914deea16cfb64dd665e48013b8f988b18ac3673 GIT binary patch literal 736 zcmV<60w4W}P)a6qDS<8|vsg~c2Y+1hB_q4aWcY8(^;kaIx zh=xSeC!!uM#v%#>zp9-q-W(d>xZXJtT@%r$rr28|nnz(UZ6p9jnD|OPUa?VrYrc=d zU|leMD3{}U?}=zqG&Wa&<9h7gJ0d#AqbZC$m%WWbU)^6p$T$jvRd%3NK>h%7CiJ5) zxUWIZ7~p#X8*J+Vwu=QQ@-Ezc6NSN|2C>A<#&b~^d}AB1)y)%Osfk^&t z|IHwRZTL#W9k}*9@FnB+Cgd7(xmO}&Ij-fuGkSIXBcAzn-Ch-r>kY8PjL#fb;(<^2 zp0-6!FP>N+qe#49VLhbCOxhw>5RMUZTPkQ)HB+q-z#;WuXsMzxKO)Z|2v^_Io5~3V z2v<)F*ejDQVxB@>Pf;o6kqC4O9- zP=IhPE!j5NE!fLj1vq30W)@OnXM<=N!oeHgTCzZI5Us@mZ0~G*9sWp@cx{Z$squjW z#2EW~n#6zA#E~)fqcQfMG>LyTBxn2gI2AobVeo^W>q3-0K%NKiUR_S~}ME?NJ)c+OB SYwphg0000v1Y zx`0+c(i*`Wz@#klY8T-~p13Y7i+tLs0LjMy#3~^il|{ajRgOF{;)TOoH$H+t$d~+J zZ*tgmoSAc$eG~`3|@xF-SBxB})GQT;n-@uS$SlKWVg& zx*(6@q|dBaF@WVd;&fkKp(`-pb>4x`6-%b%lNv#X2N1tH37*7e`b;xjsdK1qUh1-!oBH;&$vm=w@URV7g_fl zPIcq6ZTSbj~fs5A0ypLDIHCG344EJ!~z-bcH?Dw6dN)e>UVp zw=LgxFp>VSDvNxvY2Jf4WDIG*RkXae<9Z)X@q2FQ{c$wQSY&M0Oifc-!>$U5FMUh4 y*Kw}#bnHN4Lb_Q!h+4?12$__23Et-Z0>BqNPvgI!5!>$o0000XOOS6Hh&O@cjd-P$*PY6$*u_ zFA7t9@vZM<5*NkCOcjb*=51$5KS)Eb!<*@3n#8zFkoN>1Vmcd>)+nLUi--@9LfU}Z! zuJbINY-Ipv-2>1xvl--BT5Ot)=`Z~{T(aA(3?TdtK)^NaZyMmQ`e8r`KBN08ZKk?9 zH1L4%6QA%fim#52jz2%%-(KavGi_b2dEpU$Lrz!UIW{C_xA#55m633{7aln0bL3;g z8Tgzb4CWR%uDx0|@Br@`__cVLO&7v;j8!nPREqO0)l|4-MKUxywj0dtqGu0q}N$$kNe0FSqJqPdw=9%GA|M~)d00000NkvXXu0mjf>-rQ~ literal 0 HcmV?d00001 diff --git a/res/s/rescan/1.png b/res/s/rescan/1.png new file mode 100644 index 0000000000000000000000000000000000000000..19c4f777ef4a38fc914b83636580f3e5390fd713 GIT binary patch literal 15281 zcmeI3duUr#9LH~MowIgDYIP3~?xGtGy}6GhH@Vj|UDmW~(X_Rz*nzs<$4PTplAGn; zENR7At03DH!9SdvQ|99jL9L1)ihuYhf}k+z5JW|sf;tr^qoVZ{&&~5RO?LW+f1W~` zU(WgdzQ1!n=W*{p_weZO?hWl*+9`_KFf4IIp57-`!uQ?%o&sAksgak-pA)xYv}CDYMpwN%O~(}Nt@ypm>lH^(NEY@1-xZ1g&c< zNPr})V?hRdLjdWxX`5EuY*Mn?U4+=Eux-Se0Cakqrh&ZCB+cn5r4`pyX{v(|N;E2u zWDL0cl|;nUvd(o4MMAK{tsA-w6h-8 z(8q?GAY&W^`as4^7B@^<$ymTyygjbU z>aFguGS%YpmyOk9(j^fRivdRAyc{F&UWHLLPGn+06}=wK<5vTGkX@Bt8xt%LEOqO( zxhfq#umN6mb!Ewt2r71Z@eI#{0IbTv=>r}h#k{)8`Mi}{h*_;x1r7pW_0kzM zEZfXXBOT5Vor7f$IIyy{(vdLM$gxTjo&mC=IY(B=Qs7)T!$#U_LoQ`Fg-U`3Q?RyW zu`0cJja(e0LhuX^FucGB(l|W8eID84zmW^b99J1?QPteUGGlg5$$;<_+(iXAeN$`oMJsi`1aYebZ_z1(Le%nTeB2zi2R zqh=(_xj#53I$TIfam&CHWmQ|fe!@A*64|2OFL3aW<(>cKRJ6N3b??Pf(eC=xTITI3 z!ww1MYIV&>mU9!6i!k=U2R9HBeLjyb$ksR4XN($okeG-V@ZM%QhX^m0bLu-9Chl#P zh;)<_OB)4w#47HiQY(CbgU^m^_2F^l7OS3I|8r2gqW{?#wIfAP8rYcN!XiQi1Q$vJ z8xveuM5ut^LTO-Qf(wfX6%bq~4QxzsVG*GMf(xaAjR`I+B2++dp){~D!G%SH3J5Ng z1~w+Ru!v9r!G+Sm#sn7@5h@_KP#V~n;KCw81q2sL0~-@uSVX9R;6iC&V}c8d2o(@q zC=F~(aA6Ul0)h*rfsF|+EFx4uaG^A?F~NmJgbD~Qlm<2?xUh&&0l|gRz{Ug@77;2S zxKJ9{nBc-9LIngDN&_1cTv$Y?fZ#%DU}J&{iwG4ETqq4}d{JEOwbwC03ciDxgD+cN z*yPE=7d2^Za4bquGutR?_5q4oF2L_|6qV&D>c>fnlAoZcjpk$fJ{W-Sf?7k7@Ob`n z^^ZcKccD-yY^K{{CjQle-{e-zK6PJVKdas{S+2o zKGCunHowz(IN7OP{}1fk4lPO^b6+gO-}~X`(Fe91a{7c1JO6rrcHO^)0{h@gr_REb zkK^t0@M~Yk!to#AE2z-*!PDXPos-@DXN6NQg^%;EcYQ&>Hnwf-jpt6cog3-+>gT0j zq{6$)?u8>=8y>%zy864x-ho_;^yjf7e_pb9Y;OHuXOxcFw!RzQdS>U*b32x&FDsfp zzj$+JOUsq(zJ6r)HIHb6Cl~JR?jC;blNV0*ZR_d`FI^wGu;byM7u;R<37-Zp^lm?M z;;Hk>H5<>rsUE$2aWS#=<5Zix`|VxXBiqDR4n6%%=f;!#ts(kudW5H{~BQp=d Q>7b~g{^7{{uF1Lo0Gc|_(EtDd literal 0 HcmV?d00001 diff --git a/res/s/rescan/10.png b/res/s/rescan/10.png new file mode 100644 index 0000000000000000000000000000000000000000..2b4c501f86f64ae1b247947c41411f28f28de99b GIT binary patch literal 15390 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 H9i9F^PmSz+ literal 0 HcmV?d00001 diff --git a/res/s/rescan/11.png b/res/s/rescan/11.png new file mode 100644 index 0000000000000000000000000000000000000000..c43ee8ce4a388a9ed1d32841e4eb34fda3028eba GIT binary patch literal 15383 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 literal 0 HcmV?d00001 diff --git a/res/s/rescan/2.png b/res/s/rescan/2.png new file mode 100644 index 0000000000000000000000000000000000000000..406289221559917c2bdba0eadc889f98d08e257b GIT binary patch literal 15386 zcmeI3e{37&8ON`rNt@7A>5qwa>$Z~%TekLcKm6l-7sny7lg1kELh258V_MF4uai@4 zpXa;OPGKT#fC23otB|M=gEou~bqr-c1eJyq(-O1^q=NWog>}FxO;EN`1`=bc=Dp{i zZydXC{@~B|B-@YQ_xn80d!P4t-@AX_`$u>0>g@Pp2Srhxp^@Mi{Oz(oYuhMl)#NAV zKZSqV(`W&~p!(2EW0F(O2!3@}QaCbyKxL=htN58+rmy=Psr=}p}1 zo|0R!rb<)ogHXa@`P&&CmcNn+8tRmNU!kBMcJyevCIdzB@T%9#XaevsV%)_uu^7-8 z(W&tb1}dPUbq@WK@pjl;u09I<`NmjSk`_2pyIBo8DO2aLkGI7Z-I3KLT~4-*G5kISh# z#h91(vCG_RV}c2MrEaY@SEbDdHo&{CR+cPz;2epX#>7=O&+t6(!mJ#eKHvmW+@-}h zx2uv130BKhfr9{8UOFSXX&ISmq{AMfy|L^8KU~^c=}71+cVz%g^mFiet0QO3k0~w&e!iX3~VkNgz?@}9AEgA?a7O0Zuxd`upfMq9F zAzckpQr5)?8=4-UUJ|3hY}qjoWql0zbk`J1Sy2>Ji^S1XIc{WB3sRY5QR`ynP5VeEk~ZouzxyPa+yTi;yoF{kimp#p*nrGd2xE-WHcKyaZnur|Sk zMT80nE|dn=Cb+POPyxY((!kmT7ZwpJAh=K(SexL&B0>cO7fJ(b6I@tCsDR)?X<%)F z3yTO95L_q?tW9uX5upNt3#Eaz2`(%mR6uZ{G_W?og++u42riTc)+V^Hh)@B+h0?&< z*TmIPJB|rb@C;@a9=3dPm)}0=Nvk7cVTw9<6GhF;Qq*S!`1?LZO>q=;d7Pr;;}ms+ zaqI_+!|*KVUqZowNbb$p)k2}arKM%|#_bQkXdm`06wYd;-^2WKPL9jLV-AUX+P5j= z9l{^#HNd2jFUZoP5ak6su*_ki>6 zcJcHht%0?@zwQ6RrH|h`cXY>KiybC${$%HM16{4JJud|^$2z*Hjhj2xJowmCt7ZD+ z+K&8qm+R1zEvx_i-7_--FP`vR*mm^l$H)5LSYzJ)3O&1FxA$*{nE2LpR|YTd{qlTh z!>#ZBGn+d8i~FMQKKNYpJ5PV~s(AZ+cYbT<<#jLrS^cs5RP=v$nD?!JV%we4F9R1> z&vmao_x77Ieevrz=dbVDxb6Wu)HV5)nTV2~z4@IhIj(zW+x^?moH`xqJazi?@s}3 zTzF~Mv;TRf?fBeJKDc<|Q2T%H`iJjV8~-|g?)}t5Z9hHo&TmFSGp@z2{j2ZshfW;b zw0_H_9TTHRPJZjk@6Sqa4<43>-&-_#+qT~E%tzl3ey}k0C2G}cPqfZHa_k;^B11#F KgU=3*AO1hkHSXyE literal 0 HcmV?d00001 diff --git a/res/s/rescan/3.png b/res/s/rescan/3.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a64bc5cd82df44ed1a54a1bf9b24467f8b5659 GIT binary patch literal 15391 zcmeI3eQXow9mmg2$w&YdhSCHYG|v=DTh4dq^Xtuamc-7I6;mr@5G1DgeD~PCVf&2l z96PAeAcR8Oy+{=+X_++2w63jGRFJlIV(LOivQ1QUXwujw)NKf^u0byzfsUU9txWW)hsYOtWH|uc(>W*v2qTN+h*Ttwy~U(VLc3I zr&&&5Jp#*_D<6x$6Gq;w91}(ZLzQyyKc6L`>luMz^7*_q&s)`OoZ&nk55w9Rn~jDF zTANJkVu4O;8_OnDp8(LLtdh|cHElM0#i*LoeHM#RsP?H`S1J<<)k>wc3O&e?DTo<{ zv$9Mo#Wc&*^ifbBWYbJ-Y%&9wQJ|^0tOTHZV{@b61RP!EYL{RXoB(OPsTG{FI~z5t zFH5zYOfH)&ftDo(BtZ(+(I5k^DS%8u)m1H_wkTQaE**Q8I1v2g8 zWiINHqGHtM@-i)L>Z__!s!0jk0PF1U_w=*Zrh-fhs{-cBz2MP zNLtgyv;-<6SK!D+9)6^lOgrpuJ8iewowS>^1KI(vMgqLY$=hsIYb1S#fcZJb@CqY~?+V<76Z^Ahih zx;ZbiD7`)=SioEEmg{p>K73#Uyz1J@5+Zv!Fi?x1Ya!(+F435cA-mag%VFx9n2VvYOW(thz2tYi%zj#B?0Uex{mOZD>sK zGRD*;m4!1`Ze2K`)zz_h0T?@77|a3@E{ri%O)lkf8dK`ys=I-JsDm15jveEi0?P~b z8tIxzS=rzbQe`DJxxk~zY#APive5(H-DOc1m*j$K5g%C+Vrn)e>V739#sQN_$GuFw z5mDCn@}Qbjvv63z&wH6>%}ADUe=tsTxRAusmVqbAqP9l;xN(#vb0xjY#=;N78GkFO zXm?}k?mMTV-HoaB%&(;t-4BoB(m)%Uku2jTCX`_8fDdlK?{qkLhnHz=Zp;WP1&|yM zDDd8<8HWhxtmHIyG)>&yDiP_ZB$hV{@`zR1N99)d00*BPncBnS!Yx)ixjy5denp?L zF=|JOpfs>C!G%SH3J5Ng1~w+Ru!v9r!G+Sm#sn7@5h@_KP#V~n;KCw81q2sL0~-@u zSVX9R;6iC&V}c8d2o(@qC=F~(aA6Ul0)h*rfsF|+EFx4uaG^A?F~NmJgbD~Qlm<2? zxUh&&0l|gRz{Ug@77;2SxKJ9{nBc-9LIngDN&_1cTv$Y?fZ#%DU}J&{iwG4ETqq4} zOmJZlp#p*nrGbqJE-WHcKyaZnura}fMT80nE|dl~Cb+POPyxY((!j<97ZwpJAh=K( z*!YgPI_s}vf;4;wGY?<3JT-eg24B=POT(ifirT-4q7EFQsQ(q=?+uE|u@v=wgrbBQ zit1LM{>I!8d>8a@BZ2<0!k?p`6pMXrZEc4v8;_kgUiK^&-;DgG987U%*Y)(g0N-=i zdbr~ku}EY%9*MlTtR$NH`$5xuu~=LI-+p*Zjzn&~Jv%%5)-Bj_WaY}0{|Ybr152-g z(f8r^BS31@mVoZ;$-FYG2JG5=Mc)}-K-4Zq#1KjhwGaYw{tEVsL+fN0TZ;qYXuqU=+ zBD?d8_eK+KQyUU5A3VCOcjm?Ad(VEZ@3r5)dC9ev-^6ZvxBIxQ`|1bt?R~xMLkGe7 zOF#d0$15)%9X~nuqvO|}+}*WC^R9g;{=M8s*QSNTrl0-k`cK-vc{6k2ZpNOt?c27G zx#wH+H^RZ^*`s%TaAfM4x$f1|T~DPhI@f%m|M&BAmYJLPB~Nt!*Rk@ommW1I&WwNO z%6ps70qZAQ-uduYNAay^`6K`Si&GB=@B86<*NzVTkv;#?xBq%z*Uig=zFy}29__Kn z@z0NOzfya?{&@QScQ;J-vlsHoPj4SNc{n%yz$0DPXDkn|J00Bl@xFg}K0NtE*E6@C zbnkikc6ZO*+2e(C{F&K%-my#{3jg%H^9^~^G4K6_^;b;PiS{4gef3Kd9R~f8;P$}j IfymVV0e}wc{Qv*} literal 0 HcmV?d00001 diff --git a/res/s/rescan/4.png b/res/s/rescan/4.png new file mode 100644 index 0000000000000000000000000000000000000000..f92092f017eece76d62846c8888f7cc8689cbce6 GIT binary patch literal 15397 zcmeI3Yiu0V701UojuKafJZNhO3abf`VkP65*~je6u-?@1`UTnGI16#$1D?lSd&ut2 zWM}N1SS<-IrKtjqLTQC4Ehts1L9cg#Zp8G%N-1*(d%$NJMp&k8gt+%#P6xB935F3WStGv&O4xOppeS;&aofj4iue zbRn+{ZO_fpzJkQr+eLSK1$`s&AzzP~1-?+Hz-W9x^o6BPJ|v0$;1-{s;{}$JSU$*b zyv#{5$NNeb9c_hHB&#Ro;aFd(9Q@Zsk2{VfvurMx>&yi@&FmPd3hDpoN&5m+ACDKO81qv;_*tUj9sD!IkK)|v3w`T zrqgV_NZT0()lSxpv=jR+zzzf3oXBbb$~V+c)H?}#SGwCJB7o!6RSx*Ya%v=eQR*1T8k0cp%bMxJ zg0YmW4ZO+QMVDu9WrdZf7N);!Ebfyo36NM4FbWss7(X9W7**p0CJ9s_7|;S?RpcY= zqVQ^;V1Y=nS+9;&ar1!=c-NJgB})Pvqp+?sNiD=PJP$-zm4m|v0zgUzb(ISR%e9bX z)mmjZ2!O>?XTY!>GrJ#Y@Ve-2EW5zIh2C;Q%2*=D3Qf2N$cpA|Sy5YoW8rlh@m0HA zjPME-1$Bl1C`*|Zi^3b%$c=+c6z<_7!}}S(lzPNh-EHzQkhy5J9Sl;_Cg`&;1 zp?j_$iZ<7VRwM7t7*5n*s#fDhqP&NgT!66)zPN#?5DEoC5w_M{8!=?KAT<&*;Iqy4 zHW6MZ#nd*`4cyZx5NRj{78eTgid9%gMK64TgYS-P<>hhV607W7pR!TCqfa?8nvN7f zX<%)F3yTO95L_q?tW9uX5upNt3#Eaz2`(%mR6uZ{G_W?og++u42riTc)+V^Hh)@B+ zh0?&<1Q!+&Dj>K}8d#g)!XiQi1Q$vJYZF{pM5ut^LTO-af(wfX6%bq~4XjOYVG*GM zf(xaAwFxdPB2++dp){~I!G%SH3J5Ng2G%CHu!v9r!G+Sm+5{IC5h@_KP#Rd9;KCw8 z1q2sL18WmpSVX9R;6iC&ZGsDn2o(@qC=IMlaA6Ul0)h*rfwc)PEFx4uaG^A?_H}W! zR*z$X3_OFGgNH4jyKDX`JgDi@28QDlHMNnV4t|-UuI1tH-zaK=qo~WH6eT}RQJ*)T zd~mi8o(27IFxH)Lf3MEx^IMzYb<>8YPJ4$v^LfuTBR4mni9dbFJ4c$&Pv70${kiQI z`R3*x0s50g-So<{@bH5Lk3am;3pub6Hs6^zyy}BIjECMUUub!9^!~5IV-lC(=Sou{ zl|FZ}?Vyipc`H2qjrNCxW9NUf`uJ^U?p?9*m64t8o7WtB_kVXkoOyUqwEooBzkb`9 z%X863*Zv{6Y|HTrs}5~)FSdByNzBc(p5EF1=D+5S{^IzBO;2t8(G4Ac*>OisdF98; z-qo~|zdW8&gQvb_Uv_`~;k9=@`O-trpI);&a@R=nh1X9VVV1XyYezPG_w5(%{6Pmj zb?MK~pIUog2i@m>u%$ufBYh{&v_^zS?v2HuXD)+upoo{(-kewoN4Z1K{fu7s+flzb zeAL8(e;mlo*)z9XogUkAbT)jy+rRuhecu}E2>p(G_^&tqTYTgEx^qLP z#g(tka#7`y`QGeg+qt=e{oCLF_#yFteyD%_y7TX^o@_et*ohMd4}TP(td?WLGu$U|T2Rzr?~d3@ I+eWAV561ELkN^Mx literal 0 HcmV?d00001 diff --git a/res/s/rescan/5.png b/res/s/rescan/5.png new file mode 100644 index 0000000000000000000000000000000000000000..279fd345a487b9ae71b1280c822a3ec59aedd5f7 GIT binary patch literal 15381 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 K(1F&z&Hn?*+|`-@ literal 0 HcmV?d00001 diff --git a/res/s/rescan/8.png b/res/s/rescan/8.png new file mode 100644 index 0000000000000000000000000000000000000000..3930bef02fcfe8cf6679dbc7642a7645a41a945c GIT binary patch literal 15309 zcmeI3TWl0n7{><^jnop+VgMt$EMmAgJGZ^fu-&$FDXp?t+X}5WI+wHUgx#HWXG#}% zKxrUcLt=P9qrr*^m>87@6+{I=h#CwahD1R@(Fk552#T8EdSyZD|g*!T;mz?=3e|)TrJoN3X&kV-n3>CPm#^V}D0c zFT6OBqQu>LN2k>po-e6J%q44v0$izB0;(x0P?t)`>Jnf%6wsr`Yn{LE-RE@ZTCH=D zC(MQuji6U=UY-Q)%NKO0%a^F4=Bx`=1yT|;hyhD>q+-#yDWz(i8D9y;b~EF2WF*#- zT4#e@(9s!gbu=1D;PAM-w8{y7hfj2I9?{RcA8_z2=Ve%t;oLOKNvtTboFn&f2CHBc zNNN$OE!31N2Y=N%do3#=F-(7dzpGzx8Oa`o6Gf3>d4}g{sG!YdaZ66oadT?cB<~Xf zrkd0fmTtrywy&%heO9g0X%{Mda@Q40gu{hWaWh8`a%56+g5g{&6N@qBGEJ)u6bD&0 z)9hH508AS&jlQG`pnPh1qq$4r=yF#(0;9Q0LEI{91?TMgM&;^jY9S}lmyBjWYbpbx zAO`E0kO5Z~K%&>M471m$P_odSfmp7vrAI0Nw0kP1fs|e$&F;yjW!6-7ssj*8I4nJ! z)Zy}%qaj1>v#+Zq6oefvP1htK%U(|P`)Q2_UfLINbF`uWjrIu|r}$JwR(M~4sc2JN zRk>1SN(do=_cV$PY=d9mxVfTVmCVeSSsZIkzDCWj1e(qz|(Wfuz0^XiZ5Ymf0`~IcWlW@zy%? ztGBSja#St<;<3Yk_^)=Ni#;<E;8XlufEkuv91|=M$aZVR zxyl|sumN6mVP#387tWDS)98rm;b@Knepr=-(+30~M%9)xGOpXPX)7dzkq?%^fgJB#&8EL>q(tBk6$iD^WvemMymdf@g8W^Wp; z`7^}P*l6D*e2(dh^tfj9n=|sRL(?kTtG#l(2WUYipO|kbO$jje)J657GnZ{0I-&X1 zF?<2oJ6&o_0vRrh4#S9!cO7fJ&g6I@tCsDR)?X<%c53yTO95L_q?Y*}5P0rdM1`r_bD#ZT_X<KBgN5dR8Bk3;p* zvFA?z3(E^Hta|(W!t--3bZe`#xz@44+Xq_5hmN12M%T={xYIqbf5#hZC-#m$SU+mZ zN39>P`|jxb?8|4qnZ1{Ja_5OVk9F5R_#xMHcJ-83XCB$peqibLZTwrOsTDUr_T`Rq zHQPG>*l^FZ_s%gZXWcWUD|BjeyL5QU^!2OQUt6Y6o4KiJ`-JhY*MB~k9}fS%ClP?cWK{uFP+`^)bX=xf4lAb>h?g}0>@xTfzG*YWnNHLLf1Yf}IIFvB^S?|R4v&@y*H=#4qutNsV~BJ0!u literal 0 HcmV?d00001 diff --git a/res/s/rescan/9.png b/res/s/rescan/9.png new file mode 100644 index 0000000000000000000000000000000000000000..bd22fa1b32131cd241824416ecebb698f036e0d2 GIT binary patch literal 15391 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 literal 0 HcmV?d00001 diff --git a/res/w/wifi-high-pwd.png b/res/w/wifi-high-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..81a4d11eae658f9d1775a78a233b6daa81665433 GIT binary patch literal 682 zcmV;b0#*HqP)J*%sn%6A(NTd#D3WVU&pD#yBt1dfLS05{4p*sz<=Nw=)dhQy{1lpq;o(4 z$R|8pA9xasN+uXVya3Dtxs)mkc?Y<6B@#Huh4`<7cmQ;XftFd7XPQdo`Q0Y+fIW}S z1Q?|3kUEmFo8;JtH$xQ*=9R>`iINYLbJ=7qjx9J2(&&%a5_6Hgq}8}W?0%LDt4i`$ z5_cTID)9u^MaNHOQ;VH0XUWv5l zl(}v86j`3ln0?z?jdAzDElZ*U)GX_)%wUVqSErBK8;zbqmIU3jch}$xYjP-d}$10 zYJJMbn(hrqTyfkJE^7uUd%)S4y2ju3uQ-V%Nnk4T%Qi{irxIxT`n?M<0E3ACR401l Q=>Px#07*qoM6N<$f>UEHK>z>% literal 0 HcmV?d00001 diff --git a/res/w/wifi-high.png b/res/w/wifi-high.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec5305256852940cf8f0d26993a3194e30d0228 GIT binary patch literal 605 zcmV-j0;2tiP)%L&}fWrk_Xw0D|g2UHcawz z7j|dn&70Xh5{b2~?Vl|fcH_q7V;YYvumz-mO||76_ypd7@z+`DBQ^mhEdWIzAF;S0 z-~)qsWRi0d?*Q9CI;P5!d;q+F$Rv;el1t)UOX3Nu8dL6>%tm`Md=~hwiM+z+*-C&x z_AOG2j6NKPQOZWVELAM3B`KhXc;guXZmy`RCE%aGg%lL0Ue-?SR>Wu z3g<)=@XZ;J!5NxI2ER$QSFCgqljIkO*;XX-BLBQ&C<$ADtCmFS8=K7VsZzx{pQg#) zV^fWwd!VO+c&x+=Ie0?m9H^S);lKA|?=LYr#``H855guFlfB}D*9P05V+LQvsKRBi zYt{g~Tv1I{FFt7mkkpg?xe|BQC~-K^z=(K$9*EkN^V?81Y_n8n2Jn(nmEcyyT>` zz3<+0&pYoG$JvhU*zizU0}EG=9$iX=J%UTv)j}qO55kZz{k%Ay=O%!n6+%GpEt{JX zB1Re+l~VYSa6s^Ks?5a)geMabWhl;tj|_!pgb^^4GK=LYLMb1=bs{e`r*9;HBsGK7 zv5X^|wkcl;DhAps&eM&_D-m4NSaV>H0%v*jr`(*g3NJ}D?kM-v#e=$#e2&5cLoy$` zAXaGy^QMCIP^yInx-^#wgoyW0vmGlC;3X$|U}gqG?iOA za^7Yo(1!wZ93YX6^An8Mw>pYp%!$E}0Xp*yG7t2l7hAk&+Eun6qX4pc8Fs+ZiI?kZ zNX4tziuw+C7w3V#6IhAfs@$%{mn|MF<+EIxgcI-kFj_1Yr*t_Hq4!Fu_PR^ptTLpG zLvc1C7aSAH1b)_&B=Vf|AtUKM5x69T+Ov?K+b)4#_>3;s=!oyRyL0OL#t{Cd-T&GR zg*BTm$Hf!we_XEASi2vrwG9m_G@*in?ps3U23;B%(sWc#4>V!8mcI6X{;$|(*bpc< l8y;H%|3#paHSSA*0RRED|0o143K9SS002ovPDHLkV1jDj9b5na literal 0 HcmV?d00001 diff --git a/res/w/wifi-low.png b/res/w/wifi-low.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe8bdede28c3af2566a5bdce14a7430e9e1e827 GIT binary patch literal 589 zcmV-T0SvL1!-t<0!oemN1)3Q=r{r#feTQip-BN06iKl`a^oT?NZ|&Acq2VWtJTIIjEs=H z($hNG-I+IUXU2A%deq~OMnn7*#@gX;TYlJu0jR`H&D0c0=CtG?B+h$bHMbrX}72P)`$U!0->G* zk~k~lfKOs>i3*VHR|W}By3@dX(xAH=4IqF znmm;-H#=Ubw;`PO*-Xp~Ps+7rAttSQl4ZM@Q-C-tAuSzGIlnn1CxAiDeL*E(GjKE% zRPse+I6lX8103+LH{c4_a$nfi4~h3Q=MJBHl_@|KE->Bl=Ov=QtNe>rNRUW9>hXWa bw*UhG-8ai9>hoU@00000NkvXXu0mjf`;7Cz literal 0 HcmV?d00001 diff --git a/res/w/wifi-medium-pwd.png b/res/w/wifi-medium-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..221fdbc16c4783fd9744c2c3b06e2baf1804c56e GIT binary patch literal 663 zcmV;I0%-k-P)~!-*T1y?n~!QUun39I$GHjDUBb4~##~cBiQcu;@Ba2Hb?3 z8w0)|ii{IccnjDB@+no8;yvKmM#Qlcm%`hY!V_RXOtj3ZJq0S|^0!Ik1#7xi0!&i1 zNFB&HNV09@D^kU>@ksJK1mqnRTs2rrUJEFJ1&knUV*MQ9@VJQFS1Er zdq5Ztj0Ita)W*z25c^>~ZpaN3jyi^((YHWipF}5?Ub|eg9%Vc|av{w3DN}4i@|nQ5 z7|&(S+qeX}RA9;%h@ZsyA;#+_dKJ@{Bg2p-Tuy)^;J{eY25x``)(nmJLBV#al75V& z@D)&+6Dq|oQ1JTKzJ@3+g-?y?H$p~*&_k4{&C8vODZrEZ-Q*5C2FVH)I_A`u;bybh zAuf9=^xkot)}k#CgEivDvACG9#nwpsWUix0qL=uf~OV1kPagE~0iP)NFTkVF|+G{$q2Q_{RV`eC6i zeaXp#zW44u_uPBiXBhd&$3Krk+>I+&FD9lkum%)?in8Ss_y*pA$!;EnpKcQ>rY^J>U&QrjZ2TTpVv}98Ve5gmTYh4y32VxyIirks;0u zv;=5mUn8~1=;GiwN!YMgriyiCNdkC+y~&IKH@B3i#o@C~wuD4VRJ5+BA+|lAz+u3- zEWTpVofFkMWj2XbM&*-!*QtfG78MQ#dG8Ytc1`BF@5`eUcC(J z9b6dfLSmR0{Yj3F{v<|Rj0uBvaL}Qebm;&Ibf^PHe9wGMp2xNHsD_10zLd7_-uv#m z?_F`6{n(Ek4^=m?b^GMer9(I-xP(J3WI^~OObOZ7^~JI=0Tk^L0)lV3xQvi6s>rB{ z!e@k2g4a-GE}jyeO+=KTI2S%Q6wV1VAeSXyN>~$e;B)vfr59u^$WNu9NkaiCQb2JOZd^bS3O9+O%t~W)S{;7iKpLMk0_l9avvad+ zdtSG?_0OwU_rZ&ocOO3?a0&E*p?c&K_y#t>?&tabt2F^8je!J+8Wy(&QXnfM(<@1Q z3)}#HOO+*g2CP6NuOxuvlK9S%IA>Km%DtD_x}Jc)G5>2KYn)j+2{6c`Lu!#R#ldZp zvJo$&iiz5i0_KRf+Y{i!6IHb&T)1RwNF<=5iBdyiX9a;LE4gfbU^6{X)fHv-i2bWr_dF})QHH#B+-sTf)_}1)fUzblKom%A4~TKL>Of3lev1we z_Zvkb68WpzaD2c(nM-C$Jmi_sF%xF4dC)(=e4>I#fMr=Ha8F=JW@L3##F*2%1PrD3 zXh_pUcanLdx5m6e(`Xd)uxEFJHJW2qrQ0^+=*?B<1jU`Vc^Sp5rcNiU^u%lRHbn9f zhlzH0(XImrF&Wjn4XcIg?RgFloX>FG>ei{&uK)u87;efOb}a+t00000NkvXXu0mjf Dw#D`T literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-full-pwd.png b/res/w/wifi6+-full-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..b4498c0cfaaae58c22994ba848921969529a92d5 GIT binary patch literal 784 zcmV+r1MmEaP)gvj8NQ#2*5QHP9{L-ok8-Cx*QwT5(|g3~Q#r0vP0L z0P49wiG@X%Z6jVn1Wy87d5d_UT- zu7s3h`m1S?-=y#mT39p?*+Tz;_p<;7*E`#G8Ggu48>R0$T{;Ee9Yagn8b{%8cb_`&E0v~UbFSCoN|(os=8iADS6RG z3Fp4!^|}p_e9ANR3|G0vfx?1k?#C1RWwY4`TqD>%d%|)s7*wXw)Dkk#@n(p(&!c)_ zTo;I$-$MY-X+S<}xeKtMBqzp5e7XazEq4&}kTG*2CY(9s#&Wy!5o`)OgT+$0EatN} zO&1PH793okc$DS2KLT~iP?^G=!|{N}(MU*qUs0}^Nu&xX-SRTTfsy`*g|>NQ#m)lH;xl2uW4b^Dli6cY#HEv6$UYTE4;+wgBz*N)9DZi2^R$HY*n| z>Lf!+j$~^F$yvaG4-TJcDDhvtu(>p2hi`D=bG=uFiaFZoKE?{{T zn7AVF5$q7wZOO6(&tazkGOGoE;1c+o6IdPHlI|y(O?eX7XR?(z?+@|Lzy&}jKOL&a zLM2`-nxqYXDH+^%v~mD{(v$6@ZhWs|L~oV(fxo8@trGxdlOt99^>J-Br6eR zkLT4C-N55gqL+J%J$ioVr#CZwNcH9Y9~#)Qd1Mwi?KYei7Uo zwdjNe)qfU%=nMUIZTO=^K$jlPq&Ov0sWTIHy?Iau;CJApU?#U4rjtNj^l+HG^K)cCf=|S0|=fu?eiet z0)UuP6Fmezu3_tic4`42xMcm60Vl9IMfM4H2LO|b4^Ct!XVax6(9ClLQ@XDJ>^;j- zDM(z;*sl3&0c`Pij-YmUx&_2^pLxL2DM~&uPR-H(o0P()$QJF~ZZ#3p~5gGt53Rv!eC-E5HCucseaA1P3wz O0000P)J& zez{!Ih)X|sxG#6_&*%No7791#=KSXqf<&Zd%zuF3%G4WegMCL@4)2GaqZW& z1EA9~PytFSCN~0xK$;aykm2|qa2MFVCd=YH1->GXpGyOPb8&p%Hk1{|22e-T-Lip@(XraR|lHDrv*s9$BoIPm;g|>`mqYPDEe`uW+Exr?myA{n z8)7?k0W_3z`S=MRhaO`Q9!;PI6cq*(c@HGeO+30KGOUw)=K_%E#JFVp!O_ES;@~-O z0E9Uc9|IlW1h&Se%=_#YVPL3xK*nvPM+WaC+cRdl&JpJ?Ve`ZUQ4;#I#!wu-23qD* zA9(Ad89H^cc)+JVBKuUcv1|`q7$XTYNpd!x1oHx@>)@gP;EL=58y$5&g5u-6&gF=# z=-_(DGFY3-S240^(b%~ujr7G6W>+*UNqM@^8JNk5w4HVT7&X}!c_u;1)!x`&LpX1< zrnbZTyoa8^yfwFHOaGY7WN2SG4ai)LX%BFKc4lcmJ2iG4NR$QAPxg`)Vnh7HWlfMEC0EO&q!WYIGmH+?%07*qo IM6N<$f`P1qT>t<8 literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-high.png b/res/w/wifi6+-high.png new file mode 100644 index 0000000000000000000000000000000000000000..5144960f1d0bf59d9ceccdd915b9fee7d0beaefd GIT binary patch literal 787 zcmV+u1MK{XP)7YRAYziclDs<^E9bKG%kaTpIj*g^Dmy|9|mj=mnktlK$NFfcD++2Yr<06U#!n~2* zMw7|jhtG#-veMJ-d3R^tyqTSIrE)j!#(y3`-i`O(eObn16?gzF0r$<8pTKY62QdBf zy7_Bi0(80tG=Tb?!Ht0t5T}s|QXD@59skJKXL2nWaWgbjPERIy=}B!Dy6n_d&(<_#0IIE;L<%}Hd1 ziZ+ZIVmo#Owv=;O{EEeq$5;!GHqZoW3PW!B1PpL?;5l2T!aB&0j)1Te;}Y#>ClA-e z!7i{3ggFDB00+Q6Y)wp>H&`#Cz)07CT(_~lGWboRJz|tahB$u#aPWCv z=Q3okoWXR5X|Oi4TQQ>O(Acp_jnu^pMprW`NqYJ?Gc-4+rR@~`7`0g!d2WKFt6SRF z5YD^Isjcvc^Uy=gn{zvs^vi5E6S>xbDw|6b1i?f#n#6(x$&e&FX*o|+0M6T<>vIJh zgG9`lXu|PchFZ63CzAl2OVqFEu*a{S6xlQ290Ym^&RTR975!GY6u8LyaOUJb0kJiv zBefv$KIC=n7bURHXAGyhdGuKWcGOJKg+<%7OF@@a?K5&HHIR_&BfjqB&3PID*XvI> z-(qTF5I8KO;1Y)rAgb!Os{7sUE%R^rjc)-Wz4Fcf<#0uKE`=zK2#zDwlw2>k5xJXV zZ?`N0r@RSm7!S?WbREy-xufRgC?Izqj(e)`T;v0+ow_}YzM^`?!sD+10|0b5Iv1|B RYhwTa002ovPDHLkV1jV-Y6buR literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-low-pwd.png b/res/w/wifi6+-low-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..802a36688a99aab68bf22dc074831cfc2a37e8b3 GIT binary patch literal 806 zcmV+>1KIqEP)>7%N-if3^AY>za!rbC&!!j z!&F>);p5%r-Sg|a-#M>Qbhqx-e_nCfgZJKkO7N%y4}mS9VUBzSegHSX^ymJI?;9t; zpefJ-niY$i0As-AB@^caeg-@Rk_}mw;10M%BD2B-5L^O34+Qp(rlfmGv$~!dnQC%x z?XO^S5lnziUIwTZ8pkl4R4E(&>SVEHUP%ET;cvQ3fQP%LY6*B2qOD>gH8R>VY>02? z6X>hp^70%n$7`y3M7k3~I^vs3`XQsrJ;cN+HiM`fLw@XQrw_TJunkaL-Sy3P3B$W zL>ye?bpqcBGA6U5I;u&ZCuI}JNPR>>W>t7+G9Rd|U0z{UX%y2q(%qm&bIPi0+d7Wk zndzKHsH>`ej8axprV}ph#M|g=h~PUMCRX9TT^|GzlTm$AgWhQ2Y)bt!+T12e$9a+7&vO8j=<*yY%R3|pMCn2fKtdd z&}U%-U3nWg0QP|=lDQc3x7T?e9EvQsXy36c%kTCI{GnrHcFp|&2UA{0t|0OEjP2@F zplxoQF?S&iwEasM_SE}hYQV0I8l}qF^G5MFKb^a9DO&8GliwHk9B9Hm8#T6G*LdoH+;u{;Pjj%>B$m`+vDS z1D{2R(jo|ariPNA1uL}ry=US!5*V=)_GAv2)*SMA#OE8ek8b4(*!%C;2_0fiO^o~* kKO^*how`fLAN~?x0E>fcWS|%{RR91007*qoM6N<$g0@_5ng9R* literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-low.png b/res/w/wifi6+-low.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e4a96d829c2664ecee608fc339056c5ff5ca21 GIT binary patch literal 775 zcmV+i1Ni)jP)K@{E<138Q2V6WJN z3*;ra z1n4vbYCw=PxIWMW;xsaTisO0UD^Mz^vN(@{OAxusBmn2)_?yGAF*KmuuQFTLGe@NY z&h_~#oVjokppg}a)FNXK2m5)#hP?_^tf?gl;1BE#UI}n>Lq#nPyDr&s5}Bi-HKm5w zjtzk|%egF`VX>DG)o03GBBUbjEz&nGwQx3|!gi3q3;|)c3`n#mMjn-rUmW+EmUve{ zWLE%fH5h;>(6e(u%B`;sgd|ofPyv$tks=X@{8?qVl#oENOJ+)3<(Z13C!DzY!E6Ha zhB6`sF48K2Yl4Vm7OaX2X!B@X0uiP6n2=E(-AU#*b8CrL80BikJnY%kV72CuQR%Xc z*?R9(Z2^%BRMb}4&~k#fiiF{ zwd(u+E&D@iLOMELluH3PU$+v^j0d0v5;1e40>@_=YQ4#wOagE&QE$*;o5{2a`~c2D zpq=1sna;YCek;rsn8-VDcFp+#h=sfk?O4>>1?v1QXSP73Gbw>ZK4Umtwbnb#0X;q% z=Nxsuo9sU!obKRpn_y&5a=@WN6OVoV+(h)Pq6B2fT^?}0#;b`zU@svDn#_TgS7ZnQ zqHMh@oA-L}H2;>*jL6~p53c#Y93~0RB@v|&!Ex7WN~RZ#L~iETyE82U$E<{P7_Y0+ zJmk~dbJLnnM**pQIBr{sXCgnu+OgTg=sl}f6do@E3;;FyIs7`Zg8%>k002ovPDHLk FV1gB9VtN1o literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-medium-pwd.png b/res/w/wifi6+-medium-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..68f47cf3c12bc7a15c911e05fed6474731f88c27 GIT binary patch literal 833 zcmV-H1HSx;P)#j3)c4Bv(S6asIH9~A8aD}lDJd1Zinpa#PrqF<5{06=~ zCgbM4JQK0Gg^z4@cV@o%c4m_xxEfdEKabqH2d_Q*kjF;>xDM<9MRVjU@DsQIX1|UO zer!yDK`THNC}&J=0*rw;iA*jb@NM80kl#>c2_6HVLF8L10R)%8cRYceqZ#GClv!QR z9+fI{Ztc%ubLJ&LC-*&4i;QC!PO_v8e+8;oHCvLvd-$7O65!#c$yx%Ae6nREvPVU$ zMh)>DI|6MLTsA*qbG#y}8Lbk15ETo_kFy zymKJZ9Y9}ACLjuobqz?nO^iW>#PS<-fK-2ENR&nXv^LydQ9!XzW=dS7O~Lafoci8_ zofXWR#)&vMOX>vf2_llYt2(MopKsSC5K;Po1sP@0on+pzw)T02QKqMu#)0kztd;Q5 z0UiP^prlL&z-yonn=htwioUMO`eP)4p98fujz2}f-qwB%5nP--G0RhFCC+OeV$x>! z(tIz~z+$nGd#?k#fXFz?<#JQbwbYW~z>utwWS2`X;BS{#^*|jR!e{u00yx}Jh3Cc` zIDtWo0OI%nfe%yE>auoD;ImDiAr+IFX*01mXM+w0if>rypZ&;OO z-Clt^)CV&scZh=(UPod<;=9-!BI~{iTVN;Ew$fg4cJjKMOQN|8HgQx z$!BcVCB||WP?D*2!f|Y!sJnj2uaD)f3eMjBy6=m9 zibDjO(@97I73&;ldcMGa^@qjW&)hfvm%}OWNeWR~1c68DQF3p=lB{m-l-LG=Av>WX z?|^Ad_u@IZyJ{Y6`Ke20*mnF2sA#48SB6KG7k?`&4b zvqYx?&h7n|*mL0&z#uOjR*Q{8Y#ilD8}TZ1v0=TE1im2N_)Y*9H?6FNaNx2nr;sH& z+OXV^*s&3?t;pr&H@qAsWc8GGmk8;IUrO|q%Ps5;=&(-m$OsU18-QecX6&&F@|ojY z(+ckrh;#=qR+9;c14CT{(rzPbL!H7(b98`Ie`JXW#Qs@rxRy{rvCC#!T;-mM<4!np z-3N;a%9~aY32>3t34AArDCULgsDLq#vkHi4y~l!#^7u|MC#Z-gyMne1%2s13-1!1SKUqg^fu=m#EYiT9ULx(VF zv&~ttr)pp_naH`X0%bsK9QeL}&AGN(GVEI-LyBzk(WhJvfV`y&&x~8(03u=#NZ@r4 z@62$k&DuH0ECA$^^&1j)+3QkduYhw1=q8YDkZf?@-wJaCCi5Q1jNOM2R_Ae~79_sQ zo*fA3-B-XWKVy(?srNnBfIVtf(S=q^=KD_w(hjTI6=Y9pAmOa{`SoqqGfxxXv8@g{ z-{#T85U^K7!6gn6K$O+9vUzT=E%I;q!jv7pf9sn6&tZ!2TnbSxA`lPMrDX1csm#qB zYdb{=IAtfa5InS6)7*IGoZD(%j04j9AnvNdGnx1C?$oSd_MW;c<{tk97yv{tIhn|# R;wAt9002ovPDHLkV1kQUXV3ru literal 0 HcmV?d00001 diff --git a/res/w/wifi6+-meidum-pwd.png b/res/w/wifi6+-meidum-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..5d64fddc0a9bf8c375aa09f7e3aca02008a02631 GIT binary patch literal 828 zcmV-C1H=4@P)>h>OGj}? zSTYpEQVQH4Ay+P4rc7ym0$s|KbhPPkN$K($B&R`^QecWmB*i6?n=4`|xCoX&m^ac} zvmW-oa1c#adb-Ws&di&)Gvj#P-MU-T-h1=8f=3m22y6j0b>u7X1Goa_KM$UN z-Rl(=N3#5LMf9W&v?H4nB@ zn0J&Dad4K^3H&CANoL3DsDM6?ixP+_y~l!#%jixrA6Z+wyu!HDD5kMzcY`&WLuRGh zHsR>KQJqtBbye9PqmbDY>4bAV@izK3MDQIB6J6n^T^~4z$*4Zg^SxFB%jHt;y#?F{ zE~Qs}-@oR3$Sg?5#Eaoi{B(hr*3mJ1Mt>-P!+TcYnY920Fi2PvRRliGQEOE@@Y$nJ z2`GuwfgTf!?95xhA#eaRg}E5>-F`-}wjk|0?b}*qd9Sa)92$bzCHD~yhP)0PSk!t8 zH2JsKyhheTD^Q)=M42b98fcl1Fzj02hpYj;>Lxf>lka|4H|*d`o{4%dG1j|)l3Z&i zTu0gov+m>Zj(@&F_5&;XE{iX3jcfw4CM+0_#UfXefWT2o4fI)X1AX^J=ZhZ25rQq~ zBqD)OJI9$rSKz<;heh4b!nOaG%P81+fankPzifcxy(J zy*r&xA&nOvyVmZ`ym>n_=P0@#_v1g0c+rC^AHF7-I=~}f73i8H*T7HU3Yh$Q|MEv; z0(6=IJs_~*MO&umEmUtn)?OMr*_CTejw49QlLNSliGj2dFw zc>-I?xon8p@hxSLX89pooZK-j$kB-&#yk4eZUfp;xSybB=L z6+l~k1|SNIbPhX5YE@wOl*exa(xgWCawCg%Jy6i%w{ur_jRBJTuQCR zar}+_p)?@_9WSq?0Gw~D#Pj0@*aHd2oan&uNrhT}!T;UJ`L`(hF^1s`&%lx-|WloMb zz6q`W&MRoZqSSaukr-hvR`t pJRkW1_Ky4+MjxqO(Rln8U;riGIl4*B7svnr002ovPDHLkV1fu|R2KjM literal 0 HcmV?d00001 diff --git a/res/w/wifi6-full-pwd.png b/res/w/wifi6-full-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..cd21cd7efe714a1cc2b193a69357cce939a7e4ee GIT binary patch literal 761 zcmV|<{sOySP=%RAWnpz#p`ln+CRF!r=bdM}S;^99(vsZFj->P5 z?z^{dSMp%+I3CA;9#PwcPd?raaY?!Z{Si^q8a=HKYepL1bz@QV@83T720^~C+ zYXTEB1bzp53mf)iS%PPZMSLjd_=2!(T!M&mFB?z~6cYfQxU;sdFye^x+@AV={Vf*bv`Y0PsTvmme?j`lqAKIF3iK+rAd=rqt{1bODHvH*PI8_kZz;T#!qXKcW&8Zz z+8Q5obuWT^*`*9+t?ZFJGY!_~{#Hz34s0}_&a2(PSny{ z_*~s%0E;J1`Bd^Qz=ndF7$NZG9=3McfzL60uE>~ZX3T@F^vPq`6!r!-6yySkbFZ6T zI24&XxIZy-iOky+1d3LqTtqtYnq44_LD{1#vU4Tok(Qc^B}00000NkvXXu0mjf>k?oO literal 0 HcmV?d00001 diff --git a/res/w/wifi6-full.png b/res/w/wifi6-full.png new file mode 100644 index 0000000000000000000000000000000000000000..becdaa0797c59e43eec5f54a635c57011800ded5 GIT binary patch literal 711 zcmV;&0yzDNP)vacvf+h0&eB91z17Oe|Y>$DfECF%>i;KVn z1%VG?zhSMKEKBehb_yVADF6hQz$Zpv=jfhvztOD96T-I0R%o0b;!NKJKqr3;s>ebl z4klI7hQEjm?i*S;fWNyp0Ni}-Wu0(iT8Dr54$0`g$A|K$K+uioXxGu>33AV&F?J8|3d*zJOnPu>OmXBfzv!S~|jpiL@=eO;Iqc`SffUF6QZkQ-9*s zx(yM$&zkxQckLP)z|5NatEpdRv)MX6#D2gY#YqqZnHn^?f;1-Huo43Z-ZR=~Dt7@u zJW>;F1U@QZ>w|Vm0U&rtl9UnppyA2ojMKptL2F8VQ>>aj77hYPv}$bQyT6 thSKeq{Aa{5+*LIf5DCh%Q~)mm3;>X8BRWD~*oy!F002ovPDHLkV1jh3LfilV literal 0 HcmV?d00001 diff --git a/res/w/wifi6-high-pwd.png b/res/w/wifi6-high-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..cf650101a6b91e57d1ca4afbc1a6b95898c28c29 GIT binary patch literal 812 zcmV+{1JnG8P)>%B84npY^x7&=HTieaiZf?fS&Ezj=|Ae?@5zejP&~p&frGYFr7&tSOfMR@Jc`m%Z z{atd`T3!0W!+rhUujlcbi?o4_5Q3fwkFz5zdgufX)@^Vat( z2SBF{pb6AVCN}}bK(Z_tZ;9hA;4ZLsMV7^R0(?Or=PLt%b8&pn;W#riCEW{}Re3hZ zRGs%${|q{xodM9u0|(VY;~0vQGHJu!CRuEnPm;hX>`fN|@bIq5S{%kM+DZnpK}MT~ z4Y8eM0ffrAeEf)yV~4Q-mk!VZY6>GBc?U$$jU2jlGOUw)n*|`ziE+vHeMS$ziGydr z9^e;DJO%nd54KWM=3VxSFfi6VAmcXCBZGI6?GdxQjEM7>u-P*~)P??KV<-+^1N-Jv z47_pC44pPv+~ZY?oPDg>ShWXEjgg3%LgWk<4lgi( z!yU)?%z$GkBh~UlR1U@ zfq56mds~8xq9G|48Q@@Aq#^M<;{UvQ zVdk7vNe}qTehKroTd6--OnqjKF}zmE0{BGgb`*^bHsiGhQB~VbCLyHbnOaIG|KvX- quHjJCeD=FbJ+E{CWv1Yl00RIuM`ki(+=(Or0000M3JLF3N)PL#zib0E|4Xnm^bKc zG)&faXFG-_D?Q!Ww>$66o7p{kW#wkvjQ>1>vJ-E;{=ACII&c@L0C&ukAHX?q28=FV zG=42CfTSBh9jMKi+z{vkgFG=o4)Hx;6Ifl)Wg#B`-yq~?p#YEz@qG`m3pAqLmo}^N ztkJ0&@9p~USo75@fI%L5tQH&lSU8*|ZNyuri*@rz5;#G;(WL-R-ZohaVdArGMj>l- zv~Jvx*aIgZQsnaR3m*18!J4?VfCf-iNIB&L5MyoZSzDvSI?4A=fT)w;lI{ssQY~^d|Z}X zhRl^UxZPtJY|P@L7+JI#?8uZx`r-+*s~VT2JUy&Q&CY4+IP<=YTI`E5J3-3Txwf|< z$UCg5?eK*6p+}gv=5|!{hsk8Jg^S=e&;29_f=nGWQyUT@LyBzY)qJW0Aa8lL&los@ zhyi<|0pk4vx32U~p#YGFR4!Q`lQ^QFQwTVoLe?Z%vd}Lg2zW;8CEHZF@@F68ySShs zQ*PJZtO8sQY_X{_kVgC!l&T)EqiUKiocFkP4sdXE&bs&5oYkBocWz?uyTFl~ZMf9o1e~%IkJJv>U^6aNL`9u$vJ)Z_ vkJX{{@t^!N;xQblnu~}SWm&3#-vSH(xGN(hlHf}{00000NkvXXu0mjf(HvSb literal 0 HcmV?d00001 diff --git a/res/w/wifi6-low-pwd.png b/res/w/wifi6-low-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..b58198bf51570e1ec5869ccec496a750b2b7d933 GIT binary patch literal 804 zcmV+<1Ka$GP)byTBUIFt2-i1tvgJL?$dq{1A8m)K*kkk|)3^h+LEsKypd^$dlLwno;hB%<6d7 zsZ@)f?fx_DIq?!;kS89gMaBs>POFrScy+4SF^{BxPlz{L5a7#wQ?(=<`DCj|WSxq3 zj2aRmolm0>Z8bNVP{!9%IP+o^vfS z-Wd?<4q&W43lIe++5^&VQ?sE>Vzm`IK-?c25-pLxtPQtv43zj}ro;{Ise5L^k#8QX zZlfD9xO{Brt|>~8CTJrWIobcTRg(J(kSNUKzD;0&23g? z+cx3oy)d2A@O4$yAEP#_S*8;T*9)kDM_{-FR~eyWV;Rt5~PA)zPgNPJwP*1|i888N0L zltP+7#KMNU@-FZicmXtpxe(&LX9dZ6g1qP4-!u1ma^D_-lW0iEW$od`G$*mB^%m&z z`xuv(sCrK&YVu=ZwkJLhY*M0>vWerz$^&*aU2?82@BMZ+_92#B6LUY2`&T?bNm3hx zOFS_4sIZI6dwzY6>IbU&9h$Ff?P~(EMm&a0nKH%qcR5F~OT!K9*)Ka^>?poWPN~EL z-5gZ{U*f;|gTyPO1G_KbTj{2Nw_1}XD38VoT;I7_)q>b;uwz9nP-HQt@JxpLl>>q6y`m%dC!P zok~S~ZTFvJ LHlRWoGEiw+Uaa5*kmt860>W+^A=Mr^d5j?+dd@Y^ zc;|>jcK~yBSb!)n&>oO>8<`C)6023{0C9g}NJJukQ5$Y$7%270OoQE@O4$$FQXQ#S*8=t?8K||Z3ys94ioEe*RJ(;OG+sK@Ev75x2A|LNTl>c9l*y0YW?G#LIMEaz-5808WrOL~zhr+ODfJLnjhz))ud)|P^epv#}0|G8*JqBpZHoH(B zu&b%S1HNunQQ#d3_>wHBqEwJ0`^2}eQGK^60av9Cp?N5ssr52UnvQ91U+^_OyH>+N?-rWKO>Ie lSe?0$=;2saO5m>m0|0sLBMH_!jr9Nk002ovPDHLkV1hL(Pt*Va literal 0 HcmV?d00001 diff --git a/res/w/wifi6-medium-pwd.png b/res/w/wifi6-medium-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..b713c4ec78dd96f9cd805f0bc8c577d1ebcaffca GIT binary patch literal 814 zcmV+}1JV46P)d-JCRhc?^qa$P4Si7-NHa6fF(4P>tEJ$HNl{ydxB-+7^l*L0MnG6sKMEI`y zTwRZ6J0=vCKIxN_=XZDCeRucLdfwH#TK{?Ziypl8{9_f58gLz`0CjWZ3-ALt1*Sir zY9;5&}MsiP_7K9^aQ zXO&7d`Ptf^z~;zFfKKi^q!t;+Fr1W08~$okv29*S0w3USdQO0cyC!Q1ICRNYlE^9* zZ5uVjcbpOkRd9Lv2`|SPS>2%ARYE4>n<9PcQVX_CDy)-yn-UOq9YC@@Oyw~RdDBtX zyv92LB0T~0)nx*rz*zTyjN8N*v`DPF!~{t9M}|aGJK@lE zA5=1!ca0NqaFjO*d?$!V=B}EkCVjqJlt4u3JvL-iMt72V&)!;R38PY1F^xSv4cKeo zu?;)`wt$8*831p99&AQta_X+BD*Iz3fnNZ@0>_^r;ND;RHAHZ6_S9@AGD`d$IEcxZ z-7E5ap$F#k`5GRA6?Xg3_k9U8GEz&114A+($sKOJg1;4(YEvCOfY1JK3gGazYP@vK zfPEOm2q2C(5O}vhtsVBxK75As*{5RCGa(b}>&ydS4|ohTgt-vn-ou<=9YNN6+IP%e zNA_(AQi=MMTviVUlSLX5-=##m$hxNjr4tex^Vrn`Ym_LVY%SJ(s0iuRFijVjk@Un4 zzT_F3{aE%d^Z+GEtP?Kjfl)@SU-RoDskzF2i_KTG2AY7!v63>(R8uDS{<5gyZ0#4l zU+h(U7MxN^4+I&ic&@;I^aqQn&&)A~m%35{pDEp@lCi~Ryi^hub-T$VgbX}Wm(syM s`Ok>gaHwiNJL^*4FHNA#6#Nok00lo~wAjg=VE_OC07*qoM6N<$f)=@FIRF3v literal 0 HcmV?d00001 diff --git a/res/w/wifi6-medium.png b/res/w/wifi6-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..135b18173472849287790d6c0958f6cfde460620 GIT binary patch literal 765 zcmV4N3`vJV@sv?pGiFRaAzQa5Ter4f(2N`A{D6?FTmc{#;wKj3G|-TCPi!`} zXNgV){H)iXW6haW0E0ZYSS>d8u(0ovHsV$2VnaQW1im8Pa3X+{n<{G|?AUB`6tYA| z8_ErdoumRHgIped$HU%?tRB$rG9exD(-3`Oa|>$&I&3C+oC*+i>wsi?lG>vR@}Xs4 zvkLDVh|LaQtR@o>2YO}=NW1mbf;xqj=jZ^b{#c0!#QwZCT%A!siOptOT;-aIP1USp;1U?hQ6!X;RsDLp)6%`QEdXEJeyZBBqpIKY0+``!DDCT0%>;~Mc z;j#(51U7)0v7`+g0WGZQs?Mp}y2|xsB*brlu)y?v5boXD+Ysau?6tZ*kXGX7&>~FQ z>{(vysTvrM$1Au9?z7rEzV8cBS6M9?ww1_`BDZ<#y^{kV-!uv@9V6fXA`%ct;588M z=D4-Z+BqmJ0OTQ+OV)=Zjwt990uE=8t&^-X*DoRn*rN54ZP##ReWh9>bBb=OUtwZCR**YXJrTh$AAV;{(Ll00000NkvXXu0mjfxno-P literal 0 HcmV?d00001 diff --git a/res/w/wifi6-none-pwd.png b/res/w/wifi6-none-pwd.png new file mode 100644 index 0000000000000000000000000000000000000000..aee1b42a3370dd65a4001c4d69e203a3854491c8 GIT binary patch literal 783 zcmV+q1MvKbP)Db)n*CKy~qDGafTvq8-k7APu|gP169%v&*@ z?49l+oHSl|NV>b7dGq$ooE=5?>wf*`6<2-m!Mm>sKAON|U;}8GN4^8sz!fn2_2%Wz zwFxk32j~K6&Eh7&7;t4|;*!MAfoDLnrpl7s0p}nxUr7MTCGm?uVjpNmxtB7l<7rT- zl;7?C3+y=y5@3*50jWjCF*Z)>l#O^zs@OHRq<}AoH(L_m!+le=Bpiigt4X9mMY~1~ ziS0arfl4knPjPcxP}LL4oeCr?1w^#G~%#LHt0`805@WyZSz zGTi};)n@^sz*u`g+HGPsbVw{&qXWeKnIVyi{Hxkew|01hS*=mb&5`Z~HJUrD%C@cJ z=$)I+X@$C~?#rmdYN~X?xt(}xy$z9ki^Ie^+_&qa05KWWN2_Ar^1x!T*v5z8A>|y! zaXjUGC^ckY;$?^@arS^+_2@BT4*yU95AQ4E`IQ47u))z2O(Z^Dq1Mtnh&fdH5Px4;3=7Un{T*It*saA>mN;{Kkw)|2b@2)sl?N-pao9-LM&B!17?u1+Ot z^Q$x4UC0C5lxRxXB*CTffL)0(UBixR*@sy2>CAN}*Kc`%lK3;SOFVE{aMoVlk?wQE z+oSnbtwT-VCJ>JySEiie_xq~D%EXImwV_W=sl)@D1*$}$#DDb%i#eY>(1v%qJb`bN zZdb|ZXa1d%@JDdSP8cw8t_*hkPyRFF7#^rI&u?5B$F&L6>4M(^3;;UbWz^y7eE|Rf N002ovPDHLkV1lr&Z}0#B literal 0 HcmV?d00001 diff --git a/res/w/wifi6-none.png b/res/w/wifi6-none.png new file mode 100644 index 0000000000000000000000000000000000000000..c4563c20c0e08463cc320fd1a9af49dd4f81c7ff GIT binary patch literal 738 zcmV<80v-K{P)E1?p4ovCQgvDpV@w z&-VNk&Rlp2Fvxq4)FNXC2fJm;M!YIjY?xP4zz@Xhj|p&d(^M@9+dkP!5~)zphEYRe zXO2LklFQ38yzES=>J{aV26DWwl+$h3^^B=e2l+U6CerA9Fi2f7>7Xs)v=+qM}; z@4$3U&DT|BKSp&{GfO92+KIQ&*AU6KI83a=UAw;U5R*}TQWSf_1EbOC4IYB$l(QX% zVUP16*N~oxmzGih$v-LMxith1Kq8|jsz`iRpw=Vr6cRx4bv$-i^&t}{ByK=T&@A9pGmEQc1WgXt5I#CLSt-eg7x_8F36J>du8k3)iw#0`~$800HnL U3Z}|1hyVZp07*qoM6N<$f;R$2kpKVy literal 0 HcmV?d00001 diff --git a/res/x/control.svg b/res/x/control.svg new file mode 100644 index 00000000..a64182b7 --- /dev/null +++ b/res/x/control.svg @@ -0,0 +1,15 @@ + + + + +画板 1 + + + diff --git a/res/x/fly-mode-off.svg b/res/x/fly-mode-off.svg new file mode 100644 index 00000000..408b7b07 --- /dev/null +++ b/res/x/fly-mode-off.svg @@ -0,0 +1,19 @@ + + + + +画板 1 + + + + + diff --git a/res/x/fly-mode-on.svg b/res/x/fly-mode-on.svg new file mode 100644 index 00000000..9f5e543b --- /dev/null +++ b/res/x/fly-mode-on.svg @@ -0,0 +1,14 @@ + + + + +画板 1 + + diff --git a/res/x/hot-spot-off.svg b/res/x/hot-spot-off.svg new file mode 100644 index 00000000..cf39cadb --- /dev/null +++ b/res/x/hot-spot-off.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/res/x/hot-spot-on.svg b/res/x/hot-spot-on.svg new file mode 100644 index 00000000..2041db9d --- /dev/null +++ b/res/x/hot-spot-on.svg @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/res/x/load-down.png b/res/x/load-down.png new file mode 100644 index 0000000000000000000000000000000000000000..a96298ace4380a4cc8ab5eea0ce6c086df416f6f GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xl001;Ln>}1B}il(=}1B}iO(5bkuNM&Q`;HqQQMEDEg00?fh=bU1Hj zoM6?jmUCiT!d2ELHU?8}hLyh^bQ;vYGIoeIw$&&+Y5f~vV(f7AoA6WC72f}pKR22g pPZH@k(iF(NBH_RR<^~34hB`MXgMW5E4+8CD@O1TaS?83{1OUkBLnHtI literal 0 HcmV?d00001 diff --git a/res/x/net-list-bg.svg b/res/x/net-list-bg.svg new file mode 100644 index 00000000..c17c1fd8 --- /dev/null +++ b/res/x/net-list-bg.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/res/x/setup.png b/res/x/setup.png new file mode 100644 index 0000000000000000000000000000000000000000..fe242f89ca8be8b54c604ea34999ae85660e2072 GIT binary patch literal 2152 zcmV-u2$%PXP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|cvg;@e{AU%j1SAj=%fVo(W(TwUY1xiX9_NwV zldq{Uu|)(HqFW#w)_?w<;V)bqOAJ}mN-ZVg$~9MRs94;ux;-i8?YaL+M;qPh!`Z-4 zdHwjW?dad2myZ`NW6*M|4|cS$9fs&Myj{sh_WHPX5_;bCln+C7-7BSDDg%f4EU7P#S`P67!lc>+NZ~2Wh_>ZpD)mp&zA!IwcJdDP4>KkelgUWQ^AU z-GF?lg?seR+8y}Z4t=`AvK$zp@@WIfo&JM%z8*N89`S7hASw^jIqo@!&AINgYqjJdZI&#X zSTQxTYOQij*aM}Os?}<(t#N1=sKHi4{|3#%OIq?GOIdWWr7o=_e0uKEOV@6__BME= zfo)=xp~FTUZKbecr&#kUYgu)*wXSU<)@GV{$}Cf-%{tr3+QI5Wd4V-LSmTW;@24kg z&<53u3G(ekoHH=SnZUR@0|;n#&Z1Gy?94f5u`(8gFq{kWw zeG=9zQ=gP)^9<vJ0<^Ead`^Z}UwD*pFmh_} zs%#F$_!}8se8I{NSGjjD{Aym*WPnaeeIP*sU!{sr%o9<8;H_<$+I0YO?&Bvf+4so| zu-^gDjiFwwBN%_U^}pEX>4Tx0C=2zkv&MmKpe$iQ>8^J z3RVzt$WWauh>AFB6^c+H)C#RSm|XfHG-*guTpR`0f`cE6RRN)x5=kfJi*U4AUlFC!X504bJ<-QC5;w;&b9rlP*a7$aTfzH_kLk-WaV#C4iONMZqt zkRU=q6&onSMx0ii6botEPx$x;UB5&wg#t9I72Cnp$zfuRLKS{5(wAc~QvkhEaw=`uBxZD8-o($QPT`5RY zC=`JAGy0|+(02=Tt$MvR_i_3FWT>mu4RCM>j1(z*&F9_W_TK(I)9mjDTyk=r;*cus z00006VoOIv0RI600RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru)K_YUTC1K=ht&~vv`nJeV3`aj z)oVeoQtzp+)thQv$XnF$Y_JNIBuPk}7r?Ke$AN=D8*mQz8S*jUPui(eSzc{dKdJ-j zWA#*--$!L?Y6^9+v!_ozt+uK8M6Cp_1DAkLzy{zgFaR_GM}Y;vH=q}I4padgRL+w`AM)hAqp6&IpT0lLl4#hZ>l#LOnIg_AP{i1Hl$cNM()N1vH zI;buQWv|*3bdqswSFZ$J9ky51#*)Fp0N_CIcVlSFfv{G+9rPjfsoJ2D3uN~KPk{d5 z9|2o}PBP!E0S3VR0AXKgK6V5E%Tw9w)yXnFYmQzvrDV(0hiVsUYfN|+p>^tS^?ca$ zM4%3piHV7Hk`c9#sPlkZz%cLOP2QuEBr%w!FBsmD_MQgu&^L8%Sfvny9D7RlvuIWngPs0_Le zI3CM>5ttv3!U~`^?UW=5b0PunfY#{YAn+d8415m$L5x!W9M5#A@yoe*Nej`7v`uFq eTdC%d{ literal 0 HcmV?d00001 diff --git a/res/x/wifi-list-bg.svg b/res/x/wifi-list-bg.svg new file mode 100644 index 00000000..43f18664 --- /dev/null +++ b/res/x/wifi-list-bg.svg @@ -0,0 +1,15 @@ + + + + +画板 1 + + + + + + + diff --git a/src/backend/backend.pri b/src/backend/backend.pri new file mode 100644 index 00000000..feb4853f --- /dev/null +++ b/src/backend/backend.pri @@ -0,0 +1,22 @@ +INCLUDEPATH += $$PWD +include(hotspot/hotspot.pri) +include(dbus-interface/dbus-interface.pri) + +HEADERS += \ + $$PWD/dbusadaptor.h \ + $$PWD/kylinarping.h \ + $$PWD/kylinipv4arping.h \ + $$PWD/kylinipv6arping.h \ + $$PWD/sysdbusregister.h \ + $$PWD/utils.h \ + $$PWD/wifi-auth-thread.h + +SOURCES += \ + $$PWD/dbusadaptor.cpp \ + $$PWD/kylinipv4arping.cpp \ + $$PWD/kylinipv6arping.cpp \ + $$PWD/sysdbusregister.cpp \ + $$PWD/utils.cpp \ + $$PWD/wifi-auth-thread.cpp + +DISTFILES += diff --git a/src/backend/dbus-interface/dbus-interface.pri b/src/backend/dbus-interface/dbus-interface.pri new file mode 100644 index 00000000..056901df --- /dev/null +++ b/src/backend/dbus-interface/dbus-interface.pri @@ -0,0 +1,46 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/gsystem-local-alloc.h \ + $$PWD/kyenterpricesettinginfo.h \ + $$PWD/kylinactiveconnectresource.h \ + $$PWD/kylinagent.h \ + $$PWD/kylinagentinterface.h \ + $$PWD/kylinapconnectitem.h \ + $$PWD/kylinbluetoothconnectitem.h \ + $$PWD/kylinconnectitem.h \ + $$PWD/kylinconnectoperation.h \ + $$PWD/kylinconnectresource.h \ + $$PWD/kylinconnectsetting.h \ + $$PWD/kylinnetworkdeviceresource.h \ + $$PWD/kylinnetworkresourcemanager.h \ + $$PWD/kylinutil.h \ + $$PWD/kylinvpnconnectitem.h \ + $$PWD/kylinvpnrequest.h \ + $$PWD/kylinwiredconnectoperation.h \ + $$PWD/kywirelessconnectoperation.h \ + $$PWD/kywirelessnetitem.h \ + $$PWD/kywirelessnetresource.h \ + $$PWD/nm-macros-internal.h + +SOURCES += \ + $$PWD/kyenterpricesettinginfo.cpp \ + $$PWD/kylinactiveconnectresource.cpp \ + $$PWD/kylinagent.c \ + $$PWD/kylinagentinterface.c \ + $$PWD/kylinapconnectitem.cpp \ + $$PWD/kylinbluetoothconnectitem.cpp \ + $$PWD/kylinconnectitem.cpp \ + $$PWD/kylinconnectoperation.cpp \ + $$PWD/kylinconnectresource.cpp \ + $$PWD/kylinconnectsetting.cpp \ + $$PWD/kylinnetworkdeviceresource.cpp \ + $$PWD/kylinnetworkresourcemanager.cpp \ + $$PWD/kylinutil.cpp \ + $$PWD/kylinvpnconnectitem.cpp \ + $$PWD/kylinvpnrequest.c \ + $$PWD/kylinwiredconnectoperation.cpp \ + $$PWD/kywirelessconnectoperation.cpp \ + $$PWD/kywirelessnetitem.cpp \ + $$PWD/kywirelessnetresource.cpp + diff --git a/src/backend/dbus-interface/gsystem-local-alloc.h b/src/backend/dbus-interface/gsystem-local-alloc.h new file mode 100644 index 00000000..54ea4818 --- /dev/null +++ b/src/backend/dbus-interface/gsystem-local-alloc.h @@ -0,0 +1,207 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef __GSYSTEM_LOCAL_ALLOC_H__ +#define __GSYSTEM_LOCAL_ALLOC_H__ + +#include + +G_BEGIN_DECLS + +#define GS_DEFINE_CLEANUP_FUNCTION(Type, name, func) \ + static inline void name (void *v) \ + { \ + func (*(Type*)v); \ + } + +#define GS_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline void name (void *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } + +/* These functions shouldn't be invoked directly; + * they are stubs that: + * 1) Take a pointer to the location (typically itself a pointer). + * 2) Provide %NULL-safety where it doesn't exist already (e.g. g_object_unref) + */ + +/** + * gs_free: + * + * Call g_free() on a variable location when it goes out of scope. + */ +#define gs_free __attribute__ ((cleanup(gs_local_free))) +GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) + +/** + * gs_unref_object: + * + * Call g_object_unref() on a variable location when it goes out of + * scope. Note that unlike g_object_unref(), the variable may be + * %NULL. + */ +#define gs_unref_object __attribute__ ((cleanup(gs_local_obj_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref) + +/** + * gs_unref_variant: + * + * Call g_variant_unref() on a variable location when it goes out of + * scope. Note that unlike g_variant_unref(), the variable may be + * %NULL. + */ +#define gs_unref_variant __attribute__ ((cleanup(gs_local_variant_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariant*, gs_local_variant_unref, g_variant_unref) + +/** + * gs_free_variant_iter: + * + * Call g_variant_iter_free() on a variable location when it goes out of + * scope. + */ +#define gs_free_variant_iter __attribute__ ((cleanup(gs_local_variant_iter_free))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant_iter_free) + +/** + * gs_free_variant_builder: + * + * Call g_variant_builder_unref() on a variable location when it goes out of + * scope. + */ +#define gs_unref_variant_builder __attribute__ ((cleanup(gs_local_variant_builder_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref) + +/** + * gs_unref_array: + * + * Call g_array_unref() on a variable location when it goes out of + * scope. Note that unlike g_array_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_array __attribute__ ((cleanup(gs_local_array_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref) + +/** + * gs_unref_ptrarray: + * + * Call g_ptr_array_unref() on a variable location when it goes out of + * scope. Note that unlike g_ptr_array_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_ptrarray __attribute__ ((cleanup(gs_local_ptrarray_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref) + +/** + * gs_unref_hashtable: + * + * Call g_hash_table_unref() on a variable location when it goes out + * of scope. Note that unlike g_hash_table_unref(), the variable may + * be %NULL. + */ +#define gs_unref_hashtable __attribute__ ((cleanup(gs_local_hashtable_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref) + +/** + * gs_free_list: + * + * Call g_list_free() on a variable location when it goes out + * of scope. + */ +#define gs_free_list __attribute__ ((cleanup(gs_local_free_list))) +GS_DEFINE_CLEANUP_FUNCTION(GList*, gs_local_free_list, g_list_free) + +/** + * gs_free_slist: + * + * Call g_slist_free() on a variable location when it goes out + * of scope. + */ +#define gs_free_slist __attribute__ ((cleanup(gs_local_free_slist))) +GS_DEFINE_CLEANUP_FUNCTION(GSList*, gs_local_free_slist, g_slist_free) + +/** + * gs_free_checksum: + * + * Call g_checksum_free() on a variable location when it goes out + * of scope. Note that unlike g_checksum_free(), the variable may + * be %NULL. + */ +#define gs_free_checksum __attribute__ ((cleanup(gs_local_checksum_free))) +GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free) + +/** + * gs_unref_bytes: + * + * Call g_bytes_unref() on a variable location when it goes out + * of scope. Note that unlike g_bytes_unref(), the variable may + * be %NULL. + */ +#define gs_unref_bytes __attribute__ ((cleanup(gs_local_bytes_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref) + +/** + * gs_strfreev: + * + * Call g_strfreev() on a variable location when it goes out of scope. + */ +#define gs_strfreev __attribute__ ((cleanup(gs_local_strfreev))) +GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev) + +/** + * gs_free_error: + * + * Call g_error_free() on a variable location when it goes out of scope. + */ +#define gs_free_error __attribute__ ((cleanup(gs_local_free_error))) +GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free) + +/** + * gs_unref_keyfile: + * + * Call g_key_file_unref() on a variable location when it goes out of scope. + */ +#define gs_unref_keyfile __attribute__ ((cleanup(gs_local_keyfile_unref))) +GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_keyfile_unref, g_key_file_unref) + +static inline void +gs_cleanup_close_fdp (int *fdp) +{ + int fd; + + g_assert (fdp); + + fd = *fdp; + if (fd != -1) + (void) close (fd); +} + +/** + * gs_fd_close: + * + * Call close() on a variable location when it goes out of scope. + */ +#define gs_fd_close __attribute__((cleanup(gs_cleanup_close_fdp))) + +G_END_DECLS + +#endif diff --git a/src/backend/dbus-interface/kyenterpricesettinginfo.cpp b/src/backend/dbus-interface/kyenterpricesettinginfo.cpp new file mode 100644 index 00000000..c1cc1c0a --- /dev/null +++ b/src/backend/dbus-interface/kyenterpricesettinginfo.cpp @@ -0,0 +1,195 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kyenterpricesettinginfo.h" + +void assembleEapMethodTlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTlsInfo &info) +{ + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodTls); + wifi_8021x_sett->setInitialized(true); + wifi_8021x_sett->setEapMethods(list); + wifi_8021x_sett->setIdentity(info.identity); + if (!info.domain.isEmpty()){ + wifi_8021x_sett->setDomainSuffixMatch(info.domain); + } + if (info.bNeedCa) { + QByteArray caCerEndWithNull("file://" + info.caCertPath.toUtf8() + '\0'); + wifi_8021x_sett->setCaCertificate(caCerEndWithNull); + } else { + QByteArray caCerEndWithNull(""); + wifi_8021x_sett->setCaCertificate(caCerEndWithNull); + } + QByteArray cliCertEndWithNull("file://" + info.clientCertPath.toUtf8() + '\0'); + wifi_8021x_sett->setClientCertificate(cliCertEndWithNull); + QByteArray cliPriKeyEndWithNull("file://" + info.clientPrivateKey.toUtf8() + '\0'); + wifi_8021x_sett->setPrivateKey(cliPriKeyEndWithNull); + wifi_8021x_sett->setPrivateKeyPassword(info.clientPrivateKeyPWD); + wifi_8021x_sett->setPrivateKeyPasswordFlags(info.m_privateKeyPWDFlag); + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); + + return; +} + +void assembleEapMethodPeapSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodPeapInfo &info) +{ + qDebug() << "assembleEapMethodPeapSettings"; + + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodPeap); + wifi_8021x_sett->setInitialized(true); + wifi_8021x_sett->setEapMethods(list); + wifi_8021x_sett->setPhase2AuthMethod((NetworkManager::Security8021xSetting::AuthMethod)info.phase2AuthMethod); + wifi_8021x_sett->setIdentity(info.userName); + wifi_8021x_sett->setPassword(info.userPWD); + wifi_8021x_sett->setPasswordFlags(info.m_passwdFlag); + + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); + return; +} + +void assembleEapMethodTtlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTtlsInfo &info) +{ + + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodTtls); + wifi_8021x_sett->setInitialized(true); + wifi_8021x_sett->setEapMethods(list); + if (info.authType == KyTtlsAuthMethod::AUTH_EAP) + { + wifi_8021x_sett->setPhase2AuthEapMethod((NetworkManager::Security8021xSetting::AuthEapMethod)info.authEapMethod);//gtc md5 mschapv2 otp tls + } else if (info.authType == KyTtlsAuthMethod::AUTH_NO_EAP) + { + wifi_8021x_sett->setPhase2AuthMethod((NetworkManager::Security8021xSetting::AuthMethod)info.authNoEapMethod);//chap md5 mschapv2 pap gtc mschap otp tls + } + wifi_8021x_sett->setIdentity(info.userName); + wifi_8021x_sett->setPassword(info.userPWD); + wifi_8021x_sett->setPasswordFlags(info.m_passwdFlag); + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); + return; +} + + +void modifyEapMethodTlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTlsInfo &tlsInfo) +{ + NetworkManager::Security8021xSetting::Ptr setting = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + setting->setInitialized(true); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodTls); + setting->setEapMethods(list); + setting->setIdentity(tlsInfo.identity); + if(!tlsInfo.domain.isEmpty()) + { + setting->setDomainSuffixMatch(tlsInfo.domain); + } + if (tlsInfo.bNeedCa) + { + QByteArray caCerEndWithNull("file://" + tlsInfo.caCertPath.toUtf8() + '\0'); + setting->setCaCertificate(caCerEndWithNull); + } else { + QByteArray caCerEndWithNull(""); + setting->setCaCertificate(caCerEndWithNull); + } + + QByteArray cliCertEndWithNull("file://" + tlsInfo.clientCertPath.toUtf8() + '\0'); + setting->setClientCertificate(cliCertEndWithNull); + QByteArray cliPriKeyEndWithNull("file://" + tlsInfo.clientPrivateKey.toUtf8() + '\0'); + setting->setPrivateKey(cliPriKeyEndWithNull); + setting->setPrivateKeyPasswordFlags(tlsInfo.m_privateKeyPWDFlag); + if(tlsInfo.bChanged) + { + setting->setPrivateKeyPassword(tlsInfo.clientPrivateKeyPWD); + } + return; +} + +void modifyEapMethodPeapSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodPeapInfo &peapInfo) +{ + qDebug() << "assembleEapMethodPeapSettings"; + + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + wifi_8021x_sett->setInitialized(true); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodPeap); + wifi_8021x_sett->setEapMethods(list); + wifi_8021x_sett->setPhase2AuthMethod((NetworkManager::Security8021xSetting::AuthMethod)peapInfo.phase2AuthMethod); + wifi_8021x_sett->setIdentity(peapInfo.userName); + if(peapInfo.bChanged) + { + wifi_8021x_sett->setPassword(peapInfo.userPWD); + } + wifi_8021x_sett->setPasswordFlags(peapInfo.m_passwdFlag); + + QByteArray caCerEndWithNull(""); + wifi_8021x_sett->setCaCertificate(caCerEndWithNull); + + return; +} + +void modifyEapMethodTtlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTtlsInfo &ttlsInfo) +{ + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connSettingPtr->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + + QList list; + list.append(NetworkManager::Security8021xSetting::EapMethod::EapMethodTtls); + wifi_8021x_sett->setInitialized(true); + wifi_8021x_sett->setEapMethods(list); + if (ttlsInfo.authType == KyTtlsAuthMethod::AUTH_EAP) + { + wifi_8021x_sett->setPhase2AuthEapMethod((NetworkManager::Security8021xSetting::AuthEapMethod)ttlsInfo.authEapMethod);//gtc md5 mschapv2 otp tls + } else if (ttlsInfo.authType == KyTtlsAuthMethod::AUTH_NO_EAP) + { + wifi_8021x_sett->setPhase2AuthMethod((NetworkManager::Security8021xSetting::AuthMethod)ttlsInfo.authNoEapMethod);//chap md5 mschapv2 pap gtc mschap otp tls + } + wifi_8021x_sett->setIdentity(ttlsInfo.userName); + if(ttlsInfo.bChanged) + { + wifi_8021x_sett->setPassword(ttlsInfo.userPWD); + } + wifi_8021x_sett->setPasswordFlags(ttlsInfo.m_passwdFlag); + + QByteArray caCerEndWithNull(""); + wifi_8021x_sett->setCaCertificate(caCerEndWithNull); + return; +} diff --git a/src/backend/dbus-interface/kyenterpricesettinginfo.h b/src/backend/dbus-interface/kyenterpricesettinginfo.h new file mode 100644 index 00000000..f95edb49 --- /dev/null +++ b/src/backend/dbus-interface/kyenterpricesettinginfo.h @@ -0,0 +1,165 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYENTERPRICESETTINGINFO_H +#define KYENTERPRICESETTINGINFO_H + +#include +#include + +#include "kylinnetworkresourcemanager.h" +#include + +enum KyEapMethodType { + TLS = 0, + PEAP, + TTLS, +}; + +class KyEapMethodTlsInfo +{ +public: + QString identity; + QString domain; + QString devIfaceName; + QString caCertPath; + bool bNeedCa; + QString clientCertPath; + QString clientPrivateKey; + QString clientPrivateKeyPWD; + NetworkManager::Setting::SecretFlags m_privateKeyPWDFlag; + // only valid when update + bool bChanged; + + inline bool operator == (const KyEapMethodTlsInfo& info) const + { + if (this->identity == info.identity + && this->domain == info.domain +// && this->devIfaceName == info.devIfaceName + && this->caCertPath == info.caCertPath + && this->bNeedCa == info.bNeedCa + && this->clientCertPath == info.clientCertPath + && this->clientPrivateKey == info.clientPrivateKey + && this->clientPrivateKeyPWD == info.clientPrivateKeyPWD + && this->m_privateKeyPWDFlag == info.m_privateKeyPWDFlag) { + return true; + } else { + return false; + } + } +}; + +typedef enum { + KyAuthEapMethodUnknown = 0, + KyAuthEapMethodMd5, + KyAuthEapMethodMschapv2, + KyAuthEapMethodOtp, + KyAuthEapMethodGtc, + KyAuthEapMethodTls +} KyEapMethodAuth; + +typedef enum{ + KyAuthMethodUnknown = 0, + KyAuthMethodPap, + KyAuthMethodChap, + KyAuthMethodMschap, + KyAuthMethodMschapv2, + KyAuthMethodGtc, + KyAuthMethodOtp, + KyAuthMethodMd5, + KyAuthMethodTls +} KyNoEapMethodAuth; + + +class KyEapMethodPeapInfo +{ +public: + KyNoEapMethodAuth phase2AuthMethod; + QString userName; + QString userPWD; + NetworkManager::Setting::SecretFlags m_passwdFlag; + // only valid when update + bool bChanged; + + inline bool operator == (const KyEapMethodPeapInfo& info) const + { + if (this->phase2AuthMethod == info.phase2AuthMethod + && this->userName == info.userName + && this->userPWD == info.userPWD + && this->m_passwdFlag == info.m_passwdFlag) { + return true; + } else { + return false; + } + } +}; + +enum KyTtlsAuthMethod +{ + AUTH_EAP, + AUTH_NO_EAP +}; + +class KyEapMethodTtlsInfo +{ +public: + KyTtlsAuthMethod authType; + KyEapMethodAuth authEapMethod; + KyNoEapMethodAuth authNoEapMethod; + QString userName; + QString userPWD; + NetworkManager::Setting::SecretFlags m_passwdFlag; + // only valid when update + bool bChanged; + + inline bool operator == (const KyEapMethodTtlsInfo& info) const + { + if (this->authType == info.authType) { + if (authType == AUTH_EAP) { + if (this->authEapMethod == info.authEapMethod + && this ->userName == info.userName + && this->userPWD == info.userPWD + && this->m_passwdFlag == info.m_passwdFlag) { + return true; + } + } else { + if (authType == AUTH_EAP) { + if (this->authNoEapMethod == info.authNoEapMethod + && this ->userName == info.userName + && this->userPWD == info.userPWD + && this->m_passwdFlag == info.m_passwdFlag) { + return true; + } + } + } + + } + return false; + } +}; + +void assembleEapMethodTlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTlsInfo &tlsInfo); +void assembleEapMethodPeapSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodPeapInfo &peapInfo); +void assembleEapMethodTtlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTtlsInfo &ttlsInfo); + +void modifyEapMethodTlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTlsInfo &tlsInfo); +void modifyEapMethodPeapSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodPeapInfo &peapInfo); +void modifyEapMethodTtlsSettings(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyEapMethodTtlsInfo &ttlsInfo); + +#endif // KYENTERPRICESETTINGINFO_H diff --git a/src/backend/dbus-interface/kylinactiveconnectresource.cpp b/src/backend/dbus-interface/kylinactiveconnectresource.cpp new file mode 100644 index 00000000..0a613f75 --- /dev/null +++ b/src/backend/dbus-interface/kylinactiveconnectresource.cpp @@ -0,0 +1,749 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kylinutil.h" +#include "kylinactiveconnectresource.h" +#include "kywirelessconnectoperation.h" + +#include +#include +#include + +#define LOG_FLAG "[KyActiveConnectResourse]" + +KyActiveConnectResourse::KyActiveConnectResourse(QObject *parent) : QObject(parent) +{ + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); + m_networkdevice = new KyNetworkDeviceResourse(); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::activeConnectionRemove, + this, &KyActiveConnectResourse::activeConnectRemove); + connect(m_networkResourceInstance, &KyNetworkResourceManager::activeConnectStateChangeReason, + this, &KyActiveConnectResourse::stateChangeReason); + connect(m_networkResourceInstance, &KyNetworkResourceManager::vpnActiveConnectStateChangeReason, + this, &KyActiveConnectResourse::vpnConnectChangeReason); +} + +KyActiveConnectResourse::~KyActiveConnectResourse() +{ + m_networkResourceInstance = nullptr; + if (nullptr != m_networkdevice) { + delete m_networkdevice; + m_networkdevice = nullptr; + } +} + +KyConnectItem *KyActiveConnectResourse::getActiveConnectionItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get active connect item"; + + if (nullptr == activeConnectPtr) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect is empty"; + return nullptr; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectPtr->state()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect is not activated" + <<"connect name:"<connection()->name() + <<"connect state"<< activeConnectPtr->state(); + return nullptr; + } + + KyConnectItem *activeConnectItem = new KyConnectItem(); + activeConnectItem->m_connectUuid = activeConnectPtr->uuid(); + + NetworkManager::Connection::Ptr connectPtr = activeConnectPtr->connection(); + activeConnectItem->m_connectName = connectPtr->name(); + activeConnectItem->m_connectPath = connectPtr->path(); + + activeConnectItem->m_connectState = NetworkManager::ActiveConnection::State::Activated; + + return activeConnectItem; +} + +KyConnectItem *KyActiveConnectResourse::getActiveConnectionByUuid(QString connectUuid) +{ + NetworkManager::ActiveConnection::List activeConnectList; + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect list is empty"; + return nullptr; + } + //可能存在已无效的ActiveConnection,所以使用uuid遍历处理需要满足device不为空且ActiveConnection状态为已连接 + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + KyConnectItem *activeConnectItem = nullptr; + bool isFind = false; + for (int index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (connectUuid != activeConnectPtr->uuid()) { + continue; + } + + activeConnectItem = getActiveConnectionItem(activeConnectPtr); + + if (nullptr == activeConnectItem || activeConnectPtr->devices().isEmpty()) { + continue; + } else { + isFind = true; + break; + } + } + + if (!isFind) { + return nullptr; + } + + QString ifaceUni = activeConnectPtr->devices().at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + activeConnectItem->m_ifaceName = devicePtr->interfaceName(); + activeConnectItem->m_itemType = activeConnectPtr->type(); + + return activeConnectItem; +} + +KyConnectItem *KyActiveConnectResourse::getActiveConnectionByUuid(QString connectUuid, + QString deviceName) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(connectUuid); + + if (nullptr == activeConnectPtr) { + qWarning()<< "[KyActiveConnectResourse]" <<"it can not find connect "<< connectUuid; + return nullptr; + } + + QStringList interfaces = activeConnectPtr->devices(); + for (int index = 0; index < interfaces.size(); ++index) { + QString ifaceUni = interfaces.at(index); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + if (devicePtr.isNull()) { + continue; + } + + if (devicePtr->interfaceName() == deviceName) { + KyConnectItem *activeConnectItem = + getActiveConnectionItem(activeConnectPtr); + if (nullptr == activeConnectItem) { + return nullptr; + } + activeConnectItem->m_ifaceName = deviceName; + activeConnectItem->m_itemType = activeConnectPtr->type(); + return activeConnectItem; + } + } + + return nullptr; +} + +void KyActiveConnectResourse::getActiveConnectionList(QString deviceName, + NetworkManager::ConnectionSettings::ConnectionType connectionType, + QList &activeConnectItemList) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get activate connect for device" + << deviceName <<"connect type:"<getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect list is empty"; + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (int index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (connectionType != activeConnectPtr->type()) { + qDebug()<<"[KyActiveConnectResourse]" <<"the connect type " << activeConnectPtr->type() + <<"connect name" << activeConnectPtr->connection()->name(); + continue; + } + + QStringList interfaces = activeConnectPtr->devices(); + for (int index = 0; index < interfaces.size(); ++index) { + QString ifaceUni = interfaces.at(index); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + if (devicePtr->interfaceName() == deviceName) { + KyConnectItem *activeConnectItem = + getActiveConnectionItem(activeConnectPtr); + if (nullptr != activeConnectItem) { + activeConnectItem->m_ifaceName = deviceName; + activeConnectItem->m_itemType = connectionType; + activeConnectItemList << activeConnectItem; + //activeConnectItem->dumpInfo(); + } + + activeConnectPtr = nullptr; + break; + } + } + } + + return; +} + +#if 0 +void KyActiveConnectResourse::getWiredActivateConnect(QList &wiredActiveConnectItemList) +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + qDebug()<<"[KyActiveConnectResourse]"<<"get wired activate connect"; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect list is empty"; + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (NetworkManager::ConnectionSettings::ConnectionType::Wired + != activeConnectPtr->type()) { + continue; + } + + KyWiredConnectItem *activeConnectItem = + getWiredActiveConnectItem(activeConnectPtr); + if (nullptr != activeConnectItem) { + wiredActiveConnectItemList << activeConnectItem; + activeConnectItem->dumpInfo(); + } + + activeConnectPtr = nullptr; + } + + return; +} + +KyWiredConnectItem *KyActiveConnectResourse::getWiredActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get active connect item"; + + if (nullptr == activeConnectPtr) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect is empty"; + return nullptr; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectPtr->state()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect is not activated" + <connection()->name() << activeConnectPtr->state(); + return nullptr; + } + + KyWiredConnectItem *wiredItem = new KyWiredConnectItem(); + NetworkManager::Connection::Ptr connectPtr = activeConnectPtr->connection(); + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + + wiredItem->m_connectName = connectPtr->name(); + qDebug() <<"[KyActiveConnectResourse]"<< "connect uuid" << connectPtr->uuid() + << "active connect uuid" << activeConnectPtr->uuid(); + wiredItem->m_connectUuid = activeConnectPtr->uuid(); + wiredItem->m_ifaceName = settingPtr->interfaceName(); + + + getActiveConnectIp(activeConnectPtr, wiredItem->m_ipv4, wiredItem->m_ipv6); + + m_networkdevice->getWiredHardwareInfo(settingPtr->interfaceName(), wiredItem); + + wiredItem->m_state = NetworkManager::ActiveConnection::State::Activated; + //wiredItem->m_itemType; + + return wiredItem; +} + +#endif + +void KyActiveConnectResourse::getActiveConnectIpInfo( + const QString &connectUuid, + QString &ipv4Address, + QString &ipv6Address) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(connectUuid); + + if (activeConnectPtr.isNull()) { + qWarning()<< "[KyActiveConnectResourse]" <<"it can not find connect "<< connectUuid; + return; + } + + getActiveConnectIp(activeConnectPtr, ipv4Address, ipv6Address); + + return; +} + +void KyActiveConnectResourse::getActiveConnectIp( + NetworkManager::ActiveConnection::Ptr activeConnectPtr, + QString &ipv4Address, + QString &ipv6Address) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get active connect ip info"; + + NetworkManager::IpConfig ipv4Config =activeConnectPtr->ipV4Config(); + if (ipv4Config.isValid()) { + if (!ipv4Config.addresses().isEmpty()) { + NetworkManager::IpAddress address = ipv4Config.addresses().at(0); + ipv4Address = address.ip().toString(); + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"the ipv4 address is empty."; + } + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"ipv4 config is not valid"; + } + + NetworkManager::IpConfig ipv6Config =activeConnectPtr->ipV6Config(); + if (ipv6Config.isValid()) { + if (!ipv6Config.addresses().isEmpty()) { + NetworkManager::IpAddress address = ipv6Config.addresses().at(0); + ipv6Address = address.ip().toString(); + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"ipv6 address is empty"; + } + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"ipv6 config is not valid"; + } + + return; +} + +void KyActiveConnectResourse::getActiveConnectDnsInfo( + const QString &connectUuid, + QList &ipv4Dns, + QList &ipv6Dns) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(connectUuid); + if (activeConnectPtr.isNull()) { + qWarning()<< "[KyActiveConnectResourse]" <<"it can not find connect "<< connectUuid; + return; + } + + getActiveConnectDns(activeConnectPtr, ipv4Dns, ipv6Dns); + + return; +} + +void KyActiveConnectResourse::getActiveConnectDns( + NetworkManager::ActiveConnection::Ptr activeConnectPtr, + QList &ipv4Dns, + QList &ipv6Dns) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get active connect nameservice info"; + + NetworkManager::IpConfig ipv4Config = activeConnectPtr->ipV4Config(); + if (ipv4Config.isValid()) { + ipv4Dns = ipv4Config.nameservers(); + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"ipv4 config is not valid"; + } + + NetworkManager::IpConfig ipv6Config =activeConnectPtr->ipV6Config(); + if (ipv6Config.isValid()) { + ipv6Dns = ipv6Config.nameservers(); + } else { + qWarning()<<"[KyActiveConnectResourse]"<<"ipv6 config is not valid"; + } + + return; +} + +KyVpnConnectItem *KyActiveConnectResourse::getVpnActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get vpn active connect item"; + + if (nullptr == activeConnectPtr) { + qWarning()<<"[KyActiveConnectResourse]"<<"get vpn active connect failed, the active connect is empty"; + return nullptr; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectPtr->state()) { + qWarning()<<"[KyActiveConnectResourse]"<<"the active connect is not activated" + <connection()->name() << activeConnectPtr->state(); + return nullptr; + } + + KyVpnConnectItem *vpnItem = new KyVpnConnectItem(); + NetworkManager::Connection::Ptr connectPtr = activeConnectPtr->connection(); + vpnItem->m_vpnName = connectPtr->name(); + + vpnItem->m_vpnUuid = activeConnectPtr->uuid(); + + NetworkManager::ConnectionSettings::Ptr settingsPtr = connectPtr->settings(); + NetworkManager::VpnSetting::Ptr vpnSetting = settingsPtr->setting(NetworkManager::Setting::Vpn).dynamicCast(); + NMStringMap vpnDataMap = vpnSetting->data(); + if (vpnDataMap.isEmpty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"get vpn connection Data failed, the data is empty"; + } else { + vpnItem->m_vpnGateWay = vpnDataMap["gateway"]; + vpnItem->m_vpnUser = vpnDataMap["user"]; + if ( "yes" == vpnDataMap["require-mppe"]) { + vpnItem->m_vpnMppe = true; + } else { + vpnItem->m_vpnMppe = false; + qDebug()<<"[KyActiveConnectResourse]"<<"vpn mppe required:"<< vpnDataMap["require-mppe"]; + } + } + + getActiveConnectIp(activeConnectPtr, vpnItem->m_vpnIpv4Address, vpnItem->m_vpnIpv6Address); + + NetworkManager::VpnConnection *p_vpnConnect = qobject_cast(activeConnectPtr.data()); + vpnItem->m_vpnState = p_vpnConnect->state(); + + return vpnItem; +} + +void KyActiveConnectResourse::getVpnActivateConnect(QList &vpnActiveConnectItemList) +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"get vpn active connect failed, the active connect list is empty"; + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (!activeConnectPtr->vpn()) { + continue; + } + + KyVpnConnectItem *activeConnectItem = + getVpnActiveConnectItem(activeConnectPtr); + if (nullptr != activeConnectItem) { + vpnActiveConnectItemList << activeConnectItem; + } + + activeConnectPtr = nullptr; + } + + return; +} + +KyBluetoothConnectItem *KyActiveConnectResourse::getBtActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get bluetooth active connect item"; + + if (nullptr == activeConnectPtr) { + qWarning()<<"[KyActiveConnectResourse]"<<"get bluetooth item failed, the active connect is empty"; + return nullptr; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectPtr->state()) { + qWarning()<<"[KyActiveConnectResourse]"<<"get bluetooth item failed, the active connect is not activated" + <connection()->name() << activeConnectPtr->state(); + return nullptr; + } + + KyBluetoothConnectItem *bluetoothItem = new KyBluetoothConnectItem(); + NetworkManager::Connection::Ptr connectPtr = activeConnectPtr->connection(); + + bluetoothItem->m_connectName = connectPtr->name(); + bluetoothItem->m_connectUuid = activeConnectPtr->uuid(); + bluetoothItem->m_state = NetworkManager::ActiveConnection::State::Activated; + + getActiveConnectIp(activeConnectPtr, bluetoothItem->m_ipv4Address, bluetoothItem->m_ipv6Address); + + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + NetworkManager::BluetoothSetting::Ptr bluetoothSetting = + settingPtr->setting(NetworkManager::Setting::Bluetooth).dynamicCast(); + bluetoothItem->m_deviceAddress = bluetoothSetting->bluetoothAddress(); + QByteArray btAddrArray = bluetoothSetting->bluetoothAddress(); + for (int index = 0; index < btAddrArray.size(); ++index) { + qDebug("bt address %d %s", index, btAddrArray[index]); + } + qDebug()<<"bluetooth device address"<m_deviceAddress; + //wiredItem->m_itemType; + + return bluetoothItem; +} + +void KyActiveConnectResourse::getBtActivateConnect(QList &btActiveConnectItemList) +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]"<<"get bluetooth active connect failed, the active connect list is empty"; + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Bluetooth + != activeConnectPtr->type()) { + continue; + } + + KyBluetoothConnectItem *activeConnectItem = getBtActiveConnectItem(activeConnectPtr); + if (nullptr != activeConnectItem) { + btActiveConnectItemList << activeConnectItem; + } + + activeConnectPtr = nullptr; + } + + return; +} + +KyApConnectItem *KyActiveConnectResourse::getApActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr) +{ + qDebug()<<"[KyActiveConnectResourse]"<<"get wireless ap active connect item"; + + if (nullptr == activeConnectPtr) { + qWarning()<<"[KyActiveConnectResourse]"<<"get wireless ap item failed, the active connect is empty"; + return nullptr; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectPtr->state()) { + qWarning()<<"[KyActiveConnectResourse]"<<"get ap item failed, the active connect is not activated" + <connection()->name() << activeConnectPtr->state(); + return nullptr; + } + + NetworkManager::Connection::Ptr connectPtr = activeConnectPtr->connection(); + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + NetworkManager::WirelessSetting::Ptr wirelessSetting + = settingPtr->setting(NetworkManager::Setting::Wireless).dynamicCast(); + if (NetworkManager::WirelessSetting::NetworkMode::Ap + != wirelessSetting->mode()) { + qDebug() << "[KyActiveConnectResourse]" <<"get ap item failed, the active connect mode is not ap."; + return nullptr; + } + + KyApConnectItem *apConnectItem = new KyApConnectItem(); + apConnectItem->m_connectName = connectPtr->name(); + apConnectItem->m_connectUuid = activeConnectPtr->uuid(); + apConnectItem->m_ifaceName = settingPtr->interfaceName(); + + QByteArray rawSsid = wirelessSetting->ssid(); + apConnectItem->m_connectSsid = getSsidFromByteArray(rawSsid); + + + KyWirelessConnectOperation wirelessOperation; + apConnectItem->m_password = wirelessOperation.getPsk(apConnectItem->m_connectUuid); + + return apConnectItem; +} + +void KyActiveConnectResourse::getApActivateConnect(QList &apConnectItemList) +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]" + <<"get ap active connect failed, the active connect list is empty"; + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless + != activeConnectPtr->type()) { + continue; + } + + KyApConnectItem *apConnectItem = getApActiveConnectItem(activeConnectPtr); + if (nullptr != apConnectItem) { + apConnectItemList << apConnectItem; + } + + activeConnectPtr = nullptr; + } + + return; +} + +QString KyActiveConnectResourse::getDeviceOfActivateConnect(QString conUuid) +{ + QString deviceName = ""; + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(conUuid); + + if (nullptr == activeConnectPtr) { + qWarning()<< "[KyActiveConnectResourse]" <<"it can not find connect "<< conUuid; + return deviceName; + } + + QStringList interfaces = activeConnectPtr->devices(); + if (interfaces.isEmpty()) { + qWarning()<< LOG_FLAG << "get device of active connection failed."; + return deviceName; + } + + QString ifaceUni = interfaces.at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + deviceName = devicePtr->interfaceName(); + + return deviceName; +} + +bool KyActiveConnectResourse::connectionIsVirtual(QString uuid) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(uuid); + + if (activeConnectPtr.isNull()) { + qWarning()<< LOG_FLAG << "check connection virtual is failed."; + return false; + } + + QStringList interfaces = activeConnectPtr->devices(); + if (interfaces.isEmpty()) { + qWarning()<< LOG_FLAG << "active connection get device failed."; + return false; + } + + QString ifaceUni = interfaces.at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + if (devicePtr.isNull()) { + return false; + } + + return !m_networkdevice->deviceIsWired(devicePtr->interfaceName()); +} + +bool KyActiveConnectResourse::wiredConnectIsActived() +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]" + <<"get active connect failed, the active connect list is empty"; + return false; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wired + != activeConnectPtr->type()) { + continue; + } + + if (connectionIsVirtual(activeConnectPtr->uuid())) { + continue; + } + + if (activeConnectPtr->state() == NetworkManager::ActiveConnection::State::Activated) { + return true; + } + } + + return false; +} + +bool KyActiveConnectResourse::checkWirelessStatus(NetworkManager::ActiveConnection::State state) +{ + int index = 0; + NetworkManager::ActiveConnection::List activeConnectList; + + activeConnectList.clear(); + activeConnectList = m_networkResourceInstance->getActiveConnectList(); + + if (activeConnectList.empty()) { + qWarning()<<"[KyActiveConnectResourse]" + <<"get active connect failed, the active connect list is empty"; + return false; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = nullptr; + for (index = 0; index < activeConnectList.size(); index++) { + activeConnectPtr = activeConnectList.at(index); + if (activeConnectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless + != activeConnectPtr->type()) { + continue; + } + + if (activeConnectPtr->state() == state) { + return true; + } + } + + return false; + +} + +QString KyActiveConnectResourse::getAcitveConnectionPathByUuid(QString connectUuid) +{ + NetworkManager::ActiveConnection::Ptr activeAonnectPtr = nullptr; + + activeAonnectPtr = m_networkResourceInstance->getActiveConnect(connectUuid); + if (nullptr == activeAonnectPtr) { + return nullptr; + } + + return activeAonnectPtr->path(); +} diff --git a/src/backend/dbus-interface/kylinactiveconnectresource.h b/src/backend/dbus-interface/kylinactiveconnectresource.h new file mode 100644 index 00000000..d38196a9 --- /dev/null +++ b/src/backend/dbus-interface/kylinactiveconnectresource.h @@ -0,0 +1,94 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINACTIVECONNECTRESOURCE_H +#define KYLINACTIVECONNECTRESOURCE_H + +#include +#include "kylinnetworkresourcemanager.h" +#include "kylinconnectitem.h" +#include "kylinnetworkdeviceresource.h" +#include "kylinvpnconnectitem.h" +#include "kylinbluetoothconnectitem.h" +#include "kylinapconnectitem.h" + +class KyActiveConnectResourse : public QObject +{ + Q_OBJECT +public: + explicit KyActiveConnectResourse(QObject *parent = nullptr); + ~KyActiveConnectResourse(); + +public: + KyConnectItem *getActiveConnectionByUuid(QString connectUuid); + KyConnectItem *getActiveConnectionByUuid(QString connectUuid, QString deviceName); + void getActiveConnectionList(QString deviceName, + NetworkManager::ConnectionSettings::ConnectionType connectionType, + QList &connectItemList); + void getActiveConnectIpInfo(const QString &uuid, + QString &ipv4Address, + QString &ipv6Address); + void getActiveConnectDnsInfo(const QString &uuid, + QList &ipv4Dns, + QList &ipv6Dns); + + //void getWiredActivateConnect(QList &wiredActiveConnectItemList); + void getVpnActivateConnect(QList &vpnActiveConnectItemList); + void getBtActivateConnect(QList &btActiveConnectItemList); + + void getApActivateConnect(QList &apConnectItemList); + + QString getDeviceOfActivateConnect(QString conUuid); + + bool connectionIsVirtual(QString uuid); + bool wiredConnectIsActived(); + bool checkWirelessStatus(NetworkManager::ActiveConnection::State state); + QString getAcitveConnectionPathByUuid(QString uuid); + +private: + void getActiveConnectIp(NetworkManager::ActiveConnection::Ptr activeConnectPtr, + QString &ipv4Address, + QString &ipv6Address); + void getActiveConnectDns(NetworkManager::ActiveConnection::Ptr activeConnectPtr, + QList &ipv4Dns, + QList &ipv6Dns); + + KyConnectItem *getActiveConnectionItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr); + + // KyWiredConnectItem *getWiredActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr); + KyVpnConnectItem *getVpnActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr); + KyBluetoothConnectItem *getBtActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr); + KyApConnectItem *getApActiveConnectItem(NetworkManager::ActiveConnection::Ptr activeConnectPtr); + +Q_SIGNALS: + void activeConnectAdd(QString activeConnectUuid); + void updateActiveConnect(QString activeConnectUuid); + void activeConnectRemove(QString activeConnectUuid); + void stateChangeReason(QString uuid, + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason); + void vpnConnectChangeReason(QString uuid, + NetworkManager::VpnConnection::State state, + NetworkManager::VpnConnection::StateChangeReason reason); + +private: + KyNetworkResourceManager *m_networkResourceInstance = nullptr; + KyNetworkDeviceResourse *m_networkdevice = nullptr; +}; +#endif // KYLINACTIVECONNECTRESOURCE_H diff --git a/src/backend/dbus-interface/kylinagent.c b/src/backend/dbus-interface/kylinagent.c new file mode 100644 index 00000000..393d9fc4 --- /dev/null +++ b/src/backend/dbus-interface/kylinagent.c @@ -0,0 +1,836 @@ +#include "kylinagent.h" +#include + +#define KEYRING_UUID_TAG "connection-uuid" +#define KEYRING_SN_TAG "setting-name" +#define KEYRING_SK_TAG "setting-key" + +static const SecretSchema network_manager_secret_schema = { + "org.freedesktop.NetworkManager.Connection", + SECRET_SCHEMA_DONT_MATCH_NAME, + { + { KEYRING_UUID_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { KEYRING_SN_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { KEYRING_SK_TAG, SECRET_SCHEMA_ATTRIBUTE_STRING }, + { NULL, 0 }, + } +}; + +G_DEFINE_TYPE (AppletAgent, applet_agent, NM_TYPE_SECRET_AGENT_OLD); + +#define APPLET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APPLET_TYPE_AGENT, AppletAgentPrivate)) + +typedef struct { + GHashTable *requests; + gboolean vpn_only; + + gboolean disposed; +} AppletAgentPrivate; + +enum { + GET_SECRETS, + CANCEL_SECRETS, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + + +/*******************************************************/ + +typedef struct { + guint id; + + NMSecretAgentOld *agent; + NMConnection *connection; + char *path; + char *setting_name; + char **hints; + guint32 flags; + NMSecretAgentOldGetSecretsFunc get_callback; + NMSecretAgentOldSaveSecretsFunc save_callback; + NMSecretAgentOldDeleteSecretsFunc delete_callback; + gpointer callback_data; + + GCancellable *cancellable; + gint keyring_calls; +} Request; + +static Request * +request_new (NMSecretAgentOld *agent, + NMConnection *connection, + const char *connection_path, + const char *setting_name, + const char **hints, + guint32 flags, + NMSecretAgentOldGetSecretsFunc get_callback, + NMSecretAgentOldSaveSecretsFunc save_callback, + NMSecretAgentOldDeleteSecretsFunc delete_callback, + gpointer callback_data) +{ + static guint32 counter = 1; + Request *r; + + r = g_slice_new0 (Request); + r->id = counter++; + r->agent = agent; + r->connection = g_object_ref (connection); + r->path = g_strdup (connection_path); + r->setting_name = g_strdup (setting_name); + if (hints) + r->hints = g_strdupv ((gchar **) hints); + r->flags = flags; + r->get_callback = get_callback; + r->save_callback = save_callback; + r->delete_callback = delete_callback; + r->callback_data = callback_data; + r->cancellable = g_cancellable_new (); + return r; +} + +static void +request_free (Request *r) +{ + if (!g_cancellable_is_cancelled (r->cancellable)) + g_hash_table_remove (APPLET_AGENT_GET_PRIVATE (r->agent)->requests, GUINT_TO_POINTER (r->id)); + + /* By the time the request is freed, all keyring calls should be completed */ + g_warn_if_fail (r->keyring_calls == 0); + + g_object_unref (r->connection); + g_free (r->path); + g_free (r->setting_name); + g_strfreev (r->hints); + g_object_unref (r->cancellable); + memset (r, 0, sizeof (*r)); + g_slice_free (Request, r); +} + +/*******************************************************/ + +static void +get_save_cb (NMSecretAgentOld *agent, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + /* Ignored */ +} + +static void +get_secrets_cb (AppletAgent *self, + GVariant *secrets, + GError *error, + gpointer user_data) +{ + Request *r = user_data; + + /* 'secrets' shouldn't be valid if there was an error */ + if (error) { + g_warn_if_fail (secrets == NULL); + secrets = NULL; + } + + if (!g_cancellable_is_cancelled (r->cancellable)) { + /* Save updated secrets as long as user-interaction was allowed; otherwise + * we'd be saving secrets we just pulled out of the keyring which is somewhat + * redundant. + */ + if (secrets && (r->flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE)) { + NMConnection *dupl; + GVariantIter iter; + const char *setting_name; + + /* Copy the existing connection and update its secrets */ + dupl = nm_simple_connection_new_clone (r->connection); + g_variant_iter_init (&iter, secrets); + while (g_variant_iter_next (&iter, "{&s@a{sv}}", (gpointer) &setting_name, NULL)) + nm_connection_update_secrets (dupl, setting_name, secrets, NULL); + + /* And save updated secrets to the keyring */ + nm_secret_agent_old_save_secrets (NM_SECRET_AGENT_OLD (self), dupl, get_save_cb, NULL); + g_object_unref (dupl); + } + + r->get_callback (NM_SECRET_AGENT_OLD (r->agent), r->connection, secrets, error, r->callback_data); + } + request_free (r); +} + +static void +ask_for_secrets (Request *r) +{ + /* Ask the applet to get some secrets for us */ + g_signal_emit (r->agent, + signals[GET_SECRETS], + 0, + GUINT_TO_POINTER (r->id), + r->connection, + r->setting_name, + r->hints, + r->flags, + get_secrets_cb, + r); +} + +static void +check_always_ask_cb (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + gboolean *always_ask = user_data; + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (flags & NM_SETTING_PARAM_SECRET) { + if (nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) { + if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) + *always_ask = TRUE; + } + } +} + +static gboolean +has_always_ask (NMSetting *setting) +{ + gboolean always_ask = FALSE; + + nm_setting_enumerate_values (setting, check_always_ask_cb, &always_ask); + return always_ask; +} + +static gboolean +is_connection_always_ask (NMConnection *connection) +{ + NMSettingConnection *s_con; + const char *ctype; + NMSetting *setting; + + /* For the given connection type, check if the secrets for that connection + * are always-ask or not. + */ + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + ctype = nm_setting_connection_get_connection_type (s_con); + + setting = nm_connection_get_setting_by_name (connection, ctype); + g_return_val_if_fail (setting != NULL, FALSE); + + if (has_always_ask (setting)) + return TRUE; + + /* Try type-specific settings too; be a bit paranoid and only consider + * secrets from settings relevant to the connection type. + */ + if (NM_IS_SETTING_WIRELESS (setting)) { + setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); + if (setting && has_always_ask (setting)) + return TRUE; + setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + if (setting && has_always_ask (setting)) + return TRUE; + } else if (NM_IS_SETTING_WIRED (setting)) { + setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE); + if (setting && has_always_ask (setting)) + return TRUE; + setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); + if (setting && has_always_ask (setting)) + return TRUE; + } + + return FALSE; +} + +static void +keyring_find_secrets_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + Request *r = user_data; + GError *error = NULL; + GError *search_error = NULL; + const char *connection_id = NULL; + GVariantBuilder builder_setting, builder_connection; + GVariant *settings = NULL; + GList *list = NULL; + GList *iter; + gboolean hint_found = FALSE, ask = FALSE; + + r->keyring_calls--; + if (g_cancellable_is_cancelled (r->cancellable)) { + /* Callback already called by NM or dispose */ + request_free (r); + return; + } + + list = secret_service_search_finish (NULL, result, &search_error); + connection_id = nm_connection_get_id (r->connection); + + if (g_error_matches (search_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + error = g_error_new_literal (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + "The secrets request was canceled by the user"); + g_error_free (search_error); + goto done; + } else if ( (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) + && g_error_matches (search_error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + /* If the connection always asks for secrets, tolerate + * keyring service not being present. */ + g_clear_error (&search_error); + } else if (search_error) { + error = g_error_new (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "%s.%d - failed to read secrets from keyring (%s)", + __FILE__, __LINE__, search_error->message); + g_error_free (search_error); + goto done; + } + + /* Only ask if we're allowed to, so that eg a connection editor which + * requests secrets for its UI, for a connection which doesn't have any + * secrets yet, doesn't trigger the applet secrets dialog. + */ + if ( (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) + && g_list_length (list) == 0) { + g_message ("No keyring secrets found for %s/%s; asking user.", connection_id, r->setting_name); + ask_for_secrets (r); + return; + } + + g_variant_builder_init (&builder_setting, NM_VARIANT_TYPE_SETTING); + + /* Extract the secrets from the list of matching keyring items */ + for (iter = list; iter != NULL; iter = g_list_next (iter)) { + SecretItem *item = iter->data; + SecretValue *secret; + const char *key_name; + GHashTable *attributes; + + secret = secret_item_get_secret (item); + if (secret) { + attributes = secret_item_get_attributes (item); + key_name = g_hash_table_lookup (attributes, KEYRING_SK_TAG); + if (!key_name) { + g_hash_table_unref (attributes); + secret_value_unref (secret); + continue; + } + + g_variant_builder_add (&builder_setting, "{sv}", key_name, + g_variant_new_string (secret_value_get (secret, NULL))); + + /* See if this property matches a given hint */ + if (r->hints && r->hints[0]) { + if (!g_strcmp0 (r->hints[0], key_name) || !g_strcmp0 (r->hints[1], key_name)) + hint_found = TRUE; + } + + g_hash_table_unref (attributes); + secret_value_unref (secret); + break; + } + } + + /* If there were hints, and none of the hints were returned by the keyring, + * get some new secrets. + */ + if (r->flags) { + if (r->hints && r->hints[0] && !hint_found) + ask = TRUE; + else if (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) { + g_message ("New secrets for %s/%s requested; ask the user", connection_id, r->setting_name); + ask = TRUE; + } else if ( (r->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) + && is_connection_always_ask (r->connection)) + ask = TRUE; + } + + /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that + * will contain all the individual settings hashes. + */ + g_variant_builder_init (&builder_connection, NM_VARIANT_TYPE_CONNECTION); + g_variant_builder_add (&builder_connection, "{sa{sv}}", r->setting_name, &builder_setting); + settings = g_variant_builder_end (&builder_connection); + +done: + g_list_free_full (list, g_object_unref); + if (ask) { + GVariantIter dict_iter; + const char *setting_name; + GVariant *setting_dict; + + /* Stuff all the found secrets into the connection for the UI to use */ + g_variant_iter_init (&dict_iter, settings); + while (g_variant_iter_next (&dict_iter, "{s@a{sv}}", &setting_name, &setting_dict)) { + nm_connection_update_secrets (r->connection, + setting_name, + setting_dict, + NULL); + g_variant_unref (setting_dict); + } + + ask_for_secrets (r); + } else { + /* Otherwise send the secrets back to NetworkManager */ + r->get_callback (NM_SECRET_AGENT_OLD (r->agent), r->connection, error ? NULL : settings, error, r->callback_data); + request_free (r); + } + + if (settings) + g_variant_unref (settings); + g_clear_error (&error); +} + +static void +get_secrets (NMSecretAgentOld *agent, + NMConnection *connection, + const char *connection_path, + const char *setting_name, + const char **hints, + guint32 flags, + NMSecretAgentOldGetSecretsFunc callback, + gpointer callback_data) +{ + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent); + Request *r; + GError *error = NULL; + NMSettingConnection *s_con; + NMSetting *setting; + const char *uuid, *ctype; + GHashTable *attrs; + + setting = nm_connection_get_setting_by_name (connection, setting_name); + if (!setting) { + error = g_error_new (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "%s.%d - Connection didn't have requested setting '%s'.", + __FILE__, __LINE__, setting_name); + callback (agent, connection, NULL, error, callback_data); + g_error_free (error); + return; + } + + uuid = nm_connection_get_uuid (connection); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + ctype = nm_setting_connection_get_connection_type (s_con); + + if (!uuid || !ctype) { + error = g_error_new (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "%s.%d - Connection didn't have required UUID.", + __FILE__, __LINE__); + callback (agent, connection, NULL, error, callback_data); + g_error_free (error); + return; + } + + /* Track the secrets request */ + r = request_new (agent, connection, connection_path, setting_name, hints, flags, callback, NULL, NULL, callback_data); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r); + + /* VPN passwords are handled by the VPN plugin's auth dialog */ + if (!strcmp (ctype, NM_SETTING_VPN_SETTING_NAME)) { + ask_for_secrets (r); + return; + } + + /* Only handle non-VPN secrets if we're supposed to */ + if (priv->vpn_only == TRUE) { + error = g_error_new_literal (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_NO_SECRETS, + "Only handling VPN secrets at this time."); + callback (agent, connection, NULL, error, callback_data); + g_error_free (error); + return; + } + + /* For everything else we scrape the keyring for secrets first, and ask + * later if required. + */ + attrs = secret_attributes_build (&network_manager_secret_schema, + KEYRING_UUID_TAG, uuid, + KEYRING_SN_TAG, setting_name, + NULL); + + secret_service_search (NULL, &network_manager_secret_schema, attrs, + SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS, + r->cancellable, keyring_find_secrets_cb, r); + + r->keyring_calls++; + g_hash_table_unref (attrs); +} + +/*******************************************************/ + +static void +cancel_get_secrets (NMSecretAgentOld *agent, + const char *connection_path, + const char *setting_name) +{ + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent); + GHashTableIter iter; + Request *r; + GError *error; + + error = g_error_new_literal (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_AGENT_CANCELED, + "Canceled by NetworkManager"); + + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &r)) { + /* Only care about GetSecrets requests here */ + if (r->get_callback == NULL) + continue; + + /* Cancel any matching GetSecrets call */ + if ( g_strcmp0 (r->path, connection_path) == 0 + && g_strcmp0 (r->setting_name, setting_name) == 0) { + /* cancel outstanding keyring operations */ + g_cancellable_cancel (r->cancellable); + + r->get_callback (NM_SECRET_AGENT_OLD (r->agent), r->connection, NULL, error, r->callback_data); + g_hash_table_iter_remove (&iter); + g_signal_emit (r->agent, signals[CANCEL_SECRETS], 0, GUINT_TO_POINTER (r->id)); + } + } + + g_error_free (error); +} + +/*******************************************************/ + +static void +save_request_try_complete (Request *r) +{ + /* Only call the SaveSecrets callback and free the request when all the + * secrets have been saved to the keyring. + */ + if (r->keyring_calls == 0) { + if (!g_cancellable_is_cancelled (r->cancellable)) + r->save_callback (NM_SECRET_AGENT_OLD (r->agent), r->connection, NULL, r->callback_data); + request_free (r); + } +} + +static void +save_secret_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + secret_password_store_finish (result, NULL); + save_request_try_complete (user_data); +} + + + +static GHashTable * +_create_keyring_add_attr_list (NMConnection *connection, + const char *setting_name, + const char *setting_key, + char **out_display_name) +{ + const char *connection_id, *connection_uuid; + + g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (setting_name != NULL, NULL); + g_return_val_if_fail (setting_key != NULL, NULL); + + connection_uuid = nm_connection_get_uuid (connection); + g_assert (connection_uuid); + connection_id = nm_connection_get_id (connection); + g_assert (connection_id); + + if (out_display_name) { + *out_display_name = g_strdup_printf ("Network secret for %s/%s/%s", + connection_id, + setting_name, + setting_key); + } + + return secret_attributes_build (&network_manager_secret_schema, + KEYRING_UUID_TAG, connection_uuid, + KEYRING_SN_TAG, setting_name, + KEYRING_SK_TAG, setting_key, + NULL); +} + +static void +save_one_secret (Request *r, + NMSetting *setting, + const char *key, + const char *secret, + const char *display_name) +{ + GHashTable *attrs; + char *alt_display_name = NULL; + const char *setting_name; + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + /* Don't system-owned or always-ask secrets */ + if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL)) + return; + if (secret_flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) + return; + + setting_name = nm_setting_get_name (setting); + g_assert (setting_name); + + attrs = _create_keyring_add_attr_list (r->connection, + setting_name, + key, + display_name ? NULL : &alt_display_name); + g_assert (attrs); + + secret_password_storev (&network_manager_secret_schema, attrs, NULL, + display_name ? display_name : alt_display_name, secret, + r->cancellable, save_secret_cb, r); + r->keyring_calls++; + + g_hash_table_unref (attrs); + g_free (alt_display_name); +} + +static void +vpn_secret_iter_cb (const char *key, const char *secret, gpointer user_data) +{ + Request *r = user_data; + NMSetting *setting; + const char *service_name, *id; + char *display_name; + + if (secret && strlen (secret)) { + setting = nm_connection_get_setting (r->connection, NM_TYPE_SETTING_VPN); + g_assert (setting); + service_name = nm_setting_vpn_get_service_type (NM_SETTING_VPN (setting)); + g_assert (service_name); + id = nm_connection_get_id (r->connection); + g_assert (id); + + display_name = g_strdup_printf ("VPN %s secret for %s/%s/" NM_SETTING_VPN_SETTING_NAME, + key, + id, + service_name); + save_one_secret (r, setting, key, secret, display_name); + g_free (display_name); + } +} + +static void +write_one_secret_to_keyring (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) +{ + Request *r = user_data; + GType type = G_VALUE_TYPE (value); + const char *secret; + + /* Non-secrets obviously don't get saved in the keyring */ + if (!(flags & NM_SETTING_PARAM_SECRET)) + return; + + if (NM_IS_SETTING_VPN (setting) && (g_strcmp0 (key, NM_SETTING_VPN_SECRETS) == 0)) { + g_return_if_fail (type == G_TYPE_HASH_TABLE); + + /* Process VPN secrets specially since it's a hash of secrets, not just one */ + nm_setting_vpn_foreach_secret (NM_SETTING_VPN (setting), vpn_secret_iter_cb, r); + } else { + /* FIXME: password-raw is not string */ + if (!g_strcmp0 (key, NM_SETTING_802_1X_PASSWORD_RAW)) + return; + g_return_if_fail (type == G_TYPE_STRING); + secret = g_value_get_string (value); + if (secret && strlen (secret)) + save_one_secret (r, setting, key, secret, NULL); + } +} + +static void +save_delete_cb (NMSecretAgentOld *agent, + NMConnection *connection, + GError *error, + gpointer user_data) +{ + Request *r = user_data; + + /* Ignore errors; now save all new secrets */ + nm_connection_for_each_setting_value (connection, write_one_secret_to_keyring, r); + + /* If no secrets actually got saved there may be nothing to do so + * try to complete the request here. If there were secrets to save the + * request will get completed when those keyring calls return. + */ + save_request_try_complete (r); +} + +static void +save_secrets (NMSecretAgentOld *agent, + NMConnection *connection, + const char *connection_path, + NMSecretAgentOldSaveSecretsFunc callback, + gpointer callback_data) +{ + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent); + Request *r; + + r = request_new (agent, connection, connection_path, NULL, NULL, FALSE, NULL, callback, NULL, callback_data); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r); + + g_message("save secret ........................"); + /* First delete any existing items in the keyring */ + nm_secret_agent_old_delete_secrets (agent, connection, save_delete_cb, r); +} + +/*******************************************************/ + +static void +delete_find_items_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + Request *r = user_data; + GError *secret_error = NULL; + GError *error = NULL; + + r->keyring_calls--; + if (g_cancellable_is_cancelled (r->cancellable)) { + /* Callback already called by NM or dispose */ + request_free (r); + return; + } + + secret_password_clear_finish (result, &secret_error); + if (secret_error != NULL) { + error = g_error_new (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "The request could not be completed (%s)", + secret_error->message); + g_error_free (secret_error); + } + + r->delete_callback (r->agent, r->connection, error, r->callback_data); + request_free (r); +} + +static void +delete_secrets (NMSecretAgentOld *agent, + NMConnection *connection, + const char *connection_path, + NMSecretAgentOldDeleteSecretsFunc callback, + gpointer callback_data) +{ + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (agent); + Request *r; + NMSettingConnection *s_con; + const char *uuid; + + r = request_new (agent, connection, connection_path, NULL, NULL, FALSE, NULL, NULL, callback, callback_data); + g_hash_table_insert (priv->requests, GUINT_TO_POINTER (r->id), r); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + uuid = nm_setting_connection_get_uuid (s_con); + g_assert (uuid); + + secret_password_clear (&network_manager_secret_schema, r->cancellable, + delete_find_items_cb, r, + KEYRING_UUID_TAG, uuid, + NULL); + r->keyring_calls++; +} + +void +applet_agent_handle_vpn_only (AppletAgent *agent, gboolean vpn_only) +{ + g_return_if_fail (agent != NULL); + g_return_if_fail (APPLET_IS_AGENT (agent)); + + APPLET_AGENT_GET_PRIVATE (agent)->vpn_only = vpn_only; +} + +/*******************************************************/ + +AppletAgent * +applet_agent_new (GError **error) +{ + AppletAgent *agent; + + agent = g_object_new (APPLET_TYPE_AGENT, + NM_SECRET_AGENT_OLD_IDENTIFIER, "org.freedesktop.nm-applet", + NM_SECRET_AGENT_OLD_CAPABILITIES, NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, + NULL); + if (!g_initable_init (G_INITABLE (agent), NULL, error)) { + g_object_unref (agent); + return NULL; + } + + return agent; +} + +static void +applet_agent_init (AppletAgent *self) +{ + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (self); + + priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static void +dispose (GObject *object) +{ + AppletAgent *self = APPLET_AGENT (object); + AppletAgentPrivate *priv = APPLET_AGENT_GET_PRIVATE (self); + + if (!priv->disposed) { + GHashTableIter iter; + Request *r; + + /* Mark any outstanding requests as canceled */ + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &r)) + g_cancellable_cancel (r->cancellable); + + g_hash_table_destroy (priv->requests); + priv->disposed = TRUE; + } + + G_OBJECT_CLASS (applet_agent_parent_class)->dispose (object); +} + +static void applet_agent_class_init (AppletAgentClass *agent_class) +{ + g_message("applet_agent_class_init........................"); + GObjectClass *object_class = G_OBJECT_CLASS (agent_class); + NMSecretAgentOldClass *parent_class = NM_SECRET_AGENT_OLD_CLASS (agent_class); + + g_type_class_add_private (agent_class, sizeof (AppletAgentPrivate)); + + /* virtual methods */ + object_class->dispose = dispose; + parent_class->get_secrets = get_secrets; + parent_class->cancel_get_secrets = cancel_get_secrets; + parent_class->save_secrets = save_secrets; + parent_class->delete_secrets = delete_secrets; + + /* Signals */ + signals[GET_SECRETS] = + g_signal_new (APPLET_AGENT_GET_SECRETS, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (AppletAgentClass, get_secrets), + NULL, NULL, NULL, + G_TYPE_NONE, 7, + G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_POINTER); + + signals[CANCEL_SECRETS] = + g_signal_new (APPLET_AGENT_CANCEL_SECRETS, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (AppletAgentClass, cancel_secrets), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} + diff --git a/src/backend/dbus-interface/kylinagent.h b/src/backend/dbus-interface/kylinagent.h new file mode 100644 index 00000000..8b11f044 --- /dev/null +++ b/src/backend/dbus-interface/kylinagent.h @@ -0,0 +1,79 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef __KYLINNMANGENT_H__ +#define __KYLINNMANGENT_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include +#include +#include +#include + +#define APPLET_TYPE_AGENT (applet_agent_get_type ()) +#define APPLET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APPLET_TYPE_AGENT, AppletAgent)) +#define APPLET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APPLET_TYPE_AGENT, AppletAgentClass)) +#define APPLET_IS_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APPLET_TYPE_AGENT)) +#define APPLET_IS_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APPLET_TYPE_AGENT)) +#define APPLET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APPLET_TYPE_AGENT, AppletAgentClass)) + +#define APPLET_AGENT_GET_SECRETS "get-secrets" +#define APPLET_AGENT_CANCEL_SECRETS "cancel-secrets" + +typedef struct { + NMSecretAgentOld parent; +} AppletAgent; + +typedef void (*AppletAgentSecretsCallback) (AppletAgent *self, + GVariant *secrets, + GError *error, + gpointer user_data); + +typedef struct { + NMSecretAgentOldClass parent_class; + + void (*get_secrets) (AppletAgent *self, + void *request_id, + NMConnection *connection, + const char *setting_name, + const char **hints, + guint32 flags, + AppletAgentSecretsCallback callback, + gpointer callback_data); + + void (*cancel_secrets) (AppletAgent *self, + void *request_id); +} AppletAgentClass; + + +GType applet_agent_get_type (void) G_GNUC_CONST; + +AppletAgent *applet_agent_new (GError **error); + +void applet_agent_handle_vpn_only (AppletAgent *agent, gboolean vpn_only); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/backend/dbus-interface/kylinagentinterface.c b/src/backend/dbus-interface/kylinagentinterface.c new file mode 100644 index 00000000..35a7d41a --- /dev/null +++ b/src/backend/dbus-interface/kylinagentinterface.c @@ -0,0 +1,428 @@ +#include "kylinagentinterface.h" +#include "kylinagent.h" +#include "kylinvpnrequest.h" + +#include +#include + +GSList * secrets_reqs; +#if 0 +typedef struct _SecretsRequest SecretsRequest; +typedef void (*SecretsRequestFreeFunc) (SecretsRequest *req); + +struct _SecretsRequest { + size_t totsize; + gpointer reqid; + char *setting_name; + char **hints; + guint32 flags; + AppletAgent *agent; + AppletAgentSecretsCallback callback; + gpointer callback_data; + + NMConnection *connection; + + /* Class-specific stuff */ + SecretsRequestFreeFunc free_func; +}; +#endif +typedef struct { + SecretsRequest req; + GtkWidget *dialog; +} NMWifiInfo; + +static AppletAgent * kylinAgent = NULL; + +void +applet_secrets_request_set_free_func (SecretsRequest *req, + SecretsRequestFreeFunc free_func) +{ + req->free_func = free_func; +} + +static void +show_ignore_focus_stealing_prevention (GtkWidget *widget) +{ + gtk_widget_realize (widget); + gtk_widget_show (widget); + gtk_window_present (GTK_WINDOW (widget)); +} + +static GVariant * +remove_unwanted_secrets (GVariant *secrets, gboolean keep_8021X) +{ + GVariant *copy, *setting_dict; + const char *setting_name; + GVariantBuilder conn_builder; + GVariantIter conn_iter; + + g_variant_builder_init (&conn_builder, NM_VARIANT_TYPE_CONNECTION); + g_variant_iter_init (&conn_iter, secrets); + while (g_variant_iter_next (&conn_iter, "{&s@a{sv}}", &setting_name, &setting_dict)) { + if ( !strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) + || (!strcmp (setting_name, NM_SETTING_802_1X_SETTING_NAME) && keep_8021X)) + g_variant_builder_add (&conn_builder, "{s@a{sv}}", setting_name, setting_dict); + + g_variant_unref (setting_dict); + } + copy = g_variant_builder_end (&conn_builder); + g_variant_unref (secrets); + + return copy; +} + +static void +free_wifi_info (SecretsRequest *req) +{ + NMWifiInfo *info = (NMWifiInfo *) req; + + if (info->dialog) { + gtk_widget_hide (info->dialog); + gtk_widget_destroy (info->dialog); + info->dialog = NULL; + } +} + + +void +applet_secrets_request_free (SecretsRequest *req) +{ + g_return_if_fail (req != NULL); + + if (req->free_func) + req->free_func (req); + + secrets_reqs = g_slist_remove (secrets_reqs, req); + + g_object_unref (req->connection); + g_free (req->setting_name); + g_strfreev (req->hints); + memset (req, 0, req->totsize); + g_free (req); +} + +void +applet_secrets_request_complete (SecretsRequest *req, + GVariant *settings, + GError *error) +{ + req->callback (req->agent, error ? NULL : settings, error, req->callback_data); +} + +static void +get_secrets_dialog_response_cb (GtkDialog *foo, + gint response, + gpointer user_data) +{ + SecretsRequest *req = user_data; + NMWifiInfo *info = (NMWifiInfo *) req; + NMAWifiDialog *dialog = NMA_WIFI_DIALOG (info->dialog); + NMConnection *connection = NULL; + NMSettingWirelessSecurity *s_wireless_sec; + GVariant *secrets = NULL; + const char *key_mgmt, *auth_alg; + gboolean keep_8021X = FALSE; + GError *error = NULL; + + if (response != GTK_RESPONSE_OK) { + g_set_error (&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + "%s.%d (%s): canceled", + __FILE__, __LINE__, __func__); + goto done; + } + + connection = nma_wifi_dialog_get_connection (dialog, NULL, NULL); + if (!connection) { + g_set_error (&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "%s.%d (%s): couldn't get connection from Wi-Fi dialog.", + __FILE__, __LINE__, __func__); + goto done; + } + + /* Second-guess which setting NM wants secrets for. */ + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + if (!s_wireless_sec) { + g_set_error (&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "%s.%d (%s): requested setting '802-11-wireless-security'" + " didn't exist in the connection.", + __FILE__, __LINE__, __func__); + goto done; /* Unencrypted */ + } + + secrets = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (!secrets) { + g_set_error (&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "%s.%d (%s): failed to hash connection '%s'.", + __FILE__, __LINE__, __func__, nm_connection_get_id (connection)); + goto done; + } + /* If the user chose an 802.1x-based auth method, return 802.1x secrets, + * not wireless secrets. Can happen with Dynamic WEP, because NM doesn't + * know the capabilities of the AP (since Dynamic WEP APs don't broadcast + * beacons), and therefore defaults to requesting WEP secrets from the + * wireless-security setting, not the 802.1x setting. + */ + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); + if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) { + /* LEAP secrets aren't in the 802.1x setting */ + auth_alg = nm_setting_wireless_security_get_auth_alg (s_wireless_sec); + if (!auth_alg || strcmp (auth_alg, "leap")) { + NMSetting8021x *s_8021x; + + s_8021x = nm_connection_get_setting_802_1x (connection); + if (!s_8021x) { + g_set_error (&error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, + "%s.%d (%s): requested setting '802-1x' didn't" + " exist in the connection.", + __FILE__, __LINE__, __func__); + goto done; + } + keep_8021X = TRUE; + } + } + + /* Remove all not-relevant secrets (inner dicts) */ + secrets = remove_unwanted_secrets (secrets, keep_8021X); + g_variant_take_ref (secrets); + +done: + applet_secrets_request_complete (req, secrets, error); + applet_secrets_request_free (req); + + if (secrets) + g_variant_unref (secrets); + if (connection) + nm_connection_clear_secrets (connection); +} + +static gboolean +wifi_get_secrets (SecretsRequest *req, GError **error) +{ + NMWifiInfo *info = (NMWifiInfo *) req; + + g_return_val_if_fail (!info->dialog, FALSE); + +#if GTK_CHECK_VERSION(3,90,0) + gtk_init (); +#else + int argc = 0; + char ***argv = NULL; + gtk_init (&argc, &argv); +#endif + + NMClient *nm_client = nm_client_new (NULL, NULL); + if (!nm_client) { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "%s.%d (%s): create nm client failed.", + __FILE__, __LINE__, __func__); + g_warning ("create nm client failed"); + goto l_out; + } + + + info->dialog = nma_wifi_dialog_new_for_secrets (nm_client, + req->connection, + req->setting_name, + (const char *const*) req->hints); + + if (info->dialog) { + applet_secrets_request_set_free_func (req, free_wifi_info); + g_signal_connect (info->dialog, "response", + G_CALLBACK (get_secrets_dialog_response_cb), + info); + show_ignore_focus_stealing_prevention (info->dialog); + } else { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "%s.%d (%s): couldn't display secrets UI", + __FILE__, __LINE__, __func__); + } + + g_clear_object(&nm_client); + +l_out: + return !!info->dialog; + //return 0; +} + +static SecretsRequest * +applet_secrets_request_new (size_t totsize, + NMConnection *connection, + gpointer request_id, + const char *setting_name, + const char **hints, + guint32 flags, + AppletAgentSecretsCallback callback, + gpointer callback_data, + AppletAgent *agent) +{ + SecretsRequest *req; + + g_return_val_if_fail (totsize >= sizeof (SecretsRequest), NULL); + g_return_val_if_fail (connection != NULL, NULL); + + req = g_malloc0 (totsize); + req->totsize = totsize; + req->connection = g_object_ref (connection); + req->reqid = request_id; + req->setting_name = g_strdup (setting_name); + req->hints = g_strdupv ((char **) hints); + req->flags = flags; + req->callback = callback; + req->callback_data = callback_data; + req->agent = agent; + return req; +} + +static void +get_existing_secrets_cb (NMSecretAgentOld *agent, + NMConnection *connection, + GVariant *secrets, + GError *secrets_error, + gpointer user_data) +{ + SecretsRequest *req = user_data; + //NMADeviceClass *dclass; + GError *error = NULL; + + if (secrets) + nm_connection_update_secrets (connection, req->setting_name, secrets, NULL); + else + nm_connection_clear_secrets (connection); + + /* Let the device class handle secrets */ + if (!wifi_get_secrets(req, &error)) { + g_warning ("%s:%d - %s", __func__, __LINE__, error ? error->message : "(unknown)"); + applet_secrets_request_complete (req, NULL, error); + applet_secrets_request_free (req); + g_error_free (error); + } + /* Otherwise success; wait for the secrets callback */ +} + + +static void +applet_agent_get_secrets_cb (AppletAgent *agent, + gpointer request_id, + NMConnection *connection, + const char *setting_name, + const char **hints, + guint32 flags, + AppletAgentSecretsCallback callback, + gpointer callback_data, + gpointer user_data) +{ + NMSettingConnection *s_con; + GError *error = NULL; + SecretsRequest *req = NULL; + + s_con = nm_connection_get_setting_connection (connection); + g_return_if_fail (s_con != NULL); + + /* VPN secrets get handled a bit differently */ + if (!strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_VPN_SETTING_NAME)) { + req = applet_secrets_request_new (applet_vpn_request_get_secrets_size (), + connection, + request_id, + setting_name, + hints, + flags, + callback, + callback_data, + agent); + if (!applet_vpn_request_get_secrets (req, &error)) + goto error; + + secrets_reqs = g_slist_prepend (secrets_reqs, req); + return; + } + + + req = applet_secrets_request_new (sizeof (NMWifiInfo), + connection, + request_id, + setting_name, + hints, + flags, + callback, + callback_data, + agent); + secrets_reqs = g_slist_prepend (secrets_reqs, req); + + /* Get existing secrets, if any */ + nm_secret_agent_old_get_secrets (NM_SECRET_AGENT_OLD (agent), + connection, + setting_name, + hints, + NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE, + get_existing_secrets_cb, + req); + return; + +error: + g_warning ("%s", error->message); + callback (agent, NULL, error, callback_data); + g_error_free (error); + + if (req) + applet_secrets_request_free (req); +} + +static void +applet_agent_cancel_secrets_cb (AppletAgent *agent, + gpointer request_id, + gpointer user_data) +{ + GSList *iter, *next; + + for (iter = secrets_reqs; iter; iter = next) { + SecretsRequest *req = iter->data; + + next = g_slist_next (iter); + + if (req->reqid == request_id) { + /* cancel and free this password request */ + applet_secrets_request_free (req); + break; + } + } +} + +void agent_init() +{ + if (NULL != kylinAgent) { + return; + } + GError *error = NULL; + kylinAgent = applet_agent_new (&error); + + g_signal_connect (kylinAgent, APPLET_AGENT_GET_SECRETS, + G_CALLBACK (applet_agent_get_secrets_cb), NULL); + g_signal_connect (kylinAgent, APPLET_AGENT_CANCEL_SECRETS, + G_CALLBACK (applet_agent_cancel_secrets_cb), NULL); + + + return; +} + +void agent_clear() +{ + if (NULL == kylinAgent) { + return; + } + g_clear_object (&kylinAgent); + kylinAgent = NULL; +} diff --git a/src/backend/dbus-interface/kylinagentinterface.h b/src/backend/dbus-interface/kylinagentinterface.h new file mode 100644 index 00000000..972033e7 --- /dev/null +++ b/src/backend/dbus-interface/kylinagentinterface.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef __KYLINAGENTINTERFACE_H__ +#define __KYLINAGENTINTERFACE_H__ +#ifdef __cplusplus +extern "C"{ +void agent_init(); +void agent_clear(); +} +#endif + +#endif // NMAGENT_H diff --git a/src/backend/dbus-interface/kylinapconnectitem.cpp b/src/backend/dbus-interface/kylinapconnectitem.cpp new file mode 100644 index 00000000..ab3052d8 --- /dev/null +++ b/src/backend/dbus-interface/kylinapconnectitem.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kylinapconnectitem.h" + +KyApConnectItem::KyApConnectItem(QObject *parent) : QObject(parent) +{ + m_connectName = ""; + m_connectUuid = ""; + m_connectSsid = ""; + m_ifaceName = ""; + m_password = ""; + m_band = ""; + m_isActivated = false; +} + + +KyApConnectItem::~KyApConnectItem() +{ + +} diff --git a/src/backend/dbus-interface/kylinapconnectitem.h b/src/backend/dbus-interface/kylinapconnectitem.h new file mode 100644 index 00000000..63f69b87 --- /dev/null +++ b/src/backend/dbus-interface/kylinapconnectitem.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINAPCONNECTITEM_H +#define KYLINAPCONNECTITEM_H + +#include + +class KyApConnectItem : public QObject +{ + Q_OBJECT + +public: + explicit KyApConnectItem(QObject *parent = nullptr); + ~KyApConnectItem(); + +public: + QString m_connectName; + QString m_connectSsid; + QString m_connectUuid; + QString m_ifaceName; + QString m_password; + QString m_band; + bool m_isActivated; + +}; + +#endif // KYLINAPCONNECTITEM_H diff --git a/src/backend/dbus-interface/kylinbluetoothconnectitem.cpp b/src/backend/dbus-interface/kylinbluetoothconnectitem.cpp new file mode 100644 index 00000000..dd9dd643 --- /dev/null +++ b/src/backend/dbus-interface/kylinbluetoothconnectitem.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kylinbluetoothconnectitem.h" + + +KyBluetoothConnectItem::KyBluetoothConnectItem(QObject *parent) : QObject(parent) +{ + m_connectName = ""; + m_connectUuid = ""; + + m_deviceAddress = ""; + + m_ipv4Address = ""; + m_ipv6Address = ""; + + m_state = NetworkManager::ActiveConnection::State::Deactivated; +} + +KyBluetoothConnectItem::~KyBluetoothConnectItem() +{ + m_connectName = ""; + m_connectUuid = ""; + + m_deviceAddress = ""; + + m_ipv4Address = ""; + m_ipv6Address = ""; + + m_state = NetworkManager::ActiveConnection::State::Deactivated; +} + diff --git a/src/backend/dbus-interface/kylinbluetoothconnectitem.h b/src/backend/dbus-interface/kylinbluetoothconnectitem.h new file mode 100644 index 00000000..0b485d0f --- /dev/null +++ b/src/backend/dbus-interface/kylinbluetoothconnectitem.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINBLUETOOTHCONNECTITEM_H +#define KYLINBLUETOOTHCONNECTITEM_H + +#include +#include +#include +#include + +class KyBluetoothConnectItem : public QObject +{ + Q_OBJECT +public: + explicit KyBluetoothConnectItem(QObject *parent = nullptr); + ~KyBluetoothConnectItem(); + +public: + void dumpInfo(); + +public: + QString m_connectName; + QString m_connectUuid; + + QString m_deviceAddress; + + QString m_ipv4Address; + QString m_ipv6Address; + + NetworkManager::ActiveConnection::State m_state; //deactive、activing and actived + //QString m_itemType; //activeconnect or connect + +}; + +#endif // KYLINBLUETOOTHCONNECTITEM_H diff --git a/src/backend/dbus-interface/kylinconnectitem.cpp b/src/backend/dbus-interface/kylinconnectitem.cpp new file mode 100644 index 00000000..27b573e5 --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectitem.cpp @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kylinconnectitem.h" + +KyConnectItem::KyConnectItem(QObject *parent) : QObject(parent) +{ + m_connectName = ""; + m_connectUuid = ""; + m_connectPath = ""; + + m_ifaceName = ""; + + m_connectState = NetworkManager::ActiveConnection::State::Unknown; //deactive、activing and actived + m_itemType = NetworkManager::ConnectionSettings::ConnectionType::Unknown; +} + +KyConnectItem::~KyConnectItem() +{ + +} + +void KyConnectItem::setConnectUuid(QString uuid) +{ + m_connectUuid = uuid; +} + +void KyConnectItem::dumpInfo() +{ + qDebug()<<"wired connection item info:"; + qDebug()<<"connect name:"< +#include "kylinnetworkresourcemanager.h" + +class KyConnectItem : public QObject +{ + Q_OBJECT +public: + explicit KyConnectItem(QObject *parent = nullptr); + ~KyConnectItem(); + +public: + void dumpInfo(); + + void setConnectUuid(QString uuid); + +public: + QString m_connectName; + QString m_connectUuid; + QString m_connectPath; + + QString m_ifaceName; + + NetworkManager::ActiveConnection::State m_connectState; //deactive、activing and actived + + NetworkManager::ConnectionSettings::ConnectionType m_itemType; //wired or wireless vpn etc +}; + +#endif // KYLINWIREDCONNECTITEM_H diff --git a/src/backend/dbus-interface/kylinconnectoperation.cpp b/src/backend/dbus-interface/kylinconnectoperation.cpp new file mode 100644 index 00000000..023c613c --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectoperation.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include + +KyConnectOperation::KyConnectOperation(QObject *parent) : QObject(parent) +{ + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); +} + +KyConnectOperation::~KyConnectOperation() +{ + m_networkResourceInstance = nullptr; +} + +void KyConnectOperation::ipv4SettingSet( + NetworkManager::Ipv4Setting::Ptr &ipv4Setting, + const KyConnectSetting &connectSettingsInfo) +{ + ipv4Setting->setInitialized(true); + ipv4Setting->setDns(connectSettingsInfo.m_ipv4Dns); + + if (CONFIG_IP_DHCP == connectSettingsInfo.m_ipv4ConfigIpType) { + ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Automatic); + return; + } else { + ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Manual); + } + ipv4Setting->setAddresses(connectSettingsInfo.m_ipv4Address); + + return; +} +void KyConnectOperation::ipv6SettingSet( + NetworkManager::Ipv6Setting::Ptr &ipv6Setting, + const KyConnectSetting &connectSettingsInfo) +{ + ipv6Setting->setInitialized(true); + ipv6Setting->setDns(connectSettingsInfo.m_ipv6Dns); + + if (CONFIG_IP_DHCP == connectSettingsInfo.m_ipv6ConfigIpType) { + ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Automatic); + ipv6Setting->setPrivacy(NetworkManager::Ipv6Setting::Disabled); + return; + } + + ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Manual); + ipv6Setting->setAddresses(connectSettingsInfo.m_ipv6Address); + + return ; +} + +void KyConnectOperation::connectSettingSet( + NetworkManager::ConnectionSettings::Ptr connectionSettings, + const KyConnectSetting &connectSettingsInfo) +{ + connectionSettings->setId(connectSettingsInfo.m_connectName); + connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + connectionSettings->setAutoconnect(true); + connectionSettings->setAutoconnectPriority(0); + if (!connectSettingsInfo.m_ifaceName.isEmpty()) { + connectionSettings->setInterfaceName(connectSettingsInfo.m_ifaceName); + } + return; +} + +void KyConnectOperation::setAutoConnect(NetworkManager::ConnectionSettings::Ptr &connectSetting, + bool bAutoConnect) +{ + if (connectSetting.isNull()) { + return; + } + + connectSetting->setAutoconnect(bAutoConnect); + + return; +} + +void KyConnectOperation::createConnect(KyConnectSetting &connectSettingsInfo) +{ + qDebug()<<"create connect need to do"; + return; +} + +void KyConnectOperation::updateConnect(NetworkManager::ConnectionSettings::Ptr connectionSettings, const KyConnectSetting &connectSettingsInfo) +{ + qDebug()<<"update connect"<uuid(); + + NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + ipv4SettingSet(ipv4Setting, connectSettingsInfo); + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + ipv6SettingSet(ipv6Setting, connectSettingsInfo); + +// NetworkManager::WiredSetting::Ptr wiredSetting = connectionSettings->setting(NetworkManager::Setting::Wired).dynamicCast(); +// wiredSetting->setInitialized(true); + + return ; +} + +void KyConnectOperation::deleteConnect(const QString &connectUuid) +{ + qDebug()<<"delete connect uuid " << connectUuid; + + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(connectUuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + connectUuid; + qWarning()<remove(); + + return ; +} + +void KyConnectOperation::activateConnection(const QString connectUuid, const QString deviceName) +{ + QString connectPath = ""; + QString deviceIdentifier = ""; + QString connectName = ""; + QString specificObject = ""; + NetworkManager::Connection::Ptr connectPtr = nullptr; + + qDebug()<<"it will activate connect"<settings()->connectionType()) { + QString errorMessage = tr("the connect type is") + + connectPtr->settings()->connectionType() + + tr(", but it is not wired"); + qWarning()<path(); + connectName = connectPtr->name(); +// deviceName = connectPtr->settings()->interfaceName(); + +// for (auto const & dev : m_networkResourceInstance->m_devices) { +// for (auto const & dev_conn : dev->availableConnections()) { +// if (dev_conn == connectPtr) { +// deviceIdentifier = dev->uni(); +// deviceName = dev->interfaceName(); +// break; +// } +// } +// } + + auto dev = m_networkResourceInstance->findDeviceInterface(deviceName); + if (!dev.isNull()) { + deviceIdentifier = dev->uni(); + } + + + if (deviceIdentifier.isEmpty()) { + QString errorMessage = tr("device Identifier is empty, its name") + deviceName; + qWarning() << errorMessage; + Q_EMIT activateConnectionError(errorMessage); + return ; + } + + qDebug() <<"active wired connect: path "<< connectPath + << "device identify " << deviceIdentifier + << "connect name " << connectName + << "device name" << deviceName + << "specific parameter"<< specificObject; + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::activateConnection(connectPath, deviceIdentifier, specificObject), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this, connectName, deviceName] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("activate connection failed: ") + watcher->error().message(); + qWarning()<activateConnectionError(errorMessage); + } else { + qWarning()<<"active wired connect complete."; + } + + watcher->deleteLater(); + }); + + return ; +} + +void KyConnectOperation::deactivateConnection(const QString activeConnectName, const QString &activeConnectUuid) +{ + NetworkManager::ActiveConnection::Ptr activateConnectPtr = nullptr; + + qDebug()<<"deactivetate connect name"<getActiveConnect(activeConnectUuid); + if (nullptr == activateConnectPtr) { + QString errorMessage = tr("it can not find the activate connect") + + activeConnectName + tr("uuid") + activeConnectUuid; + qWarning()<path(); + QDBusPendingReply<> reply = NetworkManager::deactivateConnection(activateConnectPtr->path()); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, &QDBusPendingCallWatcher::finished, [this, activateConnectPtr] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("deactivation of connection") + + activateConnectPtr->connection()->name() + tr("failed:") + + watcher->error().message(); + + qWarning()<deactivateConnectionError(errorMessage); + } else { + qWarning() << "deactive connect operation finished" << activateConnectPtr->connection()->name(); + } + watcher->deleteLater(); + }); + + return; +} diff --git a/src/backend/dbus-interface/kylinconnectoperation.h b/src/backend/dbus-interface/kylinconnectoperation.h new file mode 100644 index 00000000..8fae0bc2 --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectoperation.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINCONNECTOPERATION_H +#define KYLINCONNECTOPERATION_H + +#include "kylinnetworkresourcemanager.h" +#include "kylinconnectsetting.h" + +class KyConnectOperation : public QObject +{ + Q_OBJECT +public: + explicit KyConnectOperation(QObject *parent = nullptr); + ~KyConnectOperation(); + +public: + void createConnect(KyConnectSetting &connectSettingsInfo); + void updateConnect(NetworkManager::ConnectionSettings::Ptr connectionSettings, const KyConnectSetting &connectSettingsInfo); + void deleteConnect(const QString &connectUuid); + void activateConnection(const QString connectUuid, const QString deviceName); + void deactivateConnection(const QString activeConnectName, const QString &activeConnectUuid); + +public: + void connectSettingSet( + NetworkManager::ConnectionSettings::Ptr connectionSettings, + const KyConnectSetting &connectSettingsInfo); + void ipv4SettingSet(NetworkManager::Ipv4Setting::Ptr &ipv4Setting, + const KyConnectSetting &connectSettingsInfo); + void ipv6SettingSet(NetworkManager::Ipv6Setting::Ptr &ipv6Setting, + const KyConnectSetting &connectSettingsInfo); + void setAutoConnect(NetworkManager::ConnectionSettings::Ptr &connectSetting, + bool bAutoConnect); + inline void errorProcess(QString errorMessage); + +Q_SIGNALS: + void createConnectionError(QString errorMessage); + void updateConnectionError(QString errorMessage); + void deleteConnectionError(QString errorMessage); + void activateConnectionError(QString errorMessage); + void deactivateConnectionError(QString errorMessage); + +protected: + KyNetworkResourceManager *m_networkResourceInstance = nullptr; +}; + +#endif // KYLINCONNECTOPERATION_H diff --git a/src/backend/dbus-interface/kylinconnectresource.cpp b/src/backend/dbus-interface/kylinconnectresource.cpp new file mode 100644 index 00000000..487cb8f6 --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectresource.cpp @@ -0,0 +1,827 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kylinconnectresource.h" +#include "kywirelessconnectoperation.h" +#include "kylinutil.h" + +#include +#include +#include +#include +#include + +const QString str2GBand = "2.4Ghz"; +const QString str5GBand = "5Ghz"; + +static bool subLanListSort(const KyConnectItem* info1, const KyConnectItem* info2) +{ + QString name1 = info1->m_connectName; + QString name2 = info2->m_connectName; + bool result = true; + if (QString::compare(name1, name2, Qt::CaseInsensitive) > 0) { + result = false; + } + return result; +} + +static void lanListSort(QList &list) +{ + qSort(list.begin(), list.end(), subLanListSort); +} + +KyConnectResourse::KyConnectResourse(QObject *parent) : QObject(parent) +{ + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionAdd, this, &KyConnectResourse::connectionAdd); + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionRemove, this, &KyConnectResourse::connectionRemove); + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionUpdate, this, &KyConnectResourse::connectionUpdate); + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectivityChanged, this, &KyConnectResourse::connectivityChanged); +} + +KyConnectResourse::~KyConnectResourse() +{ + m_networkResourceInstance = nullptr; +} + +KyConnectItem *KyConnectResourse::getConnectionItem(NetworkManager::Connection::Ptr connectPtr, QString devName) +{ + if (nullptr == connectPtr) { + qWarning()<<"[KyConnectResourse]"<<"the connect is empty"; + return nullptr; + } + + KyConnectItem *connectionItem = new KyConnectItem(); + connectionItem->m_connectName = connectPtr->name(); + connectionItem->m_connectUuid = connectPtr->uuid(); + connectionItem->m_connectPath = connectPtr->path(); + + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + connectionItem->m_ifaceName = settingPtr->interfaceName(); + connectionItem->m_itemType = settingPtr->connectionType(); + + if (m_networkResourceInstance->isActivatingConnection(connectPtr->uuid())) { + if (connectionItem->m_ifaceName == "" && devName != "") { + if (isActiveDevice(connectionItem->m_connectUuid, devName)) { + connectionItem->m_connectState = NetworkManager::ActiveConnection::State::Activating; + } else { + connectionItem->m_connectState = NetworkManager::ActiveConnection::State::Deactivated; + } + } else { + connectionItem->m_connectState = NetworkManager::ActiveConnection::State::Activating; + } + } else { + connectionItem->m_connectState = NetworkManager::ActiveConnection::State::Deactivated; + } + return connectionItem; +} + +bool KyConnectResourse::isActiveDevice(QString conUuid, QString devName) +{ + QString deviceName = ""; + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = + m_networkResourceInstance->getActiveConnect(conUuid); + + if (nullptr == activeConnectPtr) { + qWarning()<< "[KyConnectResourse]" <<"it can not find activating connect "<< conUuid; + return false; + } + + QStringList interfaces = activeConnectPtr->devices(); + if (interfaces.isEmpty()) { + qWarning()<< "[KyConnectResourse]" << "get device of activing connection failed."; + return false; + } + + QString ifaceUni = ""; + for (int index=0; index < interfaces.size(); index++) { + ifaceUni = interfaces.at(index); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + deviceName = devicePtr->interfaceName(); + if (deviceName == devName) { + return true; + } + } + return false; +} + +KyConnectItem * KyConnectResourse::getConnectionItemByUuid(QString connectUuid) +{ + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(connectUuid); + + if (nullptr == connectPtr) { + qWarning()<< "[KyConnectResourse]" <<"get connect failed, connect uuid"<isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + return nullptr; + } + + KyConnectItem *connectItem = getConnectionItem(connectPtr, ""); + if (nullptr != connectItem) { + //connectItem->dumpInfo(); + return connectItem; + } + + return nullptr; +} + +KyConnectItem * KyConnectResourse::getConnectionItemByUuidWithoutActivateChecking(QString connectUuid) +{ + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(connectUuid); + + if (nullptr == connectPtr) { + qWarning()<< "[KyConnectResourse]" <<"get connect failed, connect uuid"<dumpInfo(); + return connectItem; + } + + return nullptr; +} + +KyConnectItem * KyConnectResourse::getConnectionItemByUuid(QString connectUuid, QString deviceName) +{ + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(connectUuid); + + if (nullptr == connectPtr) { + qWarning()<< "[KyConnectResourse]" <<"get connect failed, connect uuid"<settings()->interfaceName(); + if (!connectInterface.isEmpty() + && deviceName != connectInterface) { + qDebug()<<"[KyConnectResourse]" << "connect name:"<< connectPtr->name() + << "connect device name" << connectInterface; + return nullptr; + } + + if (m_networkResourceInstance->isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + return nullptr; + } + + KyConnectItem *connectItem = getConnectionItem(connectPtr, deviceName); + if (nullptr != connectItem) { + //connectItem->dumpInfo(); + return connectItem; + } + + return nullptr; +} + +void KyConnectResourse::getConnectionList(QString deviceName, + NetworkManager::ConnectionSettings::ConnectionType connectionType, + QList &connectItemList) +{ + NetworkManager::Connection::List connectList; + + qDebug()<<"[KyConnectResourse]"<<"get connections item, device" + <getConnectList(); + + if (connectList.empty()) { + qWarning()<<"[KyConnectResourse]"<<"get connection failed, the connect list is empty"; + return; + } + + NetworkManager::Connection::Ptr connectPtr = nullptr; + for (int index = 0; index < connectList.size(); index++) { + connectPtr = connectList.at(index); + if (connectPtr.isNull()) { + continue; + } + + if (connectionType != connectPtr->settings()->connectionType()) { + qDebug()<<"[KyConnectResourse]"<<"connect name:" << connectPtr->name() + <<"connect type:"<settings()->connectionType(); + continue; + } + + QString connectInterface = connectPtr->settings()->interfaceName(); + if (!connectInterface.isEmpty() + && deviceName != connectInterface) { + qDebug() << "[KyConnectResourse]" << "connect name:"<< connectPtr->name() + << "connect device name" << connectInterface; + continue; + } + + if (m_networkResourceInstance->isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + continue; + } + + KyConnectItem *connectItem = getConnectionItem(connectPtr, deviceName); + if (nullptr != connectItem) { + // connectItem->m_itemType = connectionType; + connectItemList << connectItem; + //connectItem->dumpInfo(); + } + + connectPtr = nullptr; + } + + if (connectItemList.size() > 1) { + lanListSort(connectItemList); + } + return; +} + +#if 0 +void KyConnectResourse::getWiredConnections(QList &wiredConnectItemList) +{ + int index = 0; + NetworkManager::Connection::List connectList; + + qDebug()<<"[KyConnectResourse]"<<"get wired connections"; + + connectList.clear(); + connectList = m_networkResourceInstance->getConnectList(); + + if (connectList.empty()) { + qWarning()<<"[KyConnectResourse]"<<"get wired connection failed, the connect list is empty"; + return; + } + + NetworkManager::Connection::Ptr connectPtr = nullptr; + for (index = 0; index < connectList.size(); index++) { + connectPtr = connectList.at(index); + if (NetworkManager::ConnectionSettings::ConnectionType::Wired + != connectPtr->settings()->connectionType()) { + qDebug()<<"[KyConnectResourse]"<<"connect name:" << connectPtr->name() + <<"connect type:"<settings()->connectionType(); + continue; + } + + if (m_networkResourceInstance->isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + continue; + } + + KyWiredConnectItem *connectItem = getWiredConnectItem(connectPtr); + if (nullptr != connectItem) { + wiredConnectItemList << connectItem; + connectItem->dumpInfo(); + } + + connectPtr = nullptr; + } + + return; +} + +KyWiredConnectItem *KyConnectResourse::getWiredConnectItem(NetworkManager::Connection::Ptr connectPtr) +{ + qDebug()<<"[KyConnectResourse]"<<"get connect item"; + + if (nullptr == connectPtr) { + qWarning()<<"[KyConnectResourse]"<<"the connect is empty"; + return nullptr; + } + + KyWiredConnectItem *wiredItem = new KyWiredConnectItem(); + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + + wiredItem->m_connectName = connectPtr->name(); + wiredItem->m_connectUuid = connectPtr->uuid(); + wiredItem->m_ifaceName = settingPtr->interfaceName(); + + getConnectIp(settingPtr, wiredItem->m_ipv4, wiredItem->m_ipv6); + + m_networkdevice->getWiredHardwareInfo(settingPtr->interfaceName(), wiredItem); + + wiredItem->m_state = NetworkManager::ActiveConnection::State::Deactivated; + //wiredItem->m_itemType; + + return wiredItem; +} + +#endif + +void KyConnectResourse::getConnectIp( + NetworkManager::ConnectionSettings::Ptr settingPtr, + QString &ipv4Address, + QString &ipv6Address) +{ + NetworkManager::Ipv4Setting::Ptr ipv4Setting = + settingPtr->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + if (NetworkManager::Ipv4Setting::Manual == ipv4Setting->method()) { + QList ipv4AddressList = ipv4Setting->addresses(); + NetworkManager::IpAddress settingIpv4Address = ipv4AddressList.at(0); + if (settingIpv4Address.isValid()) { + ipv4Address = settingIpv4Address.ip().toString(); + } else { + qWarning()<<"[KyConnectResourse]"<<"get connect ipv4 failed, ipv4Address is not valid"; + } + } else { + qWarning()<<"[KyConnectResourse]"<<"get connect ipv4 failed, ipv4 config with dhcp"; + } + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = settingPtr->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + if (nullptr !=ipv6Setting + && NetworkManager::Ipv4Setting::Manual == ipv6Setting->method()) { + QList ipv6AddressList = ipv6Setting->addresses(); + NetworkManager::IpAddress settingIpv6Address = ipv6AddressList.at(0); + if (settingIpv6Address.isValid()) { + ipv6Address = settingIpv6Address.ip().toString(); + } else { + qWarning()<<"[KyConnectResourse]"<<"get connect ipv6 failed, ipv6Address is not valid"; + } + } else { + qWarning()<<"[KyConnectResourse]"<<"get connect ipv6 failed, ipv6 config with dhcp"; + } + + return; +} + + +void KyConnectResourse::getIpv4ConnectSetting( + NetworkManager::Ipv4Setting::Ptr &ipv4Setting, + KyConnectSetting &connectSetting) +{ + if (NetworkManager::Ipv4Setting::Automatic == ipv4Setting->method()) { + connectSetting.m_ipv4ConfigIpType = CONFIG_IP_DHCP; + return; + } + + connectSetting.m_ipv4ConfigIpType = CONFIG_IP_MANUAL; + + connectSetting.m_ipv4Address = ipv4Setting->addresses(); + connectSetting.m_ipv4Dns = ipv4Setting->dns(); + + return; +} + +void KyConnectResourse::getIpv6ConnectSetting( + NetworkManager::Ipv6Setting::Ptr &ipv6Setting, + KyConnectSetting &connectSetting) +{ + + if (NetworkManager::Ipv6Setting::Automatic == ipv6Setting->method()) { + connectSetting.m_ipv6ConfigIpType = CONFIG_IP_DHCP; + return; + } + + connectSetting.m_ipv6ConfigIpType = CONFIG_IP_MANUAL; + + connectSetting.m_ipv6Address = ipv6Setting->addresses(); + + connectSetting.m_ipv6Dns = ipv6Setting->dns(); + + return; +} + +void KyConnectResourse::getConnectivity(NetworkManager::Connectivity &connectivity) +{ + m_networkResourceInstance->getConnectivity(connectivity); +} + +void KyConnectResourse::getConnectionSetting(QString connectUuid, KyConnectSetting &connectSetting) +{ + qDebug() <<"[KyConnectResourse]" << connectUuid <<"get connect setting info, connect uuid"; + + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(connectUuid); + + if (nullptr == connectPtr + || !connectPtr->isValid()) { + qWarning() <<"[KyConnectResourse]" << "it can not find valid connection" << connectUuid; + return; + } + + connectSetting.m_connectName = connectPtr->name(); + + NetworkManager::ConnectionSettings::Ptr connectionSettings = connectPtr->settings(); + connectSetting.m_ifaceName = connectionSettings->interfaceName(); + connectSetting.m_isAutoConnect = connectionSettings->autoconnect(); + + NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + getIpv4ConnectSetting(ipv4Setting, connectSetting); + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + getIpv6ConnectSetting(ipv6Setting, connectSetting); + + return; +} + +bool KyConnectResourse::getInterfaceByUuid(QString &deviceName, const QString connUuid) +{ + deviceName.clear(); + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(connUuid); + + if (nullptr == connectPtr) { + qWarning()<<"getInterfaceByUuid failed, connect uuid"<settings(); + + if (connectSettingPtr.isNull()) { + qWarning()<<"getInterfaceByUuid failed, connect uuid"<settings()->interfaceName(); + qDebug() << "getInterfaceByUuid success " << deviceName; + return true; +} + +void KyConnectResourse::getVpnConnectData(NetworkManager::ConnectionSettings::Ptr settingsPtr, + KyVpnConnectItem *vpnItem) +{ + NetworkManager::VpnSetting::Ptr vpnSetting = settingsPtr->setting(NetworkManager::Setting::Vpn).dynamicCast(); + NMStringMap vpnDataMap = vpnSetting->data(); + if (vpnDataMap.isEmpty()) { + qWarning()<<"get vpn connection Data failed, the data is empty"; + return; + } + + vpnItem->m_vpnGateWay = vpnDataMap["gateway"]; + vpnItem->m_vpnUser = vpnDataMap["user"]; + if ( "yes" == vpnDataMap["require-mppe"]) { + vpnItem->m_vpnMppe = true; + } else { + vpnItem->m_vpnMppe = false; + qDebug()<<"vpn mppe required:"<< vpnDataMap["require-mppe"]; + } + + return; +} + +KyVpnConnectItem *KyConnectResourse::getVpnConnectItem(NetworkManager::Connection::Ptr connectPtr) +{ + if (nullptr == connectPtr) { + qWarning()<<"[KyConnectResourse]"<<"get vpn connection item failed, the connect is empty"; + return nullptr; + } + + KyVpnConnectItem *vpnItem = new KyVpnConnectItem(); + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + + vpnItem->m_vpnName = connectPtr->name(); + vpnItem->m_vpnUuid = connectPtr->uuid(); + vpnItem->m_vpnState = NetworkManager::VpnConnection::State::Disconnected; + + getConnectIp(settingPtr, vpnItem->m_vpnIpv4Address, vpnItem->m_vpnIpv6Address); + getVpnConnectData(settingPtr, vpnItem); + + return vpnItem; +} + +void KyConnectResourse::getVpnConnections(QList &vpnConnectItemList) +{ + int index = 0; + NetworkManager::Connection::List connectList; + + qDebug()<<"[KyConnectResourse]"<<"get vpn connections"; + + connectList.clear(); + connectList = m_networkResourceInstance->getConnectList(); + + if (connectList.empty()) { + qWarning()<<"[KyConnectResourse]"<<"get vpn connections failed, the connect list is empty"; + return; + } + + NetworkManager::Connection::Ptr connectPtr = nullptr; + for (index = 0; index < connectList.size(); index++) { + connectPtr = connectList.at(index); + if (connectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Vpn + != connectPtr->settings()->connectionType()) { + qDebug()<<"[KyConnectResourse]"<<"connect name:" << connectPtr->name() + <<"connect type:"<settings()->connectionType(); + continue; + } + + if (m_networkResourceInstance->isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + continue; + } + + KyVpnConnectItem *connectItem = getVpnConnectItem(connectPtr); + if (nullptr != connectItem) { + vpnConnectItemList << connectItem; + //connectItem->dumpInfo(); + } + + connectPtr = nullptr; + } + + return; +} + + +KyBluetoothConnectItem *KyConnectResourse::getBluetoothConnectItem(NetworkManager::Connection::Ptr connectPtr) +{ + if (nullptr == connectPtr) { + qWarning()<<"[KyConnectResourse]"<<"get bluetooth connection item failed, the connect is empty"; + return nullptr; + } + + KyBluetoothConnectItem *bluetoothItem = new KyBluetoothConnectItem(); + bluetoothItem->m_connectName = connectPtr->name(); + bluetoothItem->m_connectUuid = connectPtr->uuid(); + bluetoothItem->m_state = NetworkManager::ActiveConnection::State::Deactivated; + + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + getConnectIp(settingPtr, bluetoothItem->m_ipv4Address, bluetoothItem->m_ipv6Address); + + NetworkManager::BluetoothSetting::Ptr bluetoothSetting = + settingPtr->setting(NetworkManager::Setting::Bluetooth).dynamicCast(); + bluetoothItem->m_deviceAddress = bluetoothSetting->bluetoothAddress(); + QByteArray btAddrArray = bluetoothSetting->bluetoothAddress(); + for (int index = 0; index < btAddrArray.size(); ++index) { + qDebug("bt address %d %s", index, btAddrArray[index]); + } + // qDebug()<<"bt address 0:"<< btAddrArray[0]; + // qDebug()<<"bt address 1:"<< btAddrArray[1]; + // qDebug()<<"array size:"<m_deviceAddress.toInt(nullptr, 16); + + return bluetoothItem; +} + +void KyConnectResourse::getBluetoothConnections(QList &bluetoothConnectItemList) +{ + int index = 0; + NetworkManager::Connection::List connectList; + + qDebug()<<"[KyConnectResourse]"<<"get bluetooth connections"; + + connectList.clear(); + connectList = m_networkResourceInstance->getConnectList(); + + if (connectList.empty()) { + qWarning()<<"[KyConnectResourse]"<<"get bluetooth connections failed, the connect list is empty"; + return; + } + + NetworkManager::Connection::Ptr connectPtr = nullptr; + for (index = 0; index < connectList.size(); index++) { + connectPtr = connectList.at(index); + if (connectPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Bluetooth + != connectPtr->settings()->connectionType()) { + qDebug()<<"[KyConnectResourse]"<<"connect name:" << connectPtr->name() + <<"connect type:"<settings()->connectionType(); + continue; + } + + if (m_networkResourceInstance->isActiveConnection(connectPtr->uuid())) { + qDebug()<<"[KyConnectResourse]"<name()<<"is active connection"; + continue; + } + + KyBluetoothConnectItem *connectItem = getBluetoothConnectItem(connectPtr); + if (nullptr != connectItem) { + bluetoothConnectItemList << connectItem; + //connectItem->dumpInfo(); + } + + connectPtr = nullptr; + } + + return; +} + + +KyApConnectItem *KyConnectResourse::getApConnectItem(NetworkManager::Connection::Ptr connectPtr) +{ + if (nullptr == connectPtr) { + qWarning()<<"[KyConnectResourse]"<<"get bluetooth connection item failed, the connect is empty"; + return nullptr; + } + + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + NetworkManager::WirelessSetting::Ptr wirelessSetting + = settingPtr->setting(NetworkManager::Setting::Wireless).dynamicCast(); + + if (NetworkManager::WirelessSetting::NetworkMode::Ap + != wirelessSetting->mode()) { + qDebug() << "[KyConnectResourse]" <<"get ap item failed, the active connect mode is not ap."; + return nullptr; + } + + KyNetworkDeviceResourse deviceResource; + if (!deviceResource.wirelessDeviceIsExist(settingPtr->interfaceName())) { + qDebug() << "[KyConnectResourse]" <<"get ap item failed, the ap device is not exist yet"; + return nullptr; + } + + QByteArray rawSsid = wirelessSetting->ssid(); + + KyApConnectItem *apConnectItem = new KyApConnectItem(); + apConnectItem->m_connectName = connectPtr->name(); + apConnectItem->m_connectSsid = getSsidFromByteArray(rawSsid); + apConnectItem->m_connectUuid = connectPtr->uuid(); + if (wirelessSetting->band() == NetworkManager::WirelessSetting::FrequencyBand::A) { + apConnectItem->m_band = str2GBand; + } else if (wirelessSetting->band() == NetworkManager::WirelessSetting::FrequencyBand::Bg) { + apConnectItem->m_band = str5GBand; + } + apConnectItem->m_ifaceName = settingPtr->interfaceName(); + apConnectItem->m_isActivated = m_networkResourceInstance->isActiveConnection(connectPtr->uuid()); + + //NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySetting + // = settingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + KyWirelessConnectOperation wirelessOperation; + apConnectItem->m_password = wirelessOperation.getPsk(apConnectItem->m_connectUuid);// wirelessSecuritySetting->psk(); + + return apConnectItem; +} + +KyApConnectItem *KyConnectResourse::getApConnectionByUuid(QString connectUuid) +{ + NetworkManager::Connection::Ptr connectPtr = nullptr; + + connectPtr = m_networkResourceInstance->getConnect(connectUuid); + if (nullptr == connectPtr) { + return nullptr; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless + != connectPtr->settings()->connectionType()) { + return nullptr; + } + + KyApConnectItem *connectItem = getApConnectItem(connectPtr); + + return connectItem; +} + +QString KyConnectResourse::getApConnectionPathByUuid(QString connectUuid) +{ + NetworkManager::Connection::Ptr connectPtr = nullptr; + + connectPtr = m_networkResourceInstance->getConnect(connectUuid); + if (nullptr == connectPtr) { + return nullptr; + } + + return connectPtr->path(); +} + +void KyConnectResourse::getApConnections(QList &apConnectItemList) +{ + QList apActiveConnectItemList; + QList apDeactiveConnectItemList; + int index = 0; + NetworkManager::Connection::List connectList; + + qDebug()<<"[KyConnectResourse]"<<"get ap connections"; + + connectList.clear(); + connectList = m_networkResourceInstance->getConnectList(); + + if (connectList.empty()) { + qWarning()<<"[KyConnectResourse]"<<"get ap connections failed, the connect list is empty"; + return; + } + + NetworkManager::Connection::Ptr connectPtr = nullptr; + for (index = 0; index < connectList.size(); index++) { + connectPtr = connectList.at(index); + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless + != connectPtr->settings()->connectionType()) { + qDebug()<<"[KyConnectResourse]"<<"connect name:" << connectPtr->name() + <<"connect type:"<settings()->connectionType(); + continue; + } + + KyApConnectItem *connectItem = getApConnectItem(connectPtr); + if (nullptr != connectItem) { + if (connectItem->m_isActivated) { + apActiveConnectItemList << connectItem; + } else { + apDeactiveConnectItemList << connectItem; + } + } + + connectPtr = nullptr; + } + + apConnectItemList << apActiveConnectItemList << apDeactiveConnectItemList; + + return; +} + + +bool KyConnectResourse::isWiredConnection(QString uuid) +{ + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(uuid); + if (connectPtr.isNull()) { + qWarning()<<"[KyConnectResourse]"<<"can not find wired connection"<path(); + QString connectionType = getConnectTypeByDbus(connectPath); + if (ETHERNET_TYPE == connectionType) { + return true; + } + + return false; +} + +bool KyConnectResourse::isWirelessConnection(QString uuid) +{ + NetworkManager::Connection::Ptr connectPtr = + m_networkResourceInstance->getConnect(uuid); + if (connectPtr.isNull()) { + qWarning()<<"[KyConnectResourse]"<<"can not find wireless connection"<isValid()) { + NetworkManager::ConnectionSettings::Ptr connectSettingPtr = connectPtr->settings(); + + if (connectSettingPtr.isNull()) { + qWarning()<<"[KyConnectResourse]"<<"get connect setting failed, connect uuid"<settings()->connectionType()) { + return true; + } + } + + return false; +} + +bool KyConnectResourse::isActivatedConnection(QString uuid) +{ + return m_networkResourceInstance->isActiveConnection(uuid); +} + +bool KyConnectResourse::isApConnection(QString uuid) +{ + NetworkManager::Connection::Ptr connectPtr = nullptr; + + connectPtr = m_networkResourceInstance->getConnect(uuid); + if (nullptr == connectPtr) { + return false; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless + != connectPtr->settings()->connectionType()) { + return false; + } + + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + NetworkManager::WirelessSetting::Ptr wirelessSetting + = settingPtr->setting(NetworkManager::Setting::Wireless).dynamicCast(); + if (NetworkManager::WirelessSetting::NetworkMode::Ap + != wirelessSetting->mode()) { + return false; + } + + return true; +} diff --git a/src/backend/dbus-interface/kylinconnectresource.h b/src/backend/dbus-interface/kylinconnectresource.h new file mode 100644 index 00000000..9b334d34 --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectresource.h @@ -0,0 +1,91 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINCONNECTRESOURCE_H +#define KYLINCONNECTRESOURCE_H + +#include +#include "kylinnetworkresourcemanager.h" +#include "kylinconnectitem.h" +#include "kylinvpnconnectitem.h" +#include "kylinbluetoothconnectitem.h" +#include "kylinnetworkdeviceresource.h" +#include "kylinconnectsetting.h" +#include "kylinapconnectitem.h" + +class KyConnectResourse : public QObject +{ + Q_OBJECT +public: + explicit KyConnectResourse(QObject *parent = nullptr); + ~KyConnectResourse(); + +public: + KyConnectItem *getConnectionItemByUuid(QString connectUuid); + KyConnectItem *getConnectionItemByUuidWithoutActivateChecking(QString connectUuid); + KyConnectItem *getConnectionItemByUuid(QString connectUuid, QString deviceName); + void getConnectionList(QString deviceName, + NetworkManager::ConnectionSettings::ConnectionType connectionType, + QList &connectItemList); + // void getWiredConnections(QList &wiredConnectItemList); + void getVpnConnections(QList &vpnConnectItemList); + void getBluetoothConnections(QList &bluetoothConnectItemList); + void getApConnections(QList &apConnectItemList); + KyApConnectItem *getApConnectionByUuid(QString connectUuid); + QString getApConnectionPathByUuid(QString connectUuid); + QString getApAcitveConnectionPathByUuid(QString connectUuid); + + void getConnectionSetting(QString connectUuid, KyConnectSetting &connectSetting); + bool getInterfaceByUuid(QString &deviceName, const QString connUuid); + void getConnectivity(NetworkManager::Connectivity &connectivity); + + bool isWiredConnection(QString uuid); + bool isWirelessConnection(QString uuid); + bool isActivatedConnection(QString uuid); + bool isApConnection(QString uuid); + +private: + bool isActiveDevice(QString conUuid, QString devName); + KyConnectItem *getConnectionItem(NetworkManager::Connection::Ptr connectPtr, QString devName); + void getConnectIp(NetworkManager::ConnectionSettings::Ptr settingPtr, + QString &ipv4Address, + QString &ipv6Address); +// KyWiredConnectItem *getWiredConnectItem(NetworkManager::Connection::Ptr connectPtr); + + void getVpnConnectData(NetworkManager::ConnectionSettings::Ptr settingPtr, + KyVpnConnectItem *vpnItem); + KyVpnConnectItem *getVpnConnectItem(NetworkManager::Connection::Ptr connectPtr); + KyBluetoothConnectItem *getBluetoothConnectItem(NetworkManager::Connection::Ptr connectPtr); + KyApConnectItem *getApConnectItem(NetworkManager::Connection::Ptr connectPtr); + + void getIpv4ConnectSetting(NetworkManager::Ipv4Setting::Ptr &ipv4Setting, + KyConnectSetting &connectSetting); + void getIpv6ConnectSetting(NetworkManager::Ipv6Setting::Ptr &ipv6Setting, + KyConnectSetting &connectSetting); + +Q_SIGNALS: + void connectionAdd(QString uuid); + void connectionUpdate(QString uuid); + void connectionRemove(QString path); + void connectivityChanged(NetworkManager::Connectivity connectivity); + +private: + KyNetworkResourceManager *m_networkResourceInstance = nullptr; +}; +#endif // KYLINCONNECTRESOURCE_H diff --git a/src/backend/dbus-interface/kylinconnectsetting.cpp b/src/backend/dbus-interface/kylinconnectsetting.cpp new file mode 100644 index 00000000..88aeb57d --- /dev/null +++ b/src/backend/dbus-interface/kylinconnectsetting.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + +KyConnectSetting::KyConnectSetting(/*QObject *parent) : QObject(parent*/) +{ + m_connectName = ""; + m_ifaceName = ""; + + m_ipv4ConfigIpType = CONFIG_IP_DHCP; + m_ipv4Address.clear(); + m_ipv4Dns.clear(); + + m_ipv6ConfigIpType = CONFIG_IP_DHCP; + m_ipv6Address.clear(); + m_ipv6Dns.clear(); + + m_isAutoConnect = true; +} + +KyConnectSetting::~KyConnectSetting() +{ + +} + +void KyConnectSetting::setIfaceName(QString &ifaceName) +{ + m_ifaceName = ifaceName; +} + +void KyConnectSetting::setConnectName(QString &connectName) +{ + m_connectName = connectName; +} + +int KyConnectSetting::setIpConfigType(KyIpAddressType ipType, KyIpConfigType ipConfigType) +{ + if (ipType != IPADDRESS_V4 && ipType != IPADDRESS_V6) { + qWarning()<<"set config ip type failed, the ip address type undefined"< +#include +//#include + +#include +#include +#include +#include +#include + +typedef enum { + CONFIG_IP_MANUAL, + CONFIG_IP_DHCP, +}KyIpConfigType; + +typedef enum { + IPADDRESS_V4, + IPADDRESS_V6, +}KyIpAddressType; + +class KyConnectSetting/* : public QObject*/ +{ +// Q_OBJECT +public: +/* explicit*/ KyConnectSetting(/*QObject *parent = nullptr*/); + ~KyConnectSetting(); + +public: + void setIfaceName(QString &ifaceName); + void setConnectName(QString &connectName); + int setIpConfigType(KyIpAddressType ipType, KyIpConfigType configType); + void ipv4AddressConstruct(QString &ipv4Address, QString &ipv4NetMask, QString &ipv4GateWay, QStringList &ipv4Dns); + void ipv6AddressConstruct(QString &ipv6Address, QString &ipv6NetMask, QString &ipv6GateWay, QStringList &ipv6Dns); + void dumpInfo(); + +public: + QString m_connectName; + QString m_ifaceName; + + KyIpConfigType m_ipv4ConfigIpType; + QList m_ipv4Address; + QList m_ipv4Dns; + + KyIpConfigType m_ipv6ConfigIpType; + QList m_ipv6Address; + QList m_ipv6Dns; + + bool m_isAutoConnect; +}; + +#endif // KYLINCONNECTSETTING_H diff --git a/src/backend/dbus-interface/kylinnetworkdeviceresource.cpp b/src/backend/dbus-interface/kylinnetworkdeviceresource.cpp new file mode 100644 index 00000000..3e78bfbb --- /dev/null +++ b/src/backend/dbus-interface/kylinnetworkdeviceresource.cpp @@ -0,0 +1,430 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kylinnetworkdeviceresource.h" +#include "kywirelessnetitem.h" +#include "kylinutil.h" + +#define VIRTURAL_DEVICE_PATH "/sys/devices/virtual/net" +#define LOG_FLAG "KyNetworkDeviceResourse" + +KyNetworkDeviceResourse::KyNetworkDeviceResourse(QObject *parent) : QObject(parent) +{ + qRegisterMetaType("NetworkManager::Device::State"); + qRegisterMetaType("NetworkManager::Device::StateChangeReason"); + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); + + m_deviceMap.clear(); + + initDeviceMap(); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceAdd, + this, &KyNetworkDeviceResourse::onDeviceAdd, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceRemove, + this, &KyNetworkDeviceResourse::onDeviceRemove, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceUpdate, + this, &KyNetworkDeviceResourse::onDeviceUpdate, Qt::ConnectionType::DirectConnection); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::stateChanged, + this, &KyNetworkDeviceResourse::stateChanged, Qt::ConnectionType::DirectConnection); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceCarrierChanage, + this, &KyNetworkDeviceResourse::carrierChanage); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceBitRateChanage, + this, &KyNetworkDeviceResourse::deviceBitRateChanage); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceMacAddressChanage, + this, &KyNetworkDeviceResourse::deviceMacAddressChanage); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceActiveChanage, + this, &KyNetworkDeviceResourse::deviceActiveChanage); + connect(m_networkResourceInstance, &KyNetworkResourceManager::deviceManagedChange, + this, &KyNetworkDeviceResourse::deviceManagedChange); + +} + +KyNetworkDeviceResourse::~KyNetworkDeviceResourse() +{ + m_networkResourceInstance = nullptr; +} + +void KyNetworkDeviceResourse::initDeviceMap() +{ + NetworkManager::Device::List deviceList + = m_networkResourceInstance->getNetworkDeviceList(); + + if (deviceList.isEmpty()) { + qDebug() << LOG_FLAG << "there is not interface in computer."; + return; + } + + NetworkManager::Device::Ptr devicePtr = nullptr; + for (int index = 0; index < deviceList.size(); ++index) { + devicePtr = deviceList.at(index); + if (devicePtr.isNull()) { + continue; + } + + m_deviceMap.insert(devicePtr->uni(), devicePtr->interfaceName()); + } + + return; +} + +void KyNetworkDeviceResourse::getNetworkDeviceList( + NetworkManager::Device::Type deviceType, + QStringList &networkDeviceList) +{ + NetworkManager::Device::List deviceList + = m_networkResourceInstance->getNetworkDeviceList(); + + if (deviceList.isEmpty()) { + qDebug() << LOG_FLAG <<"network device is not exist. device type" << deviceType; + return; + } + + NetworkManager::Device::Ptr devicePtr = nullptr; + for (int index = 0; index < deviceList.size(); ++index) { + devicePtr = deviceList.at(index); + if (devicePtr.isNull()) { + continue; + } + + if (devicePtr->type() == deviceType) { + if (NetworkManager::Device::Type::Ethernet == deviceType) { + //为了区分有线网卡和虚拟网卡 + qDebug()<< LOG_FLAG << "device uni" << devicePtr->udi(); + if (devicePtr->udi().startsWith(VIRTURAL_DEVICE_PATH)) { + continue; + } + } + + networkDeviceList<interfaceName(); + } + } + + return; +} + +void KyNetworkDeviceResourse::getHardwareInfo(QString ifaceName, QString &hardAddress, int &bandWith) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->getNetworkDevice(ifaceName); + + if (nullptr == connectDevice || !connectDevice->isValid()) { + qWarning()<< LOG_FLAG <<"get hardware info failed, the device" << ifaceName << "is not existed"; + hardAddress.clear(); + bandWith = 0; + return; + } + + switch (connectDevice->type()) { + case NetworkManager::Device::Ethernet: + { + NetworkManager::WiredDevice *wiredDevicePtr = + qobject_cast(connectDevice.data()); + hardAddress = wiredDevicePtr->hardwareAddress(); + bandWith = wiredDevicePtr->bitRate(); + break; + } + case NetworkManager::Device::Wifi: + { + NetworkManager::WirelessDevice *wirelessDevicePtr = + qobject_cast(connectDevice.data()); + hardAddress = wirelessDevicePtr->hardwareAddress(); + bandWith = wirelessDevicePtr->bitRate(); + break; + } + default: + { + hardAddress = ""; + bandWith = 0; + qWarning()<< LOG_FLAG << "the network device type is undefined" << connectDevice->type(); + break; + } + } + + return; +} + +NetworkManager::Device::State KyNetworkDeviceResourse::getDeviceState(QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (!connectDevice.isNull() && connectDevice->isValid()) { + return connectDevice->state(); + } + + qWarning()<< LOG_FLAG <<"get device state failed, the device is " << deviceName; + + return NetworkManager::Device::State::UnknownState; +} + +bool KyNetworkDeviceResourse::wiredDeviceIsCarriered(QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice.isNull()) { + qDebug()<< LOG_FLAG << "check device carriered failed."; + return false; + } + + + if (connectDevice->isValid() + && NetworkManager::Device::Type::Ethernet == connectDevice->type()) { + NetworkManager::WiredDevice *wiredDevicePtr = + qobject_cast(connectDevice.data()); + return wiredDevicePtr->carrier(); + } + + qWarning()<< LOG_FLAG << deviceName <<" can not get carrier state."; + + return false; +} + +void KyNetworkDeviceResourse::setDeviceRefreshRate(QString deviceName, int ms) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice.isNull()) { + return; + } + + if (connectDevice->isValid()) { + NetworkManager::DeviceStatistics::Ptr deviceStatistics = connectDevice->deviceStatistics(); + deviceStatistics->setRefreshRateMs(ms); + } + + return; +} + +qulonglong KyNetworkDeviceResourse::getDeviceRxRefreshRate(QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice->isValid()) { + NetworkManager::DeviceStatistics::Ptr deviceStatistics = connectDevice->deviceStatistics(); + qulonglong rx = 0; + rx = deviceStatistics->rxBytes(); + if (rx != 0) { + return rx; + } else { + qDebug() << "connectDevice is invalid we do not get rxrate"; + } + } + + return 0; +} + +qulonglong KyNetworkDeviceResourse::getDeviceTxRefreshRate(QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice->isValid()) { + NetworkManager::DeviceStatistics::Ptr deviceStatistics = connectDevice->deviceStatistics(); + qulonglong tx = 0; + tx = deviceStatistics->txBytes(); + if (tx != 0){ + return tx; + } else { + qDebug() << "connectDevice is invalid we do not get txrate"; + } + } + + return 0; +} + +bool KyNetworkDeviceResourse::getActiveConnectionInfo(const QString devName, int &signalStrength, QString &uni, QString &secuType) +{ + signalStrength = 0; + uni = ""; + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->getNetworkDevice(devName); + + if (nullptr == connectDevice || !connectDevice->isValid()) { + qWarning()<< LOG_FLAG <<"getDeviceActiveAPInfo failed, the device" << devName << "is not existed"; + return false; + } + + if (connectDevice->type() == NetworkManager::Device::Wifi) { + NetworkManager::WirelessDevice *wirelessDevicePtr = + qobject_cast(connectDevice.data()); + NetworkManager::AccessPoint::Ptr apPtr = wirelessDevicePtr->activeAccessPoint(); + if (apPtr.isNull()) { + return false; + } + signalStrength = apPtr->signalStrength(); + uni = apPtr->uni(); + NetworkManager::AccessPoint::Capabilities cap = apPtr->capabilities(); + NetworkManager::AccessPoint::WpaFlags wpaFlag = apPtr->wpaFlags(); + NetworkManager::AccessPoint::WpaFlags rsnFlag = apPtr->rsnFlags(); + secuType = enumToQstring(cap, wpaFlag, rsnFlag); + return true; + } else { + return false; + } +} + +void KyNetworkDeviceResourse::getDeviceActiveAPInfo(const QString devName, QString &strMac, uint &iHz, uint &iChan, QString &secuType) +{ + strMac.clear(); + iHz = 0; + iChan = 0; + secuType.clear(); + + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->getNetworkDevice(devName); + + if (nullptr == connectDevice || !connectDevice->isValid()) { + qWarning()<< LOG_FLAG <<"getDeviceActiveAPInfo failed, the device" << devName << "is not existed"; + return; + } + + switch (connectDevice->type()) { + case NetworkManager::Device::Wifi: + { + NetworkManager::WirelessDevice *wirelessDevicePtr = + qobject_cast(connectDevice.data()); + NetworkManager::AccessPoint::Ptr apPtr = wirelessDevicePtr->activeAccessPoint(); + if (apPtr.isNull()) { + break; + } + strMac = apPtr->hardwareAddress(); + iHz = apPtr->frequency(); + iChan = NetworkManager::findChannel(iHz); + NetworkManager::AccessPoint::Capabilities cap = apPtr->capabilities(); + NetworkManager::AccessPoint::WpaFlags wpaFlag = apPtr->wpaFlags(); + NetworkManager::AccessPoint::WpaFlags rsnFlag = apPtr->rsnFlags(); + secuType = enumToQstring(cap, wpaFlag, rsnFlag); + break; + } + case NetworkManager::Device::Ethernet: + break; + default: + break; + } + + return; +} + +int KyNetworkDeviceResourse::getWirelessDeviceCapability(const QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice->isValid() + && NetworkManager::Device::Type::Wifi == connectDevice->type()) { + NetworkManager::WirelessDevice *wirelessDevicePtr = + qobject_cast(connectDevice.data()); + + int cap = 0; + if (wirelessDevicePtr->wirelessCapabilities() & NetworkManager::WirelessDevice::ApCap) { + cap = cap | 0x01; + } + if (wirelessDevicePtr->wirelessCapabilities() & NetworkManager::WirelessDevice::Freq2Ghz) { + cap = cap | 0x02; + } + if (wirelessDevicePtr->wirelessCapabilities() & NetworkManager::WirelessDevice::Freq5Ghz) { + cap = cap | 0x04; + } + return cap; + } else { + qWarning()<<"[KyNetworkDeviceResourse]"<findDeviceInterface(deviceName); + + if (devicePtr.isNull()) { + qDebug() << LOG_FLAG << "check device type failed, it is not exist"; + return false; + } + + if (NetworkManager::Device::Type::Ethernet == devicePtr->type() + && !devicePtr->udi().startsWith(VIRTURAL_DEVICE_PATH)) { + return true; + } + + return false; +} + +void KyNetworkDeviceResourse::setDeviceManaged(QString devName, bool managed) +{ + QString dbusPath; + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(devName); + if (connectDevice->isValid()) { + dbusPath = connectDevice->uni(); + } else { + qWarning()<<"[KyNetworkDeviceResourse] can not find device " << devName; + return; + } + setDeviceManagedByGDbus(dbusPath, managed); +} + +bool KyNetworkDeviceResourse::getDeviceManaged(QString deviceName) +{ + NetworkManager::Device::Ptr connectDevice = + m_networkResourceInstance->findDeviceInterface(deviceName); + if (connectDevice != nullptr && connectDevice->isValid()) { + return connectDevice->managed(); + } else { + qWarning()<<"[KyNetworkDeviceResourse] can not find device " << deviceName; + return false; + } +} diff --git a/src/backend/dbus-interface/kylinnetworkdeviceresource.h b/src/backend/dbus-interface/kylinnetworkdeviceresource.h new file mode 100644 index 00000000..4ad5881a --- /dev/null +++ b/src/backend/dbus-interface/kylinnetworkdeviceresource.h @@ -0,0 +1,83 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINNETORKDEVICERESOURCE_H +#define KYLINNETORKDEVICERESOURCE_H + +#include +#include "kylinnetworkresourcemanager.h" +#include "kylinconnectitem.h" +#include "kylinwiredconnectoperation.h" + +class KyNetworkDeviceResourse : public QObject +{ + Q_OBJECT +public: + explicit KyNetworkDeviceResourse(QObject *parent = nullptr); + ~KyNetworkDeviceResourse(); + +Q_SIGNALS: + void deviceAdd(QString deviceName, NetworkManager::Device::Type deviceType); + void deviceRemove(QString deviceName); + void deviceUpdate(QString deviceName); + + void deviceNameUpdate(QString oldName, QString newName); + void stateChange(QString deviceName, int state); + + void carrierChanage(QString deviceName, bool pluged); + void deviceBitRateChanage(QString deviceName, int bitRate); + void deviceMacAddressChanage(QString deviceName, const QString &hwAddress); + void deviceActiveChanage(QString deviceName, bool deivceActive); + void deviceManagedChange(QString deviceName, bool managed); + void stateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason); + +public Q_SLOTS: + void onDeviceAdd(QString deviceName, QString uni, NetworkManager::Device::Type deviceType); + void onDeviceRemove(QString deviceName, QString uni); + void onDeviceUpdate(QString interface, QString dbusPath); + +public: + void getNetworkDeviceList(NetworkManager::Device::Type deviceType, QStringList &networkDeviceList); + void getHardwareInfo(QString ifaceName, QString &hardAddress, int &bandWith); + void getDeviceActiveAPInfo(const QString devName, QString &strMac, uint &iHz, uint &iChan, QString &secuType); + int getWirelessDeviceCapability(const QString deviceName); + NetworkManager::Device::State getDeviceState(QString deviceName); + bool getActiveConnectionInfo(const QString devName, int &signalStrength, QString &uni, QString &secuType); + + bool wiredDeviceIsCarriered(QString deviceName); + bool wirelessDeviceIsExist(const QString devName); + bool deviceIsWired(QString deviceName); + + void setDeviceRefreshRate(QString deviceName, int ms); + + void setDeviceManaged(QString devName, bool managed); + bool getDeviceManaged(QString devName); + + qulonglong getDeviceRxRefreshRate(QString deviceName); + qulonglong getDeviceTxRefreshRate(QString deviceName); + +private: + KyWiredConnectOperation wiredOperation; + KyNetworkResourceManager *m_networkResourceInstance = nullptr; + QStringList m_activeConnectUuidList; + QMap m_deviceMap; + + void initDeviceMap(); +}; +#endif // KYLINNETORKDEVICERESOURCE_H diff --git a/src/backend/dbus-interface/kylinnetworkresourcemanager.cpp b/src/backend/dbus-interface/kylinnetworkresourcemanager.cpp new file mode 100644 index 00000000..0737a0bd --- /dev/null +++ b/src/backend/dbus-interface/kylinnetworkresourcemanager.cpp @@ -0,0 +1,1088 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include "kylinutil.h" + +#define SIGNAL_DELAY 80000 +#define EMIT_DELAY 10000 + +#define LOG_FLAG "[KyNetworkResourceManager]" + +KyNetworkResourceManager* KyNetworkResourceManager::m_pInstance = nullptr; + +KyNetworkResourceManager* KyNetworkResourceManager::getInstance() +{ + if (m_pInstance == NULL) { + m_pInstance = new KyNetworkResourceManager(); + } + return m_pInstance; +} + +void KyNetworkResourceManager::Release() +{ + if (m_pInstance != NULL) { + delete m_pInstance; + m_pInstance = NULL; + } +} + +KyNetworkResourceManager::KyNetworkResourceManager(QObject *parent) : QObject(parent) +{ + qRegisterMetaType("NetworkManager::ActiveConnection::State"); + qRegisterMetaType("NetworkManager::Connectivity"); + qRegisterMetaType("NetworkManager::ActiveConnection::Reason"); + qRegisterMetaType("NetworkManager::Device::Type"); + qRegisterMetaType("NetworkManager::Device::State"); + qRegisterMetaType("NetworkManager::Device::StateChangeReason"); + + QDBusConnection::systemBus().connect(QString("org.freedesktop.DBus"), + QString("/org/freedesktop/DBus"), + QString("org.freedesktop.DBus"), + QString("NameOwnerChanged"), this, SLOT(onServiceAppear(QString,QString,QString))); + + QDBusConnection::systemBus().connect(QString("org.freedesktop.NetworkManager"), + QString("/org/freedesktop/NetworkManager"), + QString("org.freedesktop.NetworkManager"), + QString("PropertiesChanged"), this, SLOT(onPropertiesChanged(QVariantMap))); +} + +void KyNetworkResourceManager::onInitNetwork() +{ + insertActiveConnections(); + insertConnections(); + insertDevices(); + insertWifiNetworks(); + + //initialize NetworkManager signals + connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &KyNetworkResourceManager::onDeviceAdded); + connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &KyNetworkResourceManager::onDeviceRemoved); + connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &KyNetworkResourceManager::onActiveConnectionAdded); + connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &KyNetworkResourceManager::onActiveConnectionRemoved); + connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &KyNetworkResourceManager::onConnectionAdded); + connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, static_cast(&KyNetworkResourceManager::onConnectionRemoved)); + + connect(NetworkManager::notifier(), &NetworkManager::Notifier::connectivityChanged, this, &KyNetworkResourceManager::connectivityChanged); + //todo wifi开关信号 + connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, &KyNetworkResourceManager::wifiEnabledChanged); + + // Note: the connectionRemoved is never emitted in case network-manager service stop, + // we need remove the connections manually. + connect(NetworkManager::notifier(), &NetworkManager::Notifier::serviceDisappeared, this, &KyNetworkResourceManager::clearConnections); + connect(NetworkManager::notifier(), &NetworkManager::Notifier::serviceDisappeared, this, &KyNetworkResourceManager::clearWifiNetworks); + + qDebug() <<"[KyNetworkResourceManager]" + << "active connections:" << m_activeConns.size() + << "connections:" << m_connections.size() + << "network device:" << m_devices.size(); + m_initFinished = true; + + return; +} + +KyNetworkResourceManager::~KyNetworkResourceManager() +{ + +} + +void KyNetworkResourceManager::removeActiveConnection(int pos) +{ + //active connections signals + NetworkManager::ActiveConnection::Ptr conn = m_activeConns.takeAt(pos); + conn->disconnect(this); +} + +void KyNetworkResourceManager::clearActiveConnections() +{ + while (0 < m_activeConns.size()) + removeActiveConnection(0); +} + +void KyNetworkResourceManager::addActiveConnection(NetworkManager::ActiveConnection::Ptr conn) +{ + m_activeConns.push_back(conn); +#if 0 + connect(conn.data(), &NetworkManager::ActiveConnection::connectionChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::default4Changed, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::default6Changed, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::dhcp4ConfigChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::dhcp6ConfigChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::ipV4ConfigChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::ipV6ConfigChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::idChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::typeChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::masterChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::specificObjectChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); +#endif + //connect(conn.data(), &NetworkManager::ActiveConnection::stateChangedReason, this, &KyNetworkResourceManager::onActiveConnectionChangedReason); + connect(conn.data(), &NetworkManager::ActiveConnection::stateChanged, this, &KyNetworkResourceManager::onActiveConnectionChanged); +#if 0 + connect(conn.data(), &NetworkManager::ActiveConnection::vpnChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::uuidChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(conn.data(), &NetworkManager::ActiveConnection::devicesChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); +#endif + if (conn->vpn()) { + connect(qobject_cast(conn.data()), &NetworkManager::VpnConnection::bannerChanged, this, &KyNetworkResourceManager::onActiveConnectionUpdated); + connect(qobject_cast(conn.data()), &NetworkManager::VpnConnection::stateChanged, this, &KyNetworkResourceManager::onVpnActiveConnectChanagedReason); + } +} + +void KyNetworkResourceManager::insertActiveConnections() +{ + for (auto const & conn : NetworkManager::activeConnections()) { + if (conn.isNull()) { + continue; + } + + addActiveConnection(conn); + } +} + +void KyNetworkResourceManager::removeConnection(int pos) +{ + //connections signals + QString path = m_connections.at(pos)->path(); + NetworkManager::Connection::Ptr conn = m_connections.takeAt(pos); + conn->disconnect(this); + Q_EMIT connectionRemove(path); +} + +void KyNetworkResourceManager::clearConnections() +{ + while (0 < m_connections.size()) { + removeConnection(0); + } +} + +void KyNetworkResourceManager::addConnection(NetworkManager::Connection::Ptr conn) +{ + m_connections.push_back(conn); + + //connections signals + connect(conn.data(), &NetworkManager::Connection::updated, this, &KyNetworkResourceManager::onConnectionUpdated); + connect(conn.data(), &NetworkManager::Connection::removed, this, &KyNetworkResourceManager::onConnectionRemoved); +} + +void KyNetworkResourceManager::insertConnections() +{ + for (auto const & connectPtr : NetworkManager::listConnections()) { + if (connectPtr.isNull()) { + continue; + } + + if (connectPtr->name().isEmpty() || connectPtr->uuid().isEmpty()) { + qWarning() <<"[KyNetworkResourceManager]" << " the name of connection is empty."; + continue; + } + + addConnection(connectPtr); + } + + return; +} + +void KyNetworkResourceManager::removeDevice(int pos) +{ + //connections signals + NetworkManager::Device::Ptr device = m_devices.takeAt(pos); + device->disconnect(this); +} + +void KyNetworkResourceManager::clearDevices() +{ + while (0 < m_devices.size()) + removeDevice(0); +} + +void KyNetworkResourceManager::addDevice(NetworkManager::Device::Ptr device) +{ + m_devices.push_back(device); + //device signals +#if 0 + //connect(device.data(), &NetworkManager::Device::stateChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::activeConnectionChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::autoconnectChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::availableConnectionChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::availableConnectionAppeared, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::availableConnectionDisappeared, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::capabilitiesChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::dhcp4ConfigChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::dhcp6ConfigChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::driverChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::driverVersionChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::firmwareMissingChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::firmwareVersionChanged, this, &KyNetworkResourceManager::onDeviceUpdated); +#endif + connect(device.data(), &NetworkManager::Device::activeConnectionChanged, this, &KyNetworkResourceManager::onDeviceActiveChanage); + connect(device.data(), &NetworkManager::Device::interfaceNameChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::managedChanged, this, &KyNetworkResourceManager::onDeviceManagedChange); +#if 0 + connect(device.data(), &NetworkManager::Device::ipV4AddressChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::ipV4ConfigChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::ipV6ConfigChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::ipInterfaceChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::physicalPortIdChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::mtuChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::nmPluginMissingChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::meteredChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::connectionStateChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(device.data(), &NetworkManager::Device::stateReasonChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + + connect(device.data(), &NetworkManager::Device::stateChanged, this, &KyNetworkResourceManager::onDeviceStateChanged); + connect(device.data(), &NetworkManager::Device::udiChanged, this, &KyNetworkResourceManager::onDeviceUpdated); +#endif + switch (device->type()) + { + case NetworkManager::Device::Ethernet: + connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::bitRateChanged, this, &KyNetworkResourceManager::onDeviceBitRateChanage); + connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::carrierChanged, this, &KyNetworkResourceManager::onDeviceCarrierChanage); + connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::hardwareAddressChanged, this, &KyNetworkResourceManager::onDeviceMacAddressChanage); + // connect(qobject_cast(device.data()), &NetworkManager::WiredDevice::permanentHardwareAddressChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + break; + + case NetworkManager::Device::Wifi: +#if 0 + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::bitRateChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::activeAccessPointChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::modeChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::wirelessCapabilitiesChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::hardwareAddressChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::permanentHardwareAddressChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::wirelessPropertiesChanged, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::accessPointAppeared, this, &KyNetworkResourceManager::onDeviceUpdated); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::accessPointDisappeared, this, &KyNetworkResourceManager::onDeviceUpdated); +#endif + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::networkAppeared, this, &KyNetworkResourceManager::onWifiNetworkAppeared); + connect(qobject_cast(device.data()), &NetworkManager::WirelessDevice::networkDisappeared, this, &KyNetworkResourceManager::onWifiNetworkDisappeared); + connect(device.data(), &NetworkManager::Device::stateChanged, this, &KyNetworkResourceManager::stateChanged); + break; + default: + //TODO: other device types! + break; + } +} + +void KyNetworkResourceManager::insertDevices() +{ + for (auto const & device : NetworkManager::networkInterfaces()) { + if (device.isNull()) { + continue; + } + + addDevice(device); + } + + return; +} + +void KyNetworkResourceManager::removeWifiNetwork(int pos) +{ + //network signals + NetworkManager::WirelessNetwork::Ptr net = m_wifiNets.takeAt(pos); + net->disconnect(this); +} + +void KyNetworkResourceManager::clearWifiNetworks() +{ + while (0 < m_wifiNets.size()) + removeWifiNetwork(0); +} + +void KyNetworkResourceManager::addWifiNetwork(NetworkManager::WirelessNetwork::Ptr net) +{ + m_wifiNets.push_back(net); + //device signals + connect(net.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &KyNetworkResourceManager::onUpdateWirelessNet); + connect(net.data(), &NetworkManager::WirelessNetwork::referenceAccessPointChanged, this, &KyNetworkResourceManager::onUpdateWirelessNet); + connect(net.data(), &NetworkManager::WirelessNetwork::referenceAccessPointChanged, this, &KyNetworkResourceManager::onReferenceAccessPointChanged); + connect(net.data(), &NetworkManager::WirelessNetwork::disappeared, this, &KyNetworkResourceManager::onUpdateWirelessNet); + connect(net->referenceAccessPoint().data(), &NetworkManager::AccessPoint::wpaFlagsChanged, this, &KyNetworkResourceManager::onWifiNetworkSecuChang, + Qt::UniqueConnection); + connect(net->referenceAccessPoint().data(), &NetworkManager::AccessPoint::rsnFlagsChanged, this, &KyNetworkResourceManager::onWifiNetworkSecuChang, + Qt::UniqueConnection); +} + +void KyNetworkResourceManager::insertWifiNetworks() +{ + for (auto const & device : m_devices) { + if (device.isNull()) { + continue; + } + + if (NetworkManager::Device::Wifi == device->type()) { + NetworkManager::WirelessDevice::Ptr w_dev = device.objectCast(); + for (auto const & net : w_dev->networks()) { + if (!net.isNull()) { + addWifiNetwork(net); + Q_EMIT wifiNetworkAdded(device->interfaceName(),net->ssid()); + } + } + } + } +} + +NetworkManager::ActiveConnection::Ptr KyNetworkResourceManager::findActiveConnection(QString const & path) +{ + auto i = std::find_if(m_activeConns.cbegin(), m_activeConns.cend(), [&path] (NetworkManager::ActiveConnection::Ptr const & conn) -> bool { + return conn->path() == path; + }); + return m_activeConns.cend() == i ? NetworkManager::ActiveConnection::Ptr{} : *i; +} + +template +NetworkManager::Device::Ptr KyNetworkResourceManager::findDevice(Predicate const & pred) +{ + auto i = std::find_if(m_devices.cbegin(), m_devices.cend(), pred); + return m_devices.cend() == i ? NetworkManager::Device::Ptr{} : *i; +} + +NetworkManager::Device::Ptr KyNetworkResourceManager::findDeviceUni(QString const & uni) +{ + return findDevice([&uni] (NetworkManager::Device::Ptr const & dev) { return dev->uni() == uni; }); +} + +NetworkManager::Device::Ptr KyNetworkResourceManager::findDeviceInterface(QString const & interfaceName) +{ + return findDevice([&interfaceName] (NetworkManager::Device::Ptr const & dev) { return dev->interfaceName() == interfaceName; }); +} + +NetworkManager::WirelessNetwork::Ptr KyNetworkResourceManager::findWifiNetwork(QString const & ssid, QString const & devUni) +{ + auto i = std::find_if(m_wifiNets.cbegin(), m_wifiNets.cend(), [&ssid, &devUni] (NetworkManager::WirelessNetwork::Ptr const & net) -> bool { + return net->ssid() == ssid && net->device() == devUni; + }); + return m_wifiNets.cend() == i ? NetworkManager::WirelessNetwork::Ptr{} : *i; +} + +NetworkManager::Device::Ptr KyNetworkResourceManager::getNetworkDevice(const QString ifaceName) +{ + NetworkManager::Device::Ptr devicePtr = nullptr; + if (ifaceName.isEmpty()) { + return nullptr; + } + + for (int index = 0; index < m_devices.size(); ++index) { + devicePtr = m_devices.at(index); + if (devicePtr.isNull()) { + continue; + } + + if (ifaceName == devicePtr->interfaceName()) { + return devicePtr; + } + } + + return nullptr; +} + +NetworkManager::ActiveConnection::Ptr KyNetworkResourceManager::getActiveConnect(const QString activeConnectUuid) +{ + int index = 0; + NetworkManager::ActiveConnection::Ptr activateConnectPtr = nullptr; + + qDebug()<<"[KyNetworkResourceManager]"<<"get activetate connect with uuid"<< activeConnectUuid; + if (activeConnectUuid.isEmpty()) { + return nullptr; + } + + for (index = 0; index < m_activeConns.size(); ++index) { + activateConnectPtr = m_activeConns.at(index); + if (activateConnectPtr.isNull()) { + continue; + } + + if (activateConnectPtr->uuid() == activeConnectUuid) { + return activateConnectPtr; + } + } + + qWarning()<<"[KyNetworkResourceManager]"<<"it can not find the activate connect with uuid" <uuid() == connectUuid) { + return connectPtr; + } + } + + qWarning()<<"[KyNetworkResourceManager]"<<"it can not find connect with uuid"<uuid() == uuid + && NetworkManager::ActiveConnection::State::Activated == activateConnectPtr->state()) { + return true; + } + } + + return false; +} + +bool KyNetworkResourceManager::isActivatingConnection(QString uuid) +{ + int index = 0; + NetworkManager::ActiveConnection::Ptr activateConnectPtr = nullptr; + + if (uuid.isEmpty()) { + return false; + } + + for (index = 0; index < m_activeConns.size(); ++index) { + activateConnectPtr = m_activeConns.at(index); + if (activateConnectPtr.isNull()) { + continue; + } + + if (activateConnectPtr->uuid() == uuid + && NetworkManager::ActiveConnection::State::Activating == activateConnectPtr->state()) { + return true; + } + } + + return false; +} + +void KyNetworkResourceManager::getConnectivity(NetworkManager::Connectivity &connectivity) +{ + connectivity = NetworkManager::connectivity(); +} + +bool KyNetworkResourceManager::NetworkManagerIsInited() +{ + return m_initFinished; +} + +void KyNetworkResourceManager::requestScan(NetworkManager::WirelessDevice * dev) +{ + if (nullptr == dev) { + qWarning() << LOG_FLAG << "request scan failed, wireless device is invalid."; + return; + } + + qDebug() <<"[KyNetworkResourceManager]"<< dev->interfaceName()<<"start scan wifi ap"; + QDBusPendingReply<> reply = dev->requestScan(); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, dev); + connect(watcher, &QDBusPendingCallWatcher::finished, [dev] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) + { + //TODO: in what form should we output the warning messages + qWarning() << QStringLiteral("requestScan on device '%1' failed: %3").arg(dev->interfaceName()) + .arg(watcher->error().message()); + } + watcher->deleteLater(); + }); + + return; +} + +void KyNetworkResourceManager::onServiceAppear(QString interface, QString oldOwner, QString newOwner) +{ + if (interface == "org.freedesktop.NetworkManager" + && oldOwner.isEmpty() && !newOwner.isEmpty()) { + qDebug() << LOG_FLAG << "org.freedesktop.NetworkManager start"; + QTimer::singleShot(500,this,&KyNetworkResourceManager::insertWifiNetworks); + } +} + +void KyNetworkResourceManager::onPropertiesChanged(QVariantMap qvm) +{ + for(QString keyStr : qvm.keys()) { + //收到wifi开关打开或关闭的信号后,进行处理 + if (keyStr == "WiredEnabled") { + bool wiredEnable = qvm.value("WiredEnabled").toBool(); + Q_EMIT wiredEnabledChanged(wiredEnable); + } + } +} + +void KyNetworkResourceManager::onConnectionUpdated() +{ + NetworkManager::Connection *connectPtr = + qobject_cast(sender()); + if (nullptr != connectPtr && connectPtr->isValid()) { + qDebug()<< LOG_FLAG <<"connection will Update, connection name"<name() + << "connection uuid" << connectPtr->uuid(); + Q_EMIT connectionUpdate(connectPtr->uuid()); + } else { + qWarning()<< LOG_FLAG + <<"onConnectionUpdate failed, the connect is invalid"; + } + + return; +} + +void KyNetworkResourceManager::onActiveConnectionUpdated() +{ + //Q_EMIT activeConnectionUpdate(qobject_cast(sender())); +} + +void KyNetworkResourceManager::onActiveConnectionChangedReason( + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason) +{ + NetworkManager::ActiveConnection * activeConnect = + qobject_cast(sender()); + if (nullptr != activeConnect && activeConnect->isValid()) { + qDebug()<< LOG_FLAG <<"connect uuid"<uuid() + <<"state change"<uuid(), state, reason); + } else { + qWarning() << LOG_FLAG << "onActiveConnectionChangedReason failed, the connection is invalid."; + } + + return; +} + +void KyNetworkResourceManager::onActiveConnectionChanged( + NetworkManager::ActiveConnection::State state) +{ + NetworkManager::ActiveConnection * activeConnect = + qobject_cast(sender()); + if (nullptr != activeConnect && activeConnect->isValid()) { + qDebug()<< LOG_FLAG << "connection uuid" << activeConnect->uuid() + <<"state change "<state() != state) { + qDebug() << "[KyNetworkResourceManager]" + <<"connect real state"<state() <<"change state"<uuid(), state, + NetworkManager::ActiveConnection::Reason::UknownReason); + } else { + qWarning() << LOG_FLAG << "onActiveConnectionChanged failed, the connection is invalid."; + } + + return; +} + +void KyNetworkResourceManager::onVpnActiveConnectChanagedReason(NetworkManager::VpnConnection::State state, + NetworkManager::VpnConnection::StateChangeReason reason) +{ + NetworkManager::ActiveConnection *activeConnect = + qobject_cast(sender()); + + if (nullptr != activeConnect && activeConnect->isValid()) { + qDebug()<<"vpn connect uuid" << activeConnect->uuid() + <<"state change " <uuid(), state, reason); + } else { + qWarning() << LOG_FLAG << "onVpnActiveConnectChanagedReason failed, the connection is invalid."; + } + + return; +} + +void KyNetworkResourceManager::onDeviceActiveChanage() +{ + NetworkManager::Device *p_device = qobject_cast(sender()); + if (nullptr == p_device) { + return; + } + + QString deviceName = p_device->interfaceName(); + //此处需要取反,因为激活连接的网卡状态是false,断开连接的网卡状态是true + bool isActive = !p_device->isActive(); + + qDebug()<< LOG_FLAG << "device active change, device name " << deviceName + << "active state" << isActive; + + Q_EMIT deviceActiveChanage(deviceName, isActive); + + return; +} + +void KyNetworkResourceManager::onDeviceUpdated() +{ + NetworkManager::Device *p_device = qobject_cast(sender()); + if (nullptr == p_device) { + return; + } + + QString deviceName = p_device->interfaceName(); + QString deviceUni = p_device->uni(); + + Q_EMIT deviceUpdate(deviceName, deviceUni); + + return; +} + +void KyNetworkResourceManager::onDeviceManagedChange() +{ + NetworkManager::Device *p_device = qobject_cast(sender()); + if (nullptr == p_device) { + return; + } + + QString deviceName = p_device->interfaceName(); + bool managed = p_device->managed(); + + Q_EMIT deviceManagedChange(deviceName, managed); +} + +void KyNetworkResourceManager::onDeviceCarrierChanage(bool pluged) +{ + NetworkManager::WiredDevice * networkDevice + = qobject_cast(sender()); + + qDebug()<< LOG_FLAG<<"device carrier chanage"<< pluged; + if (nullptr !=networkDevice && networkDevice->isValid()) { + Q_EMIT deviceCarrierChanage(networkDevice->interfaceName(), pluged); + } else { + qWarning()<< LOG_FLAG<<"onDeviceCarrierChanage failed."; + } + + return; +} + +void KyNetworkResourceManager::onDeviceBitRateChanage(int bitRate) +{ + NetworkManager::WiredDevice * networkDevice + = qobject_cast(sender()); + + if (nullptr != networkDevice + && networkDevice->isValid()) { + Q_EMIT deviceBitRateChanage(networkDevice->interfaceName(), bitRate); + } else { + qWarning()<< LOG_FLAG <<"the device is not invalid with bitrate" << bitRate; + } + + return; +} + +void KyNetworkResourceManager::onDeviceMacAddressChanage(const QString &hwAddress) +{ + NetworkManager::WiredDevice * networkDevice + = qobject_cast(sender()); + + if (nullptr !=networkDevice && networkDevice->isValid()) { + Q_EMIT deviceMacAddressChanage(networkDevice->interfaceName(), hwAddress); + } else { + qWarning()<< LOG_FLAG <<"the device is not invalid with mac" << hwAddress; + } + + return; +} + +void KyNetworkResourceManager::onDeviceStateChanged( + NetworkManager::Device::State newstate, + NetworkManager::Device::State oldstate, + NetworkManager::Device::StateChangeReason reason) +{ + qWarning() << LOG_FLAG <<"the device state "<interfaceName() << ssid; + + NetworkManager::WirelessDevice * w_dev = qobject_cast(dev); + NetworkManager::WirelessNetwork::Ptr net = w_dev->findNetwork(ssid); + if (!net.isNull()) { + if (0 > m_wifiNets.indexOf(net)){ + addWifiNetwork(net); + } else { + //TODO: onWifiNetworkUpdate + qDebug()<< LOG_FLAG << "add but already exist"; + } + + NetworkManager::AccessPoint::Ptr accessPoitPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPoitPtr->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + Q_EMIT wifiNetworkAdded(dev->interfaceName(), wifiSsid); + } + + return; +} + +void KyNetworkResourceManager::onWifiNetworkUpdate(NetworkManager::WirelessNetwork * net) +{ + if (nullptr == net) { + return; + } + + auto index = std::find(m_wifiNets.cbegin(), m_wifiNets.cend(), net); + if (m_wifiNets.cend() != index) { + if (net->accessPoints().isEmpty()) { + //Q_EMIT + bool bFlag = false; + QString devIface; + NetworkManager::Device::Ptr dev = findDeviceUni(net->device()); + if(dev.isNull()) { + qDebug()<< LOG_FLAG << "device invalid"; + bFlag = true; + } else { + devIface = dev->interfaceName(); + } + + //remove + auto pos = index - m_wifiNets.cbegin(); + removeWifiNetwork(pos); + if(bFlag) { + //device invalid + qDebug() << LOG_FLAG << "wifiNetworkDeviceDisappear"; + Q_EMIT wifiNetworkDeviceDisappear(); + } else { + qDebug()<< LOG_FLAG << "wifiNetwork disappear" << net << net->ssid(); + NetworkManager::AccessPoint::Ptr accessPoitPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPoitPtr->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + Q_EMIT wifiNetworkRemoved(devIface, wifiSsid); + } + } else { + qDebug()<< LOG_FLAG << "wifiNetworkPropertyChange " << net << net->ssid(); + Q_EMIT wifiNetworkPropertyChange(net); + } + } + + return; +} + +void KyNetworkResourceManager::onWifiNetworkRemove(NetworkManager::Device * dev, QString const & ssid) +{ + if (nullptr == dev) { + return; + } + + qDebug() << "wifiNetworkRemove" << dev << dev->interfaceName() << ssid; + + NetworkManager::WirelessNetwork::Ptr net = findWifiNetwork(ssid, dev->uni()); + if (!net.isNull()) { + auto pos = m_wifiNets.indexOf(net); + if (0 <= pos) { + removeWifiNetwork(pos); + NetworkManager::AccessPoint::Ptr accessPoitPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPoitPtr->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + Q_EMIT wifiNetworkRemoved(dev->interfaceName(), wifiSsid); + } + } + + return; +} + +void KyNetworkResourceManager::onWifiNetworkAppeared(QString const & ssid) +{ + NetworkManager::Device * p_device = qobject_cast(sender()); + if (nullptr != p_device) { + onWifiNetworkAdd(p_device, ssid); + + QString deviceName = p_device->interfaceName(); + QString deviceUni = p_device->uni(); + + Q_EMIT deviceUpdate(deviceName, deviceUni); + } else { + qWarning()<< LOG_FLAG << "onWifiNetworkAppeared failed."; + } + + return; +} + +void KyNetworkResourceManager::onWifiNetworkDisappeared(QString const & ssid) +{ + NetworkManager::Device *p_device = qobject_cast(sender()); + if (nullptr != p_device) { + onWifiNetworkRemove(p_device, ssid); + + QString deviceName = p_device->interfaceName(); + QString deviceUni = p_device->uni(); + + Q_EMIT deviceUpdate(deviceName, deviceUni); + } else { + qWarning()<< LOG_FLAG << "onWifiNetworkDisappeared failed."; + } + + return; +} + +void KyNetworkResourceManager::onReferenceAccessPointChanged() +{ + NetworkManager::WirelessNetwork *p_wirelessNet = + qobject_cast(sender()); + if (nullptr != p_wirelessNet) { + onAccessPointUpdate(p_wirelessNet); + } +} + +void KyNetworkResourceManager::onAccessPointUpdate(NetworkManager::WirelessNetwork * net) +{ + if (nullptr == net) { + return; + } + auto index = std::find(m_wifiNets.cbegin(), m_wifiNets.cend(), net); + if (m_wifiNets.cend() != index) { + if (!net->referenceAccessPoint().isNull()) { + connect(net->referenceAccessPoint().data(), &NetworkManager::AccessPoint::wpaFlagsChanged, this, &KyNetworkResourceManager::onWifiNetworkSecuChang, + Qt::UniqueConnection); + connect(net->referenceAccessPoint().data(), &NetworkManager::AccessPoint::rsnFlagsChanged, this, &KyNetworkResourceManager::onWifiNetworkSecuChang, + Qt::UniqueConnection); + } + } +} + +void KyNetworkResourceManager::onUpdateWirelessNet() +{ + NetworkManager::WirelessNetwork *p_wirelessNet = + qobject_cast(sender()); + if (nullptr != p_wirelessNet) { + onWifiNetworkUpdate(p_wirelessNet); + } + + return; +} + +void KyNetworkResourceManager::onWifiNetworkSecuChang() +{ + NetworkManager::AccessPoint *p_wirelessNet = + qobject_cast(sender()); + Q_EMIT wifiNetworkSecuChange(p_wirelessNet); +} + +void KyNetworkResourceManager::onDeviceAdded(QString const & uni) +{ + qDebug()<< "onDeviceAdded"<isValid()) { + qWarning() << uni << " is currently not invalid"; + return; + } + + if (0 > m_devices.indexOf(networkDevice)) { + addDevice(networkDevice); + Q_EMIT deviceAdd(networkDevice->interfaceName(), networkDevice->uni(), networkDevice->type()); + } else { + qWarning() << networkDevice->interfaceName() <<"the device is exist in network device list."; + } + + return; +} + +void KyNetworkResourceManager::onDeviceRemoved(QString const & uni) +{ + NetworkManager::Device::Ptr networkDevice = findDeviceUni(uni); + if (networkDevice.isNull()) { + qWarning()<<"the device is not exist in network device list ."<< uni; + return; + } + + qDebug()<<"remove network device"<< networkDevice->interfaceName() <<"uni:" << uni; + + auto index = std::find(m_devices.cbegin(), m_devices.cend(), networkDevice); + if (m_devices.cend() != index) { + const int pos = index - m_devices.cbegin(); + removeDevice(pos); + Q_EMIT deviceRemove(networkDevice->interfaceName(), networkDevice->uni()); + } + + return; +} + +void KyNetworkResourceManager::onActiveConnectionAdded(QString const & path) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = NetworkManager::findActiveConnection(path); + if (activeConnectPtr.isNull()) { + qWarning() << "[KyNetworkResourceManager]" << "the active connect is null, so do not add it."<isValid()) { + qWarning() << "[KyNetworkResourceManager]" << path << " connect is currently not valid"; + return; + } + + qDebug()<<"add active connect"<connection()->name(); + + if (0 > m_activeConns.indexOf(activeConnectPtr)) { + addActiveConnection(activeConnectPtr); + Q_EMIT activeConnectionAdd(activeConnectPtr->uuid()); + } else { + //TODO: onActiveConnectionUpdate + qWarning() << "[KyNetworkResourceManager]" << "update active connection to do"; + //Q_EMIT activeConnectionUpdate(conn->uuid()); + } + + return; +} + +void KyNetworkResourceManager::onActiveConnectionRemoved(QString const & path) +{ + NetworkManager::ActiveConnection::Ptr activeConnectPtr = findActiveConnection(path);//XXX: const QString &uni + if (activeConnectPtr.isNull()) { + qWarning() <<"[KyNetworkResourceManager]" + <<"the active connect is null, so do not remove it. "<< path; + return; + } + + qDebug() <<"[KyNetworkResourceManager]"<<"remove active connect"<uuid(); + + auto index = std::find(m_activeConns.cbegin(), m_activeConns.cend(), activeConnectPtr); + if (m_activeConns.cend() != index) { + const int pos = index - m_activeConns.cbegin(); + removeActiveConnection(pos); + Q_EMIT activeConnectionRemove(activeConnectPtr->uuid()); + } + + return; +} + +void KyNetworkResourceManager::onConnectionAdded(QString const & path) +{ + NetworkManager::Connection::Ptr connectPtr = NetworkManager::findConnection(path); + if (connectPtr.isNull()) { + qWarning() <<"[KyNetworkResourceManager]" <<"it can not find in networkmanager."<isValid()) { + qWarning() <<"[KyNetworkResourceManager]" << path << " is currently not invalid"; + return; + } + + qDebug() <<"[KyNetworkResourceManager]" <<"add connect "<< connectPtr->name() << connectPtr->path(); + + if (connectPtr->name().isEmpty() || connectPtr->uuid().isEmpty()) { + qWarning() <<"[KyNetworkResourceManager]" << "the name or uuid of connection is empty"; + return; + } + + if (0 > m_connections.indexOf(connectPtr)) { + addConnection(connectPtr); + Q_EMIT connectionAdd(connectPtr->uuid()); + } else { + //TODO::updateconnect + qWarning() << "[KyNetworkResourceManager]" << connectPtr->uuid() <<" connect is exist in connect list."; + } + + return; +} + +void KyNetworkResourceManager::onConnectionRemoved(QString const & path) +{ + if (path.isEmpty()) { + qDebug() <<"[KyNetworkResourceManager]" <<"the connect path is empty"; + return; + } + + qDebug() <<"[KyNetworkResourceManager]" << "remove connection path" << path; + NetworkManager::Connection::Ptr connectionPtr = nullptr; + for (int index = 0; index < m_connections.size(); ++index) { + connectionPtr = m_connections.at(index); + if (connectionPtr->path() == path) { + removeConnection(index); + return; + } + } + + qWarning() <<"[KyNetworkResourceManager]" << path <<" connect is no exist in connect list"; + + return; +} + +void KyNetworkResourceManager::removeConnection(QString const & uuid) +{ + NetworkManager::Connection::Ptr conn = this->getConnect(uuid); + if(!conn.isNull()) { + conn->disconnect(this); + conn->remove(); + } +} + +void KyNetworkResourceManager::setWirelessNetworkEnabled(bool enabled) +{ + NetworkManager::setWirelessEnabled(enabled); +} + +void KyNetworkResourceManager::connectionDump() +{ + NetworkManager::Connection::Ptr connectionPtr = nullptr; + for (int index = 0; index < m_connections.size(); ++index) { + connectionPtr = m_connections.at(index); + qDebug()<<"connection info**********************"; + qDebug()<<"connection name"<< connectionPtr->name(); + qDebug()<<"connection uuid"<< connectionPtr->uuid(); + qDebug()<<"connection path"<< connectionPtr->path(); + } +} diff --git a/src/backend/dbus-interface/kylinnetworkresourcemanager.h b/src/backend/dbus-interface/kylinnetworkresourcemanager.h new file mode 100644 index 00000000..0de8ce9a --- /dev/null +++ b/src/backend/dbus-interface/kylinnetworkresourcemanager.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class KyNetworkResourceManager : public QObject +{ + Q_OBJECT +public: + static KyNetworkResourceManager* getInstance(); + static void Release(); + +public: + explicit KyNetworkResourceManager(QObject *parent = nullptr); + ~KyNetworkResourceManager(); + + void removeActiveConnection(int pos); + void clearActiveConnections(); + void insertActiveConnections(); + void addActiveConnection(NetworkManager::ActiveConnection::Ptr conn); + + void removeConnection(int pos); + void clearConnections(); + void insertConnections(); + void addConnection(NetworkManager::Connection::Ptr conn); + + void removeDevice(int pos); + void clearDevices(); + void insertDevices(); + void addDevice(NetworkManager::Device::Ptr conn); + + void removeWifiNetwork(int pos); + void clearWifiNetworks(); + void addWifiNetwork(NetworkManager::WirelessNetwork::Ptr net); + + NetworkManager::ActiveConnection::Ptr findActiveConnection(QString const & path); + template + NetworkManager::Device::Ptr findDevice(Predicate const & pred); + NetworkManager::Device::Ptr findDeviceUni(QString const & uni); + NetworkManager::Device::Ptr findDeviceInterface(QString const & interfaceName); + NetworkManager::WirelessNetwork::Ptr findWifiNetwork(QString const & ssid, QString const & devUni); + + void requestScan(NetworkManager::WirelessDevice * dev); + + void removeConnection(QString const & uuid); + + void connectionDump(); + +public: + NetworkManager::Device::Ptr getNetworkDevice(const QString ifaceName); + NetworkManager::ActiveConnection::Ptr getActiveConnect(const QString activeConnectUuid); + NetworkManager::Connection::Ptr getConnect(const QString uuid); + NetworkManager::WirelessNetwork::Ptr getWifiNetwork(const QString apName); + + NetworkManager::ActiveConnection::List getActiveConnectList(); + NetworkManager::Connection::List getConnectList(); + NetworkManager::Device::List getNetworkDeviceList(); + bool isActiveConnection(QString uuid); + bool isActivatingConnection(QString uuid); + + void getConnectivity(NetworkManager::Connectivity &connectivity); + + bool NetworkManagerIsInited(); + +Q_SIGNALS: + void connectionAdd(QString uuid); + void connectionUpdate(QString uuid); + void connectionRemove(QString path); + + void deviceAdd(QString deviceName, QString uni, NetworkManager::Device::Type deviceType); + void deviceUpdate(QString deviceName, QString deviceUni); + void deviceRemove(QString deviceName, QString uni); + void deviceManagedChange(QString deviceName, bool managed); + + void deviceActiveChanage(QString deviceName, bool deviceActive); + void deviceCarrierChanage(QString deviceName, bool pluged); + void deviceBitRateChanage(QString deviceName, int bitRate); + void deviceMacAddressChanage(QString deviceName, const QString &hwAddress); + + //to KyWirelessNetResource + void wifiNetworkRemoved(QString, QString); + void wifiNetworkAdded(QString, QString); + void wifiNetworkPropertyChange(NetworkManager::WirelessNetwork * net); + void wifiNetworkSecuChange(NetworkManager::AccessPoint *); + void wifiNetworkDeviceDisappear(); + void wifiEnabledChanged(bool); + void wiredEnabledChanged(bool); + + void activeConnectionsReset(); + void activeConnectionAdd(QString uuid); + void activeConnectionUpdate(QString uuid); + void activeConnectionRemove(QString uuid); + void activeConnectStateChangeReason(QString uuid, + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason); + void vpnActiveConnectStateChangeReason(QString uuid, + NetworkManager::VpnConnection::State state, + NetworkManager::VpnConnection::StateChangeReason reason); + + void connectivityChanged(NetworkManager::Connectivity connectivity); + void stateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason); + + +public Q_SLOTS: + void onInitNetwork(); + void setWirelessNetworkEnabled(bool enabled); + +private Q_SLOTS: + void insertWifiNetworks(); + void onServiceAppear(QString, QString, QString); + void onPropertiesChanged(QVariantMap qvm); + //connection + void onConnectionUpdated(); + //void onConnectionRemoved(); + + //active connection + void onActiveConnectionUpdated(); + void onActiveConnectionChangedReason(NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason); + + void onActiveConnectionChanged(NetworkManager::ActiveConnection::State state); + void onVpnActiveConnectChanagedReason(NetworkManager::VpnConnection::State state, + NetworkManager::VpnConnection::StateChangeReason reason); + + //device + + void onDeviceActiveChanage(); + + void onDeviceUpdated(); + void onDeviceManagedChange(); + void onDeviceCarrierChanage(bool pluged); + void onDeviceBitRateChanage(int bitRate); + void onDeviceMacAddressChanage(const QString &hwAddress); + void onDeviceStateChanged(NetworkManager::Device::State newstate, + NetworkManager::Device::State oldstate, + NetworkManager::Device::StateChangeReason reason); + + void onWifiNetworkAppeared(QString const & ssid); + void onWifiNetworkDisappeared(QString const & ssid); + + //wifi network + void onUpdateWirelessNet(); + void onWifiNetworkSecuChang(); + + //notifier + void onDeviceAdded(QString const & uni); + void onDeviceRemoved(QString const & uni); + void onActiveConnectionAdded(QString const & path); + void onActiveConnectionRemoved(QString const & path); + + //settings notifier + void onConnectionAdded(QString const & path); + void onConnectionRemoved(QString const & path); + +private: + void onWifiNetworkAdd(NetworkManager::Device * dev, QString const & ssid); + void onWifiNetworkUpdate(NetworkManager::WirelessNetwork * net); + void onWifiNetworkRemove(NetworkManager::Device * dev, QString const & ssid); + + void onAccessPointUpdate(NetworkManager::WirelessNetwork * net); + void onReferenceAccessPointChanged(); + +private: + bool m_initFinished = false; + +public: + static KyNetworkResourceManager* m_pInstance; + + NetworkManager::ActiveConnection::List m_activeConns; //已连接资源类 + NetworkManager::Connection::List m_connections; //配置文件资源类 + NetworkManager::Device::List m_devices; //设备类 + NetworkManager::WirelessNetwork::List m_wifiNets; //无线热点类 +}; + + +#endif // KYLINNETWORKRESOURCEMANAGER_H diff --git a/src/backend/dbus-interface/kylinutil.cpp b/src/backend/dbus-interface/kylinutil.cpp new file mode 100644 index 00000000..7f307eb3 --- /dev/null +++ b/src/backend/dbus-interface/kylinutil.cpp @@ -0,0 +1,219 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kylinutil.h" +#include + +#include +#include +#include +#include + +#define LOG_FLAG "[kylin-util]" + +QString getConnectTypeByDbus(QString &connectPath) +{ + QString connectType = ""; + + if (connectPath.isEmpty()) { + qWarning()<< LOG_FLAG << "connect path is empty, so can not get connect type"; + return connectType; + } + + QDBusInterface dbusInterface("org.freedesktop.NetworkManager", + connectPath, + "org.freedesktop.NetworkManager.Settings.Connection", + QDBusConnection::systemBus()); + + QDBusMessage result = dbusInterface.call("GetSettings"); + const QDBusArgument &dbusArg1st = result.arguments().at( 0 ).value(); + QMap> map; + dbusArg1st >> map; + + if (map.isEmpty()) { + qWarning() << LOG_FLAG <<"get connection settings failed."; + return connectType; + } + + QMap connectMap = map.value(KEY_CONNECTION); + if (connectMap.isEmpty()) { + qWarning() << LOG_FLAG <<"threre is not connection settings"; + return connectType; + } + + connectType = connectMap.value(KEY_CONNECT_TYPE).toString(); + + return connectType; +} + +QString getSsidFromByteArray(QByteArray &rawSsid) +{ + QString wifiSsid = ""; + + if (rawSsid.isEmpty()) { + qWarning() << LOG_FLAG << "wifi raw ssid is empty"; + return wifiSsid; + } + + /* + * 由于区分GB2312和UTF-8的方法比较困难,加之会存在中英文混合的情况,所以暂时 + * 不区分,统一经过gb2312转换,经过测试没有影响。 + */ +// QTextCodec *p_textGBK = QTextCodec::codecForName("GB2312"); +// wifiSsid = p_textGBK->toUnicode(rawSsid); + + QTextCodec::ConverterState state; + QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + codec->toUnicode( rawSsid.constData(), rawSsid.size(), &state); + if (state.invalidChars > 0) + { + wifiSsid = QTextCodec::codecForName("GBK")->toUnicode(rawSsid); + } + else + { + wifiSsid = rawSsid; + } + return wifiSsid; +} + +void setWiredEnabledByGDbus(bool enabled) +{ + GDBusProxy *props_proxy; + GVariant *ret = NULL; + GError *error = NULL; + + /* Create a D-Bus object proxy for the active connection object's properties */ + props_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager", + "org.freedesktop.DBus.Properties", + NULL, NULL); + g_assert (props_proxy); + + /* Get the object path of the Connection details */ + ret = g_dbus_proxy_call_sync (props_proxy, + "Set", + g_variant_new ("(ssv)", + "org.freedesktop.NetworkManager", + "WiredEnabled", + g_variant_new_boolean(enabled)), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &error); + if (!ret) { + g_dbus_error_strip_remote_error (error); + qDebug() << "failed to setWiredEnabledByGDbus"; + g_error_free (error); + } + +out: + if (ret) + g_variant_unref (ret); + g_object_unref (props_proxy); +} + +bool getWiredEnabledByGDbus() +{ + GDBusProxy *props_proxy; + GVariant *ret = NULL, *path_value = NULL; + GError *error = NULL; + gboolean bRet = false; + + /* Create a D-Bus object proxy for the active connection object's properties */ + props_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager", + "org.freedesktop.DBus.Properties", + NULL, NULL); + g_assert (props_proxy); + + /* Get the object path of the Connection details */ + ret = g_dbus_proxy_call_sync (props_proxy, + "Get", + g_variant_new ("(ss)", + "org.freedesktop.NetworkManager", + "WiredEnabled"), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &error); + if (!ret) { + g_dbus_error_strip_remote_error (error); + qDebug() << "failed to setWiredEnabledByGDbus"; + g_error_free (error); + } + + g_variant_get (ret, "(v)", &path_value); + if (!g_variant_is_of_type (path_value, G_VARIANT_TYPE_BOOLEAN)) { + g_warning ("Unexpected type returned getting Connection property: %s", + g_variant_get_type_string (path_value)); + goto out; + } + + bRet = g_variant_get_boolean (path_value); + +out: + if (path_value) + g_variant_unref (path_value); + if (ret) + g_variant_unref (ret); + g_object_unref (props_proxy); + + return bRet; +} + + +void setDeviceManagedByGDbus(QString dbusPath, bool managed) +{ + GDBusProxy *props_proxy; + GVariant *ret = NULL; + GError *error = NULL; + + /* Create a D-Bus object proxy for the active connection object's properties */ + props_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.NetworkManager", + dbusPath.toStdString().c_str(), + "org.freedesktop.DBus.Properties", + NULL, NULL); + g_assert (props_proxy); + + /* Get the object path of the Connection details */ + ret = g_dbus_proxy_call_sync (props_proxy, + "Set", + g_variant_new ("(ssv)", + "org.freedesktop.NetworkManager.Device", + "Managed", + g_variant_new_boolean(managed)), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &error); + if (!ret) { + g_dbus_error_strip_remote_error (error); + qDebug() << "failed to setWiredEnabledByGDbus"; + g_error_free (error); + } + +out: + if (ret) + g_variant_unref (ret); + g_object_unref (props_proxy); +} + diff --git a/src/backend/dbus-interface/kylinutil.h b/src/backend/dbus-interface/kylinutil.h new file mode 100644 index 00000000..3925b419 --- /dev/null +++ b/src/backend/dbus-interface/kylinutil.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINUTIL_H +#define KYLINUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define KEY_CONNECTION "connection" +#define KEY_CONNECT_TYPE "type" +#define ETHERNET_TYPE "802-3-ethernet" + +QString getConnectTypeByDbus(QString &connectPath); +QString getSsidFromByteArray(QByteArray &rawSsid); +void setWiredEnabledByGDbus(bool enabled); +void setDeviceManagedByGDbus(QString dbusPath, bool managed); +bool getWiredEnabledByGDbus(); + +#endif // KYLINUTIL_H diff --git a/src/backend/dbus-interface/kylinvpnconnectitem.cpp b/src/backend/dbus-interface/kylinvpnconnectitem.cpp new file mode 100644 index 00000000..7eb0c5be --- /dev/null +++ b/src/backend/dbus-interface/kylinvpnconnectitem.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kylinvpnconnectitem.h" + + +KyVpnConnectItem::KyVpnConnectItem(QObject *parent) : QObject(parent) +{ + m_vpnName = ""; + m_vpnUuid = ""; + + m_vpnUser = ""; + m_vpnGateWay = ""; + + m_vpnIpv4Address = ""; + m_vpnIpv6Address = ""; + + m_vpnMppe = false; + m_vpnState = NetworkManager::VpnConnection::State::Disconnected; +} + +KyVpnConnectItem::~KyVpnConnectItem() +{ + +} diff --git a/src/backend/dbus-interface/kylinvpnconnectitem.h b/src/backend/dbus-interface/kylinvpnconnectitem.h new file mode 100644 index 00000000..704cc3ae --- /dev/null +++ b/src/backend/dbus-interface/kylinvpnconnectitem.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINVPNCONNECTITEM_H +#define KYLINVPNCONNECTITEM_H + +#include +#include +#include + +class KyVpnConnectItem : public QObject +{ + Q_OBJECT +public: + explicit KyVpnConnectItem(QObject *parent = nullptr); + ~KyVpnConnectItem(); + +public: + QString m_vpnName; + QString m_vpnUuid; + + QString m_vpnUser; + QString m_vpnGateWay; + + QString m_vpnIpv4Address; + QString m_vpnIpv6Address; + + bool m_vpnMppe; + NetworkManager::VpnConnection::State m_vpnState; +}; + + +#endif // KYLINVPNCONNECTITEM_H diff --git a/src/backend/dbus-interface/kylinvpnrequest.c b/src/backend/dbus-interface/kylinvpnrequest.c new file mode 100644 index 00000000..c294bd66 --- /dev/null +++ b/src/backend/dbus-interface/kylinvpnrequest.c @@ -0,0 +1,762 @@ +#include "kylinvpnrequest.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "gsystem-local-alloc.h" +#include "nma-vpn-password-dialog.h" +#include "nm-macros-internal.h" + +extern char **environ; + +/*****************************************************************************/ + +typedef struct { + char *name; + char *label; + char *value; + gboolean is_secret; + gboolean should_ask; +} EuiSecret; + +typedef struct { + char *uuid; + char *id; + char *service_type; + + guint watch_id; + GPid pid; + + int child_stdout; + GString *child_response; + GIOChannel *channel; + guint channel_eventid; + GVariantBuilder secrets_builder; + gboolean external_ui_mode; + + /* These are just for the external UI mode */ + EuiSecret *eui_secrets; +} RequestData; + +typedef struct { + SecretsRequest req; + RequestData *req_data; +} VpnSecretsInfo; + + +gint +_nm_utils_ascii_str_to_bool (const char *str, + gint default_value) +{ + gsize len; + char *s = NULL; + + if (!str) + return default_value; + + while (str[0] && g_ascii_isspace (str[0])) + str++; + + if (!str[0]) + return default_value; + + len = strlen (str); + if (g_ascii_isspace (str[len - 1])) { + s = g_strdup (str); + g_strchomp (s); + str = s; + } + + if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) + default_value = TRUE; + else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) + default_value = FALSE; + if (s) + g_free (s); + return default_value; +} + + +/*****************************************************************************/ + +static void request_data_free (RequestData *req_data); +static void complete_request (VpnSecretsInfo *info); + +/*****************************************************************************/ + +size_t +applet_vpn_request_get_secrets_size (void) +{ + return sizeof (VpnSecretsInfo); +} + +/*****************************************************************************/ + +static void +external_ui_add_secrets (VpnSecretsInfo *info) +{ + RequestData *req_data = info->req_data; + EuiSecret *secret; + guint i; + + for (i = 0; req_data->eui_secrets[i].name; i++) { + secret = &req_data->eui_secrets[i]; + if ( secret->is_secret + && secret->value + && secret->value[0]) { + g_variant_builder_add (&req_data->secrets_builder, "{ss}", + secret->name, + secret->value); + } + } +} + +static void +external_ui_dialog_response (GtkDialog *dialog, int response_id, gpointer user_data) +{ + VpnSecretsInfo *info = user_data; + RequestData *req_data = info->req_data; + NMAVpnPasswordDialog *vpn_dialog = NMA_VPN_PASSWORD_DIALOG (dialog); + EuiSecret *secret; + const char *value; + guint i_secret, i_pw; + + for (i_secret = 0, i_pw = 0; req_data->eui_secrets[i_secret].name; i_secret++) { + secret = &req_data->eui_secrets[i_secret]; + if ( secret->is_secret + && secret->should_ask) { + switch (i_pw) { + case 0: + value = nma_vpn_password_dialog_get_password (vpn_dialog); + break; + case 1: + value = nma_vpn_password_dialog_get_password_secondary (vpn_dialog); + break; + case 2: + value = nma_vpn_password_dialog_get_password_ternary (vpn_dialog); + break; + default: + continue; + } + g_free (secret->value); + secret->value = g_strdup (value); + i_pw++; + } + } + + gtk_widget_destroy (GTK_WIDGET (dialog)); + external_ui_add_secrets (info); + complete_request (info); +} + +static gboolean +external_ui_from_child_response (VpnSecretsInfo *info, GError **error) +{ + RequestData *req_data = info->req_data; + gs_unref_keyfile GKeyFile *keyfile = NULL; + gs_strfreev char **groups = NULL; + NMAVpnPasswordDialog *dialog = NULL; + gs_free char *version = NULL; + gs_free char *title = NULL; + gs_free char *message = NULL; + gsize num_groups; + guint num_ask = 0; + guint i_group, i_secret, i_pw; + + /* Parse response key file */ + keyfile = g_key_file_new (); + + if (!g_key_file_load_from_data (keyfile, + req_data->child_response->str, + req_data->child_response->len, + G_KEY_FILE_NONE, + error)) { + return FALSE; + } + + groups = g_key_file_get_groups (keyfile, &num_groups); + if (g_strcmp0 (groups[0], "VPN Plugin UI") != 0) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Expected [VPN Plugin UI]"); + return FALSE; + } + + version = g_key_file_get_string (keyfile, "VPN Plugin UI", "Version", error); + if (!version) + return FALSE; + if (strcmp (version, "2") != 0) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Expected Version=2"); + return FALSE; + } + + title = g_key_file_get_string (keyfile, "VPN Plugin UI", "Title", error); + if (!title) + return FALSE; + + message = g_key_file_get_string (keyfile, "VPN Plugin UI", "Description", error); + if (!message) + return FALSE; + + /* Create a secret instance for each group */ + req_data->eui_secrets = g_new0 (EuiSecret, num_groups); + for (i_group = 1, i_secret = 0; i_group < num_groups; i_group++) { + EuiSecret *secret = &req_data->eui_secrets[i_secret]; + const char *group = groups[i_group]; + char *label; + + label = g_key_file_get_string (keyfile, group, "Label", NULL); + if (!label) { + g_warning ("Skipping entry: no label\n"); + continue; + } + + secret->name = g_strdup (group); + secret->label = label; + secret->value = g_key_file_get_string (keyfile, group, "Value", NULL); + secret->is_secret = g_key_file_get_boolean (keyfile, group, "IsSecret", NULL); + secret->should_ask = g_key_file_get_boolean (keyfile, group, "ShouldAsk", NULL); + + i_secret++; + + if (secret->is_secret && secret->should_ask) + num_ask++; + } + + /* If there are any secrets that must be asked to user, + * create a dialog and display it. */ + if (num_ask > 0) { + dialog = (NMAVpnPasswordDialog *) nma_vpn_password_dialog_new (title, message, NULL); + g_object_ref_sink (dialog); + + nma_vpn_password_dialog_set_show_password (dialog, FALSE); + nma_vpn_password_dialog_set_show_password_secondary (dialog, FALSE); + nma_vpn_password_dialog_set_show_password_ternary (dialog, FALSE); + + for (i_secret = 0, i_pw = 0; req_data->eui_secrets[i_secret].name; i_secret++) { + EuiSecret *secret = &req_data->eui_secrets[i_secret]; + + if ( secret->is_secret + && secret->should_ask) { + switch (i_pw) { + case 0: + nma_vpn_password_dialog_set_show_password (dialog, TRUE); + nma_vpn_password_dialog_set_password_label (dialog, secret->label); + if (secret->value) + nma_vpn_password_dialog_set_password (dialog, secret->value); + break; + case 1: + nma_vpn_password_dialog_set_show_password_secondary (dialog, TRUE); + nma_vpn_password_dialog_set_password_secondary_label (dialog, secret->label); + if (secret->value) + nma_vpn_password_dialog_set_password_secondary (dialog, secret->value); + break; + case 2: + nma_vpn_password_dialog_set_show_password_ternary (dialog, TRUE); + nma_vpn_password_dialog_set_password_ternary_label (dialog, secret->label); + if (secret->value) + nma_vpn_password_dialog_set_password_ternary (dialog, secret->value); + break; + default: + g_warning ("Skipping entry: more than 3 passwords not supported\n"); + continue; + } + i_pw++; + } + } + g_signal_connect (dialog, + "response", + G_CALLBACK (external_ui_dialog_response), + info); + gtk_widget_show (GTK_WIDGET (dialog)); + return TRUE; + } + + /* Nothing to ask, return known secrets */ + external_ui_add_secrets (info); + complete_request (info); + return TRUE; +} + +/*****************************************************************************/ + +static void +complete_request (VpnSecretsInfo *info) +{ + SecretsRequest *req = (SecretsRequest *) info; + RequestData *req_data = info->req_data; + GVariantBuilder settings_builder, vpn_builder; + gs_unref_variant GVariant *settings = NULL; + + g_variant_builder_init (&settings_builder, NM_VARIANT_TYPE_CONNECTION); + g_variant_builder_init (&vpn_builder, NM_VARIANT_TYPE_SETTING); + + g_variant_builder_add (&vpn_builder, "{sv}", + NM_SETTING_VPN_SECRETS, + g_variant_builder_end (&req_data->secrets_builder)); + g_variant_builder_add (&settings_builder, "{sa{sv}}", + NM_SETTING_VPN_SETTING_NAME, + &vpn_builder); + settings = g_variant_builder_end (&settings_builder); + + applet_secrets_request_complete (req, settings, NULL); + applet_secrets_request_free (req); +} + +static void +process_child_response (VpnSecretsInfo *info) +{ + SecretsRequest *req = (SecretsRequest *) info; + RequestData *req_data = info->req_data; + gs_free_error GError *error = NULL; + + if (req_data->external_ui_mode) { + if (!external_ui_from_child_response (info, &error)) { + applet_secrets_request_complete (req, NULL, error); + applet_secrets_request_free (req); + } + } else { + char **lines = g_strsplit (req_data->child_response->str, "\n", -1); + int i; + + for (i = 0; lines[i] && *(lines[i]); i += 2) { + if (lines[i + 1] == NULL) + break; + g_variant_builder_add (&req_data->secrets_builder, "{ss}", lines[i], lines[i + 1]); + } + + g_strfreev (lines); + complete_request (info); + } +} + +static void +child_finished_cb (GPid pid, int status, gpointer user_data) +{ + VpnSecretsInfo *info = user_data; + SecretsRequest *req = (SecretsRequest *) info; + RequestData *req_data = info->req_data; + gs_free_error GError *error = NULL; + + req_data->pid = 0; + req_data->watch_id = 0; + + if (status) { + error = g_error_new (NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_USER_CANCELED, + "%s.%d (%s): canceled", __FILE__, __LINE__, __func__); + + applet_secrets_request_complete (req, NULL, error); + applet_secrets_request_free (req); + } else if (req_data->channel_eventid == 0) { + /* We now have both the child response and its exit status. Process it. */ + process_child_response (info); + } +} + +static gboolean +child_stdout_data_cb (GIOChannel *source, GIOCondition condition, gpointer user_data) +{ + SecretsRequest *req = user_data; + VpnSecretsInfo *info = (VpnSecretsInfo *) req; + RequestData *req_data = info->req_data; + GIOStatus status; + char buf[4096]; + size_t bytes_read; + gs_free_error GError *error = NULL; + + status = g_io_channel_read_chars (source, buf, sizeof (buf)-1, &bytes_read, &error); + switch (status) { + case G_IO_STATUS_ERROR: + req_data->channel_eventid = 0; + applet_secrets_request_complete (req, NULL, error); + applet_secrets_request_free (req); + return FALSE; + case G_IO_STATUS_EOF: + req_data->channel_eventid = 0; + if (req_data->pid == 0) { + /* We now have both the childe respons and + * its exit status. Process it. */ + process_child_response (info); + } + return FALSE; + case G_IO_STATUS_NORMAL: + g_string_append_len (req_data->child_response, buf, bytes_read); + break; + default: + /* What just happened... */ + g_return_val_if_reached (FALSE); + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +_str_append (GString *str, + const char *tag, + const char *val) +{ + const char *s; + gsize i; + + nm_assert (str); + nm_assert (tag && tag[0]); + nm_assert (val); + + g_string_append (str, tag); + g_string_append_c (str, '='); + + s = strchr (val, '\n'); + if (s) { + gs_free char *val2 = g_strdup (val); + + for (i = 0; val2[i]; i++) { + if (val2[i] == '\n') + val2[i] = ' '; + } + g_string_append (str, val2); + } else + g_string_append (str, val); + g_string_append_c (str, '\n'); +} + +static char * +connection_to_data (NMConnection *connection, + gsize *out_length, + GError **error) +{ + NMSettingVpn *s_vpn; + GString *buf; + const char **keys; + guint i, len; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + s_vpn = nm_connection_get_setting_vpn (connection); + if (!s_vpn) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + ("Connection had no VPN setting")); + return NULL; + } + + buf = g_string_new_len (NULL, 100); + + keys = nm_setting_vpn_get_data_keys (s_vpn, &len); + for (i = 0; i < len; i++) { + _str_append (buf, "DATA_KEY", keys[i]); + _str_append (buf, "DATA_VAL", nm_setting_vpn_get_data_item (s_vpn, keys[i])); + } + nm_clear_g_free (&keys); + + keys = nm_setting_vpn_get_secret_keys (s_vpn, &len); + for (i = 0; i < len; i++) { + _str_append (buf, "SECRET_KEY", keys[i]); + _str_append (buf, "SECRET_VAL", nm_setting_vpn_get_secret (s_vpn, keys[i])); + } + nm_clear_g_free (&keys); + + g_string_append (buf, "DONE\n\nQUIT\n\n"); + NM_SET_OUT (out_length, buf->len); + return g_string_free (buf, FALSE); +} + +/*****************************************************************************/ + +static gboolean +connection_to_fd (NMConnection *connection, + int fd, + GError **error) +{ + gs_free char *data = NULL; + gsize data_len; + gssize w; + int errsv; + + data = connection_to_data (connection, &data_len, error); + if (!data) + return FALSE; + +again: + w = write (fd, data, data_len); + if (w < 0) { + errsv = errno; + if (errsv == EINTR) + goto again; + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + ("Failed to write connection to VPN UI: %s (%d)"), g_strerror (errsv), errsv); + return FALSE; + } + + if ((gsize) w != data_len) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + ("Failed to write connection to VPN UI: incomplete write")); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +vpn_child_setup (gpointer user_data) +{ + /* We are in the child process at this point */ + pid_t pid = getpid (); + setpgid (pid, pid); +} + +static gboolean +auth_dialog_spawn (const char *con_id, + const char *con_uuid, + const char *const*hints, + const char *auth_dialog, + const char *service_type, + gboolean supports_hints, + gboolean external_ui_mode, + guint32 flags, + GPid *out_pid, + int *out_stdin, + int *out_stdout, + GError **error) +{ + gsize hints_len; + gsize i, j; + gs_free const char **argv = NULL; + gs_free const char **envp = NULL; + gsize environ_len; + + g_return_val_if_fail (con_id, FALSE); + g_return_val_if_fail (con_uuid, FALSE); + g_return_val_if_fail (auth_dialog, FALSE); + g_return_val_if_fail (service_type, FALSE); + g_return_val_if_fail (out_pid, FALSE); + g_return_val_if_fail (out_stdin, FALSE); + g_return_val_if_fail (out_stdout, FALSE); + + hints_len = NM_PTRARRAY_LEN (hints); + argv = g_new (const char *, 11 + (2 * hints_len)); + i = 0; + argv[i++] = auth_dialog; + argv[i++] = "-u"; + argv[i++] = con_uuid; + argv[i++] = "-n"; + argv[i++] = con_id; + argv[i++] = "-s"; + argv[i++] = service_type; + if (flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION) + argv[i++] = "-i"; + if (flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW) + argv[i++] = "-r"; + for (j = 0; supports_hints && (j < hints_len); j++) { + argv[i++] = "-t"; + argv[i++] = hints[j]; + } + if (external_ui_mode) + argv[i++] = "--external-ui-mode"; + nm_assert (i <= 10 + (2 * hints_len)); + argv[i++] = NULL; + + environ_len = NM_PTRARRAY_LEN (environ); + envp = g_new (const char *, environ_len + 1); + memcpy (envp, environ, sizeof (const char *) * environ_len); + for (i = 0, j = 0; i < environ_len; i++) { + const char *e = environ[i]; + + if (g_str_has_prefix (e, "G_MESSAGES_DEBUG=")) { + /* skip this environment variable. We interact with the auth-dialog via stdout. + * G_MESSAGES_DEBUG may enable additional debugging messages from GTK. */ + continue; + } + envp[j++] = e; + } + envp[j] = NULL; + + if (!g_spawn_async_with_pipes (NULL, + (char **) argv, + (char **) envp, + G_SPAWN_DO_NOT_REAP_CHILD, + vpn_child_setup, + NULL, + out_pid, + out_stdin, + out_stdout, + NULL, + error)) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + +static void +free_vpn_secrets_info (SecretsRequest *req) +{ + request_data_free (((VpnSecretsInfo *) req)->req_data); +} + +gboolean +applet_vpn_request_get_secrets (SecretsRequest *req, GError **error) +{ + VpnSecretsInfo *info = (VpnSecretsInfo *) req; + RequestData *req_data; + NMSettingConnection *s_con; + NMSettingVpn *s_vpn; + const char *connection_type; + const char *service_type; + const char *auth_dialog; + gs_unref_object NMVpnPluginInfo *plugin = NULL; + int child_stdin; + + applet_secrets_request_set_free_func (req, free_vpn_secrets_info); + + s_con = nm_connection_get_setting_connection (req->connection); + s_vpn = nm_connection_get_setting_vpn (req->connection); + + connection_type = nm_setting_connection_get_connection_type (s_con); + g_return_val_if_fail (nm_streq0 (connection_type, NM_SETTING_VPN_SETTING_NAME), FALSE); + + service_type = nm_setting_vpn_get_service_type (s_vpn); + g_return_val_if_fail (service_type, FALSE); + + plugin = nm_vpn_plugin_info_new_search_file (NULL, service_type); + auth_dialog = plugin ? nm_vpn_plugin_info_get_auth_dialog (plugin) : NULL; + if (!auth_dialog) { + g_set_error (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Could not find the authentication dialog for VPN connection type '%s'", + service_type); + return FALSE; + } + + info->req_data = g_slice_new0 (RequestData); + if (!info->req_data) { + g_set_error_literal (error, + NM_SECRET_AGENT_ERROR, + NM_SECRET_AGENT_ERROR_FAILED, + "Could not create VPN secrets request object"); + return FALSE; + } + req_data = info->req_data; + + g_variant_builder_init (&req_data->secrets_builder, G_VARIANT_TYPE ("a{ss}")); + + req_data->external_ui_mode = _nm_utils_ascii_str_to_bool ( + nm_vpn_plugin_info_lookup_property (plugin, + "GNOME", + "supports-external-ui-mode"), + FALSE); + + if (!auth_dialog_spawn (nm_setting_connection_get_id (s_con), + nm_setting_connection_get_uuid (s_con), + (const char *const*) req->hints, + auth_dialog, + service_type, + nm_vpn_plugin_info_supports_hints (plugin), + req_data->external_ui_mode, + req->flags, + &req_data->pid, + &child_stdin, + &req_data->child_stdout, + error)) + return FALSE; + + /* catch when child is reaped */ + req_data->watch_id = g_child_watch_add (req_data->pid, child_finished_cb, info); + + /* listen to what child has to say */ + req_data->channel = g_io_channel_unix_new (req_data->child_stdout); + req_data->child_response = g_string_sized_new (4096); + req_data->channel_eventid = g_io_add_watch (req_data->channel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + child_stdout_data_cb, + info); + + if (!connection_to_fd (req->connection, child_stdin, error)) + return FALSE; + close (child_stdin); + + g_io_channel_set_encoding (req_data->channel, NULL, NULL); + + /* Dump parts of the connection to the child */ + return TRUE; +} + +/*****************************************************************************/ + +static gboolean +ensure_killed (gpointer data) +{ + pid_t pid = GPOINTER_TO_INT (data); + + if (kill (pid, 0) == 0) + kill (pid, SIGKILL); + /* ensure the child is reaped */ + waitpid (pid, NULL, 0); + return FALSE; +} + +static void +request_data_free (RequestData *req_data) +{ + guint i; + + if (!req_data) + return; + + g_free (req_data->uuid); + g_free (req_data->id); + g_free (req_data->service_type); + + nm_clear_g_source (&req_data->watch_id); + + nm_clear_g_source (&req_data->channel_eventid); + if (req_data->channel) + g_io_channel_unref (req_data->channel); + + if (req_data->pid) { + g_spawn_close_pid (req_data->pid); + if (kill (req_data->pid, SIGTERM) == 0) + g_timeout_add_seconds (2, ensure_killed, GINT_TO_POINTER (req_data->pid)); + else { + kill (req_data->pid, SIGKILL); + /* ensure the child is reaped */ + waitpid (req_data->pid, NULL, 0); + } + } + + if (req_data->child_response) + g_string_free (req_data->child_response, TRUE); + + g_variant_builder_clear (&req_data->secrets_builder); + + if (req_data->eui_secrets) { + for (i = 0; req_data->eui_secrets[i].name; i++) { + g_free (req_data->eui_secrets[i].name); + g_free (req_data->eui_secrets[i].label); + g_free (req_data->eui_secrets[i].value); + } + g_free (req_data->eui_secrets); + } + + g_slice_free (RequestData, req_data); +} diff --git a/src/backend/dbus-interface/kylinvpnrequest.h b/src/backend/dbus-interface/kylinvpnrequest.h new file mode 100644 index 00000000..266f085e --- /dev/null +++ b/src/backend/dbus-interface/kylinvpnrequest.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLIN_VPN_REQUEST_H +#define KYLIN_VPN_REQUEST_H + +#include +#include "kylinagent.h" + +typedef struct _SecretsRequest SecretsRequest; +typedef void (*SecretsRequestFreeFunc) (SecretsRequest *req); +struct _SecretsRequest { + size_t totsize; + gpointer reqid; + char *setting_name; + char **hints; + guint32 flags; + AppletAgent *agent; + AppletAgentSecretsCallback callback; + gpointer callback_data; + + NMConnection *connection; + + /* Class-specific stuff */ + SecretsRequestFreeFunc free_func; +}; + + +size_t applet_vpn_request_get_secrets_size(void); + +gboolean applet_vpn_request_get_secrets(SecretsRequest *req, GError **error); + +#endif /* APPLET_VPN_REQUEST_H */ diff --git a/src/backend/dbus-interface/kylinwiredconnectoperation.cpp b/src/backend/dbus-interface/kylinwiredconnectoperation.cpp new file mode 100644 index 00000000..f3231949 --- /dev/null +++ b/src/backend/dbus-interface/kylinwiredconnectoperation.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include + +KyWiredConnectOperation::KyWiredConnectOperation(QObject *parent) : KyConnectOperation(parent) +{ + connect(m_networkResourceInstance, &KyNetworkResourceManager::wiredEnabledChanged, + this, &KyWiredConnectOperation::wiredEnabledChanged); +} + +KyWiredConnectOperation::~KyWiredConnectOperation() +{ +} + +void KyWiredConnectOperation::setWiredEnabled(bool enabled) +{ + setWiredEnabledByGDbus(enabled); +} + +bool KyWiredConnectOperation::getWiredEnabled() +{ + return getWiredEnabledByGDbus(); +} + +void KyWiredConnectOperation::createWiredConnect(KyConnectSetting &connectSettingsInfo) +{ + qDebug()<<"[KyWiredConnectOperation]" << "create connect "; + connectSettingsInfo.dumpInfo(); + + NetworkManager::ConnectionSettings::Ptr wiredConnectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wired)); + connectSettingSet(wiredConnectionSettings, connectSettingsInfo); + + NetworkManager::Ipv4Setting::Ptr ipv4Setting = wiredConnectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + ipv4SettingSet(ipv4Setting, connectSettingsInfo); + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = wiredConnectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + ipv6SettingSet(ipv6Setting, connectSettingsInfo); + + NetworkManager::WiredSetting::Ptr wiredSetting = wiredConnectionSettings->setting(NetworkManager::Setting::Wired).dynamicCast(); + wiredSetting->setInitialized(true); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addConnection(wiredConnectionSettings->toMap()), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("create wired connection failed: ") + watcher->error().message(); + qWarning()<createConnectionError(errorMessage); + } else { + qDebug()<<"create wired connect complete"; + } + watcher->deleteLater(); + }); + + return; +} + +void KyWiredConnectOperation::updateWiredConnect(const QString &connectUuid, const KyConnectSetting &connectSettingsInfo) +{ + qDebug()<<"update connect"<settings(); + updateConnect(connectSettingPtr, connectSettingsInfo); + + NMVariantMapMap mapmap1 = connectSettingPtr->toMap(); + if (mapmap1.contains("ipv4")) { + QVariantMap map1 = mapmap1.value(QLatin1String("ipv4")); + bool isAuto = false; + if (map1.contains("method") && map1["method"] == "auto") { + qDebug() << "[KyWiredConnectOperation] set ipv4 method auto, clear address-data && addresses && gateway"; + isAuto = true; + } + if (isAuto) { + if (map1.contains("address-data")) { + map1.remove("address-data"); + } + if (map1.contains("addresses")) { + map1.remove("addresses"); + } + if (map1.contains("gateway")) { + map1.remove("gateway"); + } + } + mapmap1["ipv4"] = map1; + } + + if (mapmap1.contains("ipv6")) { + QVariantMap map2 = mapmap1.value(QLatin1String("ipv6")); + bool isAuto = false; + if (map2.contains("method") && map2["method"] == "auto") { + qDebug() << "[KyWiredConnectOperation] set ipv6 method auto, clear address-data && addresses && gateway"; + isAuto = true; + } + if (isAuto) { + if (map2.contains("address-data")) { + map2.remove("address-data"); + } + if (map2.contains("addresses")) { + map2.remove("addresses"); + } + if (map2.contains("gateway")) { + map2.remove("gateway"); + } + } + mapmap1["ipv6"] = map2; + } + + connectPtr->update(mapmap1); + + return ; +} + +void KyWiredConnectOperation::deleteWiredConnect(const QString &connectUuid) +{ + qDebug()<<"delete wired connect uuid " << connectUuid; + + deleteConnect(connectUuid); + + return ; +} + +void KyWiredConnectOperation::activateWiredConnection(const QString connectUuid, const QString devName) +{ + activateConnection(connectUuid, devName); + return ; +} + +void KyWiredConnectOperation::deactivateWiredConnection(const QString activeConnectName, const QString &activeConnectUuid) +{ + qDebug()<<"deactivetate connect name"<settings()->connectionType()) { + QString errorMessage = tr("the connect type is") + + connectPtr->settings()->connectionType() + + tr(", but it is not vpn"); + qWarning()<path(); + connectName = connectPtr->name(); + //deviceName = connectPtr->settings()->interfaceName(); + specificObject = deviceIdentifier = QStringLiteral("/"); + + qDebug() <<"active wired connect: path "<< connectPath + << "device identify " << deviceIdentifier + << "connect name " << connectName + // << "device name" << deviceName + << "specific parameter"<< specificObject; + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::activateConnection(connectPath, deviceIdentifier, specificObject), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this, connectName] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("activate vpn connection failed: ") + watcher->error().message(); + qWarning()<activateConnectionError(errorMessage); + } else { + qWarning()<<"active vpn connect complete."; + } + + watcher->deleteLater(); + }); + + return; +} + +void KyWiredConnectOperation::saveActiveConnection(QString &deviceName, QString &connectUuid) +{ + QSettings *p_settings = new QSettings(WIRED_NETWORK_STATE_CONF_FILE, QSettings::IniFormat); + + QString settingValue = p_settings->value(deviceName).toString(); + if (settingValue.isEmpty()) { + p_settings->setValue(deviceName, connectUuid); + p_settings->sync(); + } + + delete p_settings; + p_settings = nullptr; + + return; +} + +void KyWiredConnectOperation::getActiveConnection(QString &deviceName, QString &connectUuid) +{ + QSettings *p_settings = new QSettings(WIRED_NETWORK_STATE_CONF_FILE, QSettings::IniFormat); + + connectUuid = p_settings->value(deviceName).toString(); + p_settings->remove(deviceName); + + delete p_settings; + p_settings = nullptr; + + return; +} + +int KyWiredConnectOperation::closeWiredNetworkWithDevice(QString deviceName) +{ + NetworkManager::Device::Ptr wiredDevicePtr = + m_networkResourceInstance->findDeviceInterface(deviceName); + + if (wiredDevicePtr.isNull()) { + qWarning()<<"[KyWiredConnectOperation]"<<"the network device" << deviceName <<"is not exist."; + return -ENXIO; + } + + if (NetworkManager::Device::Type::Ethernet != wiredDevicePtr->type()) { + qWarning()<<"[KyWiredConnectOperation]"<<"the device type" + << wiredDevicePtr->type() <<"is not Ethernet."; + return -EINVAL; + } + + NetworkManager::ActiveConnection::Ptr activeConnectPtr = wiredDevicePtr->activeConnection(); + if (nullptr != activeConnectPtr) { + QString activeConnectUuid = activeConnectPtr->uuid(); + if (!activeConnectUuid.isEmpty()) { + qDebug()<<"[KyWiredConnectOperation]" <<"close wired network save connection uuid" + << activeConnectUuid <<"device name " << deviceName; + saveActiveConnection(deviceName, activeConnectUuid); + } + } + + //wiredDevicePtr->setAutoconnect(false); + wiredDevicePtr->disconnectInterface(); + + return 0; +} + +int KyWiredConnectOperation::openWiredNetworkWithDevice(QString deviceName) +{ + NetworkManager::Device::Ptr wiredDevicePtr = + m_networkResourceInstance->findDeviceInterface(deviceName); + + if (wiredDevicePtr.isNull() || !wiredDevicePtr->isValid()) { + qWarning()<<"[KyWiredConnectOperation]"<<"the network device" << deviceName <<"is not exist."; + return -ENXIO; + } + + if (NetworkManager::Device::Type::Ethernet != wiredDevicePtr->type()) { + qWarning()<<"[KyWiredConnectOperation]"<<"the device type" + << wiredDevicePtr->type() <<"is not Ethernet."; + return -EINVAL; + } + + NetworkManager::WiredDevice *p_wiredDevice = + qobject_cast(wiredDevicePtr.data()); + + if (p_wiredDevice->carrier()) { + QString connectUuid; + getActiveConnection(deviceName, connectUuid); + if (!connectUuid.isEmpty()) { + qDebug()<<"[KyWiredConnectOperation]" << "open wired network active connection" + << connectUuid <<"device name" << deviceName; + activateConnection(connectUuid, deviceName); + } + } + + wiredDevicePtr->setAutoconnect(true); + + return 0; +} diff --git a/src/backend/dbus-interface/kylinwiredconnectoperation.h b/src/backend/dbus-interface/kylinwiredconnectoperation.h new file mode 100644 index 00000000..67f416c6 --- /dev/null +++ b/src/backend/dbus-interface/kylinwiredconnectoperation.h @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINWIREDCONNECTOPERATION_H +#define KYLINWIREDCONNECTOPERATION_H + +#include +#include + +#include "kylinnetworkresourcemanager.h" +#include "kylinconnectsetting.h" +#include "kylinconnectoperation.h" + +const QString WIRED_NETWORK_STATE_CONF_FILE = QDir::homePath() + "/.config/ukui/kylin-nm-wired.ini"; + +class KyWiredConnectOperation : public KyConnectOperation +{ + Q_OBJECT +public: + explicit KyWiredConnectOperation(QObject *parent = nullptr); + ~KyWiredConnectOperation(); + +public: + //无线开关 + void setWiredEnabled(bool enabled); + bool getWiredEnabled(); + + void createWiredConnect(KyConnectSetting &connectSettingsInfo); + void updateWiredConnect(const QString &connectUuid, const KyConnectSetting &connectSettingsInfo); + void deleteWiredConnect(const QString &connectUuid); + void activateWiredConnection(const QString connectUuid, const QString devName); + void activateVpnConnection(const QString connectUuid); + void deactivateWiredConnection(const QString activeConnectName, const QString &activeConnectUuid); + + int closeWiredNetworkWithDevice(QString deviceName); + int openWiredNetworkWithDevice(QString deviceName); + +Q_SIGNALS: + void wiredEnabledChanged(bool); + +private: + void getActiveConnection(QString &deviceName, QString &connectUuid); + void saveActiveConnection(QString &deviceName, QString &connectUuid); +}; + +#endif // KYLINWIREDCONNECTOPERATION_H diff --git a/src/backend/dbus-interface/kywirelessconnectoperation.cpp b/src/backend/dbus-interface/kywirelessconnectoperation.cpp new file mode 100644 index 00000000..9f4b2bea --- /dev/null +++ b/src/backend/dbus-interface/kywirelessconnectoperation.cpp @@ -0,0 +1,1077 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kywirelessconnectoperation.h" +#include "kylinutil.h" + +#include + +#define PSK_SETTING_NAME "802-11-wireless-security" +#define PRIVATE_PSK_SETTING_NAME "802-1x" + +NetworkManager::ConnectionSettings::Ptr assembleWpaXPskSettings(NetworkManager::AccessPoint::Ptr accessPoint, QString &psk, bool isAutoConnect) +{ + QByteArray rawSsid = accessPoint->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + + NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings{NetworkManager::ConnectionSettings::Wireless}}; + settings->setId(wifiSsid); + settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + settings->setAutoconnect(isAutoConnect); + //Note: workaround for wrongly (randomly) initialized gateway-ping-timeout + settings->setGatewayPingTimeout(0); + + NetworkManager::WirelessSetting::Ptr wifi_sett + = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); + wifi_sett->setInitialized(true); + wifi_sett->setSsid(rawSsid); + wifi_sett->setSecurity("802-11-wireless-security"); + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + if (NetworkManager::AccessPoint::Adhoc == accessPoint->mode()) { + wifi_sett->setMode(NetworkManager::WirelessSetting::Adhoc); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); + } else { + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); + } + if (!psk.isEmpty()) { + security_sett->setPsk(psk); + } + + return settings; +} + +NetworkManager::ConnectionSettings::Ptr assembleSaeSettings(NetworkManager::AccessPoint::Ptr accessPoint, QString &psk, bool isAutoConnect) +{ + QByteArray rawSsid = accessPoint->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + + NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings{NetworkManager::ConnectionSettings::Wireless}}; + settings->setId(wifiSsid); + settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + settings->setAutoconnect(isAutoConnect); + //Note: workaround for wrongly (randomly) initialized gateway-ping-timeout + settings->setGatewayPingTimeout(0); + + NetworkManager::WirelessSetting::Ptr wifi_sett + = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); + wifi_sett->setInitialized(true); + wifi_sett->setSsid(rawSsid); + wifi_sett->setSecurity("802-11-wireless-security"); + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + if (NetworkManager::AccessPoint::Adhoc == accessPoint->mode()) { + wifi_sett->setMode(NetworkManager::WirelessSetting::Adhoc); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaNone); + } else { + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::SAE); + } + if (!psk.isEmpty()) { + security_sett->setPsk(psk); + } + + return settings; +} + +NetworkManager::ConnectionSettings::Ptr assembleWirelessSettings( + const NetworkManager::AccessPoint::Ptr accessPointPtr, + const KyWirelessConnectSetting &connSettingInfo, + bool isHidden) +{ + QByteArray rawSsid; + if (nullptr == accessPointPtr || accessPointPtr.isNull()) { + rawSsid = connSettingInfo.m_ssid.toUtf8(); + } else { + rawSsid = accessPointPtr->rawSsid(); + } + + NetworkManager::ConnectionSettings::Ptr settings{new NetworkManager::ConnectionSettings{NetworkManager::ConnectionSettings::Wireless}}; + settings->setId(connSettingInfo.m_connectName); + settings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + settings->setAutoconnect(connSettingInfo.isAutoConnect); + //Note: workaround for wrongly (randomly) initialized gateway-ping-timeout + settings->setGatewayPingTimeout(0); + settings->setInterfaceName(connSettingInfo.m_ifaceName); + + NetworkManager::WirelessSetting::Ptr wifi_sett + = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); + wifi_sett->setInitialized(true); + wifi_sett->setSsid(rawSsid); + wifi_sett->setSecurity("802-11-wireless-security"); + wifi_sett->setHidden(isHidden); + + if (connSettingInfo.m_type != KyKeyMgmt::WpaNone && connSettingInfo.m_type != KyKeyMgmt::Unknown) + { + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = settings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + security_sett->setInitialized(true); + security_sett->setKeyMgmt((NetworkManager::WirelessSecuritySetting::KeyMgmt)connSettingInfo.m_type); + if (KyKeyMgmt::SAE == connSettingInfo.m_type || KyKeyMgmt::WpaPsk == connSettingInfo.m_type) + { + security_sett->setPsk(connSettingInfo.m_psk); + } + } + return settings; +} + + +KyWirelessConnectOperation::KyWirelessConnectOperation(QObject *parent) : KyConnectOperation(parent) +{ + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiEnabledChanged, + this, &KyWirelessConnectOperation::wifiEnabledChanged); + connect(this, &KyWirelessConnectOperation::enabledWirelessNetwork, + m_networkResourceInstance, &KyNetworkResourceManager::setWirelessNetworkEnabled, Qt::ConnectionType::QueuedConnection); +} + +KyWirelessConnectOperation::~KyWirelessConnectOperation() +{ + m_networkResourceInstance = nullptr; +} + +void KyWirelessConnectOperation::activeWirelessConnect(QString devIfaceName, QString connUuid) +{ + activateConnection(connUuid, devIfaceName); + return; +} + +void KyWirelessConnectOperation::deActivateWirelessConnection(const QString activeConnectName, const QString &activeConnectUuid) +{ + deactivateConnection(activeConnectName, activeConnectUuid); + return; +} + +//普通wifi +void KyWirelessConnectOperation::addConnect(const KyWirelessConnectSetting &connSettingInfo) +{ + NetworkManager::WirelessNetwork::Ptr wifiNet = + checkWifiNetExist(connSettingInfo.m_ssid, connSettingInfo.m_ifaceName); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + + " is not exsit in " + connSettingInfo.m_ifaceName; + qWarning()<referenceAccessPoint(); + + NetworkManager::ConnectionSettings::Ptr connSetting = + assembleWirelessSettings(accessPointPtr, connSettingInfo, false); + setIpv4AndIpv6Setting(connSetting, connSettingInfo); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addConnection(connSetting->toMap()), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("create wireless connection failed: ") + watcher->error().message(); + qWarning()<createConnectionError(errorMessage); + } else { + qDebug()<<"create wireless connect complete"; + } + watcher->deleteLater(); + }); + + return; +} +//tls +void KyWirelessConnectOperation::addTlsConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodTlsInfo &tlsInfo) +{ + NetworkManager::WirelessNetwork::Ptr wifiNet = + checkWifiNetExist(connSettingInfo.m_ssid, connSettingInfo.m_ifaceName); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + + " is not exsit in " + connSettingInfo.m_ifaceName; + qWarning()<referenceAccessPoint(); + NetworkManager::ConnectionSettings::Ptr connSetting = + assembleWirelessSettings(accessPointPtr, connSettingInfo, false); + setIpv4AndIpv6Setting(connSetting, connSettingInfo); + assembleEapMethodTlsSettings(connSetting, tlsInfo); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addConnection(connSetting->toMap()), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("create wireless tls connection failed: ") + watcher->error().message(); + qWarning()<createConnectionError(errorMessage); + } else { + qDebug()<<"create wireless connect complete"; + } + watcher->deleteLater(); + }); + + return; +} +//peap +void KyWirelessConnectOperation::addPeapConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodPeapInfo &peapInfo) +{ + NetworkManager::WirelessNetwork::Ptr wifiNet = + checkWifiNetExist(connSettingInfo.m_ssid, connSettingInfo.m_ifaceName); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + + " is not exsit in " + connSettingInfo.m_ifaceName; + qWarning()<referenceAccessPoint(); + NetworkManager::ConnectionSettings::Ptr connSetting = + assembleWirelessSettings(accessPointPtr, connSettingInfo, false); + setIpv4AndIpv6Setting(connSetting, connSettingInfo); + assembleEapMethodPeapSettings(connSetting, peapInfo); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addConnection(connSetting->toMap()), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("create wireless peap connection failed: ") + watcher->error().message(); + qWarning()<createConnectionError(errorMessage); + } else { + qDebug()<<"create wireless connect complete"; + } + watcher->deleteLater(); + }); + + return; +} + +void KyWirelessConnectOperation::addTtlsConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodTtlsInfo &ttlsInfo) +{ + NetworkManager::WirelessNetwork::Ptr wifiNet = + checkWifiNetExist(connSettingInfo.m_ssid, connSettingInfo.m_ifaceName); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + + " is not exsit in " + connSettingInfo.m_ifaceName; + qWarning()<referenceAccessPoint(); + NetworkManager::ConnectionSettings::Ptr connSetting = + assembleWirelessSettings(accessPointPtr, connSettingInfo, false); + setIpv4AndIpv6Setting(connSetting, connSettingInfo); + assembleEapMethodTtlsSettings(connSetting, ttlsInfo); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addConnection(connSetting->toMap()), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this](QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("create wireless ttls connection failed: ") + watcher->error().message(); + qWarning()<createConnectionError(errorMessage); + } else { + qDebug()<<"create wireless connect complete"; + } + watcher->deleteLater(); + }); + + return; +} + +void KyWirelessConnectOperation::setWirelessAutoConnect(const QString &uuid, bool bAutoConnect) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + setAutoConnect(connectionSettings, bAutoConnect); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::deleteWirelessConnect(const QString &connectUuid) +{ + qDebug()<<"delete wireless connect uuid " << connectUuid; + + deleteConnect(connectUuid); + + return ; +} + +QString KyWirelessConnectOperation::getPsk(const QString &connectUuid) +{ + qDebug() << "getPsk" << connectUuid; + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(connectUuid); + if (connectPtr.isNull()) { + QString errorMessage = tr("it can not find connection") + connectUuid; + qWarning()< reply = connectPtr->secrets(PSK_SETTING_NAME); + QMap map(reply.value()); + if (map.contains("802-11-wireless-security") + && map.value("802-11-wireless-security").contains("psk")) { + QString psk = map.value("802-11-wireless-security").value("psk").toString(); + return psk; + } + return ""; +} + +QString KyWirelessConnectOperation::getPrivateKeyPassword(const QString &connectUuid) +{ + qDebug() << "getPsk" << connectUuid; + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(connectUuid); + if (connectPtr.isNull()) { + QString errorMessage = tr("it can not find connection") + connectUuid; + qWarning()< reply = connectPtr->secrets(PRIVATE_PSK_SETTING_NAME); + QMap map(reply.value()); + if (map.contains("802-1x") + && map.value("802-1x").contains("private-key-password")) { + QString psk = map.value("802-1x").value("private-key-password").toString(); + return psk; + } + return ""; +} + +QString KyWirelessConnectOperation::get8021xPassword(const QString &connectUuid) +{ + qDebug() << "getPsk" << connectUuid; + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(connectUuid); + if (connectPtr.isNull()) { + QString errorMessage = tr("it can not find connection") + connectUuid; + qWarning()< reply = connectPtr->secrets(PRIVATE_PSK_SETTING_NAME); + QMap map(reply.value()); + if (map.contains("802-1x") && map.value("802-1x").contains("password")) + { + QString psk = map.value("802-1x").value("password").toString(); + return psk; + } + return ""; +} + +void KyWirelessConnectOperation::updateIpv4AndIpv6SettingInfo(const QString &uuid, const KyConnectSetting &connectSettingsInfo) +{ + qDebug()<<"updateIpv4AndIpv6SettingInfo wireless connect uuid " << uuid; + + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + + setIpv4AndIpv6Setting(connectionSettings,connectSettingsInfo); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::updateWirelessPersonalConnect(const QString &uuid, const KyWirelessConnectSetting &connSettingInfo, bool bPwdChange) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + + if (connSettingInfo.m_type != Unknown &&connSettingInfo.m_type != WpaNone && connSettingInfo.m_type != WpaPsk && connSettingInfo.m_type != SAE) + { + qDebug() << "updateWirelessPersonalConnect " << connSettingInfo.m_type << " not support"; + return; + } + + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connectionSettings->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + wifi_8021x_sett->setInitialized(false); + + updateWirelessSecu(connectionSettings, connSettingInfo, bPwdChange); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::updateWirelessEnterPriseTlsConnect(const QString &uuid, const KyEapMethodTlsInfo &tlsInfo) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (connectPtr.isNull()) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + + setWirelessSecuWpaXEap(connectionSettings); + modifyEapMethodTlsSettings(connectionSettings, tlsInfo); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::updateWirelessEnterPrisePeapConnect(const QString &uuid, const KyEapMethodPeapInfo &peapInfo) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + + setWirelessSecuWpaXEap(connectionSettings); + modifyEapMethodPeapSettings(connectionSettings, peapInfo); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::updateWirelessEnterPriseTtlsConnect(const QString &uuid, const KyEapMethodTtlsInfo &ttlsInfo) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (nullptr == connectPtr) { + QString errorMessage = tr("it can not find connection") + uuid; + qWarning()<settings(); + + setWirelessSecuWpaXEap(connectionSettings); + modifyEapMethodTtlsSettings(connectionSettings, ttlsInfo); + connectPtr->update(connectionSettings->toMap()); + return; +} + +void KyWirelessConnectOperation::addAndActiveWirelessConnect(QString & devIface,KyWirelessConnectSetting &connSettingInfo,bool isHidden) +{ + qDebug() << "addAndActiveWirelessConnect" << connSettingInfo.m_ssid << devIface <findDeviceInterface(devIface); + if (dev.isNull()) { + Q_EMIT addAndActivateConnectionError("can not find device"); + return; + } + + qDebug() << "addAndActiveWirelessConnect device " << devIface << " exist"; + dev_uni = dev->uni(); + auto spec_dev = dev->as(); + if (!isHidden) { + qDebug() << "start assemble"; + auto access_point = wifiNet->referenceAccessPoint(); + conn_uni = access_point->uni(); + conn_name = access_point->ssid(); + spec_object = conn_uni; + + NetworkManager::WirelessSecurityType sec_type = NetworkManager::findBestWirelessSecurity(spec_dev->wirelessCapabilities() + , true, (spec_dev->mode() == NetworkManager::WirelessDevice::Adhoc) + , access_point->capabilities(), access_point->wpaFlags(), access_point->rsnFlags()); + + qDebug() << "findBestWirelessSecurity type "<< sec_type; + + NetworkManager::ConnectionSettings::Ptr settings = nullptr; + switch (sec_type) + { + case NetworkManager::UnknownSecurity: + qWarning() << QStringLiteral("unknown security to use for '%1'").arg(conn_name); + case NetworkManager::NoneSecurity: + //nothing to do + break; + case NetworkManager::WpaPsk: + case NetworkManager::Wpa2Psk: + settings = assembleWpaXPskSettings(access_point, connSettingInfo.m_psk, connSettingInfo.isAutoConnect); + if (nullptr != settings) { + map_settings = settings->toMap(); + } else { + qWarning() << QStringLiteral("connection settings assembly for '%1' failed, abandoning activation...").arg(conn_name); + return; + } + break; + //TODO: other types... + case NetworkManager::SAE: + settings = assembleSaeSettings(access_point, connSettingInfo.m_psk, connSettingInfo.isAutoConnect); + if (nullptr != settings) { + map_settings = settings->toMap(); + } else { + qWarning() << QStringLiteral("connection settings assembly for '%1' failed, abandoning activation...").arg(conn_name); + return; + } + break; + default: + qDebug() << "addAndActiveWirelessConnect not support"; + break; + } + + qDebug() << "finish assemble"; + } else { + qDebug() << "start assembleWirelessSettings"; + map_settings = assembleWirelessSettings(nullptr, connSettingInfo, isHidden)->toMap(); + qDebug() << "finish assembleWirelessSettings"; + } + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(map_settings, dev_uni, spec_object), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [&] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = watcher->error().message(); + qDebug() << "activation of connection failed " << errorMessage; + Q_EMIT addAndActivateConnectionError(errorMessage); + } + watcher->deleteLater(); + }); +} + +void KyWirelessConnectOperation::requestWirelessScan() +{ + for (auto const & dev : m_networkResourceInstance->m_devices) { + auto spec_dev = dev->as(); + if (nullptr != spec_dev) { + m_networkResourceInstance->requestScan(spec_dev); + } + } +} + +void KyWirelessConnectOperation::addAndActiveWirelessEnterPriseTlsConnect(KyEapMethodTlsInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden) +{ + QString conn_uni; + QString dev_uni; + QString spec_object; + NMVariantMapMap map_settings; + NetworkManager::AccessPoint::Ptr accessPointPtr = nullptr; + + if (!isHidden) { + NetworkManager::WirelessNetwork::Ptr wifiNet = checkWifiNetExist(connSettingInfo.m_ssid, devIface); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + " is not exsit in " + devIface; + qWarning()<referenceAccessPoint(); + conn_uni = accessPointPtr->uni(); + spec_object = conn_uni; + } + + auto dev = m_networkResourceInstance->findDeviceInterface(devIface); + if (dev.isNull()) { + Q_EMIT addAndActivateConnectionError("can not find device"); + return; + } + dev_uni = dev->uni(); + + NetworkManager::ConnectionSettings::Ptr settings = assembleWirelessSettings(accessPointPtr, connSettingInfo, isHidden); + assembleEapMethodTlsSettings(settings, info); + + if(settings.isNull()) { + qDebug() << "assembleEapMethodTlsSettings failed"; + return; + } + + map_settings = settings->toMap(); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(map_settings, dev_uni, spec_object), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [&] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = watcher->error().message(); + qDebug() << "addAndActiveWirelessEnterPriseTlsConnect failed " << errorMessage; + Q_EMIT addAndActivateConnectionError(errorMessage); + } + watcher->deleteLater(); + }); + +} + +void KyWirelessConnectOperation::addAndActiveWirelessEnterPrisePeapConnect(KyEapMethodPeapInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden) +{ + qDebug() <<"addAndActiveWirelessEnterPrisePeapConnect"; + QString conn_uni; + QString dev_uni; + QString spec_object; + NMVariantMapMap map_settings; + NetworkManager::AccessPoint::Ptr accessPointPtr = nullptr; + + if (!isHidden) { + NetworkManager::WirelessNetwork::Ptr wifiNet = checkWifiNetExist(connSettingInfo.m_ssid, devIface); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + " is not exsit in " + devIface; + qWarning()<referenceAccessPoint(); + conn_uni = accessPointPtr->uni(); + spec_object = conn_uni; + } + + auto dev = m_networkResourceInstance->findDeviceInterface(devIface); + if (dev.isNull()) { + Q_EMIT addAndActivateConnectionError("can not find device"); + return; + } + dev_uni = dev->uni(); + + NetworkManager::ConnectionSettings::Ptr settings = + assembleWirelessSettings(accessPointPtr, connSettingInfo, isHidden); + assembleEapMethodPeapSettings(settings, info); + + if(settings.isNull()) { + qDebug() << "assembleEapMethodPeapSettings failed"; + return; + } + map_settings = settings->toMap(); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(map_settings, dev_uni, spec_object), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [&] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = watcher->error().message(); + qDebug() << "addAndActiveWirelessEnterPrisePeapConnect failed " << errorMessage; + Q_EMIT addAndActivateConnectionError(errorMessage); + } + watcher->deleteLater(); + }); + +} + +void KyWirelessConnectOperation::addAndActiveWirelessEnterPriseTtlsConnect(KyEapMethodTtlsInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden) +{ + QString conn_uni; + QString dev_uni; + QString spec_object; + NMVariantMapMap map_settings; + NetworkManager::AccessPoint::Ptr accessPointPtr = nullptr; + + if (!isHidden) { + NetworkManager::WirelessNetwork::Ptr wifiNet = checkWifiNetExist(connSettingInfo.m_ssid, devIface); + if (wifiNet.isNull()) { + QString errorMessage = "the ssid " + connSettingInfo.m_ssid + " is not exsit in " + devIface; + qWarning()<referenceAccessPoint(); + conn_uni = accessPointPtr->uni(); + spec_object = conn_uni; + } + + auto dev = m_networkResourceInstance->findDeviceInterface(devIface); + if (dev.isNull()) { + Q_EMIT addAndActivateConnectionError("can not find device"); + return; + } + dev_uni = dev->uni(); + + NetworkManager::ConnectionSettings::Ptr settings = + assembleWirelessSettings(accessPointPtr, connSettingInfo, isHidden); + assembleEapMethodTtlsSettings(settings, info); + + if(settings.isNull()) { + qDebug() << "assembleEapMethodTtlsSettings failed"; + return; + } + + map_settings = settings->toMap(); + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(map_settings, dev_uni, spec_object), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [&] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = watcher->error().message(); + qDebug() << "addAndActiveWirelessEnterPriseTtlsConnect failed " << errorMessage; + Q_EMIT addAndActivateConnectionError(errorMessage); + } + watcher->deleteLater(); + }); +} + +//无线网络开关设置 +void KyWirelessConnectOperation::setWirelessEnabled(bool enabled) +{ + Q_EMIT enabledWirelessNetwork(enabled); + + return; +} + +bool KyWirelessConnectOperation::getWirelessEnabled() +{ + return NetworkManager::isWirelessEnabled(); +} + +bool KyWirelessConnectOperation::getConnSecretFlags(QString &connUuid, NetworkManager::Setting::SecretFlags &flag) +{ + NetworkManager::Connection::Ptr conn; + conn = m_networkResourceInstance->getConnect(connUuid); + if (conn.isNull()) { + qDebug() <<"get failed"; + return false; + } + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = conn->settings()->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + flag = security_sett->pskFlags(); + return true; +} + +NetworkManager::ConnectionSettings::Ptr + KyWirelessConnectOperation::createWirelessApSetting(const QString apSsid, + const QString apPassword, + const QString apDevice, + const QString wirelessBand) +{ + NetworkManager::ConnectionSettings::Ptr connectionSettings = + NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(NetworkManager::ConnectionSettings::Wireless)); + connectionSettings->setId(apSsid); + connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); + connectionSettings->setAutoconnect(false); + connectionSettings->setAutoconnectPriority(0); + connectionSettings->setInterfaceName(apDevice); + //Note: workaround for wrongly (randomly) initialized gateway-ping-timeout + connectionSettings->setGatewayPingTimeout(0); + + NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + ipv4Setting->setInitialized(true); + ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + ipv6Setting->setInitialized(true); + ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Ignored); + + NetworkManager::WirelessSetting::Ptr wirelessSetting + = connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast(); + wirelessSetting->setInitialized(true); + wirelessSetting->setSsid(apSsid.toUtf8()); + wirelessSetting->setMode(NetworkManager::WirelessSetting::NetworkMode::Ap); + wirelessSetting->setSecurity("802-11-wireless-security"); + if (wirelessBand == WIFI_BAND_2_4GHZ) { + wirelessSetting->setBand(NetworkManager::WirelessSetting::FrequencyBand::Bg); + } else if (wirelessBand == WIFI_BAND_5GHZ) { + wirelessSetting->setBand(NetworkManager::WirelessSetting::FrequencyBand::A); + } else { + qWarning()<<"[KyWirelessConnectOperation] the band type undefined"<setBand(NetworkManager::WirelessSetting::FrequencyBand::Automatic); + } + + + NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySetting + = connectionSettings->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + if (apPassword.isEmpty()) { + wirelessSecuritySetting->setInitialized(false); + } else { + wirelessSecuritySetting->setInitialized(true); + wirelessSecuritySetting->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); + wirelessSecuritySetting->setPsk(apPassword); + } + + return connectionSettings; +} + +void KyWirelessConnectOperation::updateWirelessApSetting( + NetworkManager::Connection::Ptr apConnectPtr, + const QString apName, const QString apPassword, + const QString apDevice, const QString wirelessBand) + +{ + NetworkManager::ConnectionSettings::Ptr apConnectSettingPtr = apConnectPtr->settings(); + apConnectSettingPtr->setId(apName); + apConnectSettingPtr->setInterfaceName(apDevice); + apConnectSettingPtr->setAutoconnect(false); + + NetworkManager::WirelessSetting::Ptr wirelessSetting + = apConnectSettingPtr->setting(NetworkManager::Setting::Wireless).dynamicCast(); + wirelessSetting->setInitialized(true); + wirelessSetting->setSsid(apName.toUtf8()); + if (wirelessBand == WIFI_BAND_2_4GHZ) { + wirelessSetting->setBand(NetworkManager::WirelessSetting::FrequencyBand::Bg); + } else if (wirelessBand == WIFI_BAND_5GHZ) { + wirelessSetting->setBand(NetworkManager::WirelessSetting::FrequencyBand::A); + } else { + qWarning()<<"[KyWirelessConnectOperation] the band type undefined"<setBand(NetworkManager::WirelessSetting::FrequencyBand::Automatic); + } + + + NetworkManager::WirelessSecuritySetting::Ptr wirelessSecuritySetting + = apConnectSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + if (apPassword.isEmpty()) { + wirelessSecuritySetting->setInitialized(false); + } else { + wirelessSecuritySetting->setInitialized(true); + wirelessSecuritySetting->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); + wirelessSecuritySetting->setPsk(apPassword); + } + + apConnectPtr->update(apConnectSettingPtr->toMap()); +} + +void KyWirelessConnectOperation::activeWirelessAp(const QString apUuid, const QString apName, + const QString apPassword, const QString apDevice, + const QString wirelessBand) + +{ + qDebug() << "[activeWirelessAp]" << apUuid << apName << apPassword << apDevice << wirelessBand; + //1、检查连接是否存在 + NetworkManager::Connection::Ptr connectPtr = m_networkResourceInstance->getConnect(apUuid); + if (nullptr == connectPtr) { + NetworkManager::Device::Ptr devicePtr = m_networkResourceInstance->findDeviceInterface(apDevice); + if (devicePtr.isNull()) { + QString errorMsg ="Create hotspot faild. " + apDevice + " is not existed"; + qWarning()<< errorMsg; + Q_EMIT addAndActivateConnectionError(errorMsg); + return; + } + + QString deviceIdentifier = devicePtr->uni(); + + NetworkManager::ConnectionSettings::Ptr apConnectSettingPtr = + createWirelessApSetting(apName, apPassword, apDevice, wirelessBand); + QString specificObject = ""; + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::addAndActivateConnection(apConnectSettingPtr->toMap(), deviceIdentifier, specificObject), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [&] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMsg = "Create hotspot faild. " + watcher->error().message(); + qWarning() << errorMsg; + Q_EMIT addAndActivateConnectionError(errorMsg); + } + watcher->deleteLater(); + }); + } else { + updateWirelessApSetting(connectPtr, apName, apPassword, apDevice, wirelessBand); + QTimer::singleShot(500, this, [=](){ + activateApConnectionByUuid(apUuid, apDevice); + }); + } + + return; +} + +void KyWirelessConnectOperation::deactiveWirelessAp(const QString apName, const QString apUuid) +{ + deactivateConnection(apName, apUuid); + return; +} + +//private +NetworkManager::WirelessNetwork::Ptr KyWirelessConnectOperation::checkWifiNetExist(QString ssid, QString devName) +{ + for (auto const & net : m_networkResourceInstance->m_wifiNets) { + auto dev = m_networkResourceInstance->findDeviceUni(net->device()); + if (dev == nullptr) { + continue; + } + if (dev->type() != NetworkManager::Device::Wifi || dev->interfaceName() != devName) { + continue; + } + + NetworkManager::AccessPoint::Ptr accessPointPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPointPtr->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + + if (ssid == wifiSsid) { + return net; + } + } + return nullptr; +} + +KyKeyMgmt KyWirelessConnectOperation::getConnectKeyMgmt(const QString &uuid) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (connectPtr.isNull()) { + return KyKeyMgmt::Unknown; + } + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connectPtr->settings()->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + + if(security_sett.isNull()) { + return KyKeyMgmt::Unknown; + } + return (KyKeyMgmt)security_sett->keyMgmt(); +} + +void KyWirelessConnectOperation::updateWirelessSecu(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyWirelessConnectSetting &connSettingInfo, bool bPwdChange) +{ + qDebug() << "updateWirelessSecu " << connSettingInfo.m_type; + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + + KyKeyMgmt type = connSettingInfo.m_type; + qDebug() << "set keyMgmt " << type; + if (type == WpaNone) { + security_sett->setInitialized(false); + return; + } else { + security_sett->setInitialized(true); + } + security_sett->setKeyMgmt((NetworkManager::WirelessSecuritySetting::KeyMgmt)type); + if (bPwdChange) { + security_sett->setPsk(connSettingInfo.m_psk); + NetworkManager::Setting::SecretFlags flag = NetworkManager::Setting::None; + security_sett->setPskFlags(flag); + } + return; +} + +void KyWirelessConnectOperation::setWirelessSecuWpaXEap(NetworkManager::ConnectionSettings::Ptr connSettingPtr) +{ + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = connSettingPtr->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + + security_sett->setInitialized(true); + security_sett->setKeyMgmt(NetworkManager::WirelessSecuritySetting::KeyMgmt::WpaEap); + return; +} + +void KyWirelessConnectOperation::setIpv4AndIpv6Setting(NetworkManager::ConnectionSettings::Ptr connSetting, const KyConnectSetting &connSettingInfo) +{ + NetworkManager::Ipv4Setting::Ptr ipv4Setting = connSetting->setting(NetworkManager::Setting::Ipv4).dynamicCast(); + ipv4SettingSet(ipv4Setting, connSettingInfo); + + NetworkManager::Ipv6Setting::Ptr ipv6Setting = connSetting->setting(NetworkManager::Setting::Ipv6).dynamicCast(); + ipv6SettingSet(ipv6Setting, connSettingInfo); +} + +void KyWirelessConnectOperation::activateApConnectionByUuid(const QString apUuid, const QString apDevice) +{ + QString connectPath = ""; + QString deviceIdentifier = ""; + QString connectName = ""; + QString specificObject = ""; + + qDebug()<<"it will activate hotspot connect"<getConnect(apUuid); + if (connectPtr.isNull()) + { + QString errorMessage = tr("Create hotspot faild.UUID is empty, its name") + apUuid; + qWarning() << errorMessage; + Q_EMIT activateConnectionError(errorMessage); + return; + } + connectPath = connectPtr->path(); + connectName = connectPtr->name(); + + auto dev = m_networkResourceInstance->findDeviceInterface(apDevice); + if (!dev.isNull()) { + deviceIdentifier = dev->uni(); + } + + if (deviceIdentifier.isEmpty()) { + QString errorMessage = tr("Create hotspot faild.Device Identifier is empty, its name") + apDevice; + qWarning() << errorMessage; + Q_EMIT activateConnectionError(errorMessage); + return ; + } + + QDBusPendingCallWatcher * watcher; + watcher = new QDBusPendingCallWatcher{NetworkManager::activateConnection(connectPath, deviceIdentifier, specificObject), this}; + connect(watcher, &QDBusPendingCallWatcher::finished, [this, connectName, apDevice] (QDBusPendingCallWatcher * watcher) { + if (watcher->isError() || !watcher->isValid()) { + QString errorMessage = tr("Create hotspot faild. ") + watcher->error().message(); + qWarning()<activateConnectionError(errorMessage); + } else { + qWarning()<<"active wired connect complete."; + } + + watcher->deleteLater(); + }); + + return ; +} + +bool KyWirelessConnectOperation::getEnterpiseEapMethod(const QString &uuid, KyEapMethodType &type) +{ + NetworkManager::Connection::Ptr connectPtr = + NetworkManager::findConnectionByUuid(uuid); + if (connectPtr.isNull()) { + qWarning() << "getEnterpiseEapMethod faild.Can't find uuid = " << uuid; + return false; + } + + KyKeyMgmt keyMgmt = getConnectKeyMgmt(uuid); + if (keyMgmt != WpaEap) { + qWarning() << "getEnterpiseEapMethod but not WpaEap.it's " << keyMgmt; + return false; + } + + NetworkManager::ConnectionSettings::Ptr connectionSettings = connectPtr->settings(); + + NetworkManager::Security8021xSetting::Ptr wifi_8021x_sett + = connectionSettings->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + + QList list = wifi_8021x_sett->eapMethods(); + + if (list.contains(NetworkManager::Security8021xSetting::EapMethod::EapMethodTls)) { + type = TLS; + } else if (list.contains(NetworkManager::Security8021xSetting::EapMethod::EapMethodPeap)) { + type = PEAP; + } else if (list.contains(NetworkManager::Security8021xSetting::EapMethod::EapMethodTtls)) { + type = TTLS; + } + + return true; +} diff --git a/src/backend/dbus-interface/kywirelessconnectoperation.h b/src/backend/dbus-interface/kywirelessconnectoperation.h new file mode 100644 index 00000000..bc958f40 --- /dev/null +++ b/src/backend/dbus-interface/kywirelessconnectoperation.h @@ -0,0 +1,159 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYWIRELESSCONNECTOPERATION_H +#define KYWIRELESSCONNECTOPERATION_H + +#include +#include +#include +#include "kyenterpricesettinginfo.h" +#include "kylinconnectoperation.h" +#include "kyenterpricesettinginfo.h" + +const QByteArray GSETTINGS_SCHEMA = "org.ukui.kylin-nm.switch"; +const QString WIRELESS_SWITCH = "wirelessswitch"; + +const QString WIFI_BAND_2_4GHZ = "2.4Ghz"; +const QString WIFI_BAND_5GHZ = "5Ghz"; + +enum KySecuType { + NONE = 0, + WPA_AND_WPA2_PERSONAL, + WPA_AND_WPA2_ENTERPRISE, + WPA3_PERSONAL, +}; + +enum KyKeyMgmt { + Unknown = -1, + Wep, Ieee8021x, + WpaNone, + WpaPsk, + WpaEap, + SAE +}; + +class KyWirelessConnectSetting : public KyConnectSetting +{ +// Q_OBJECT + +public: + QString m_ssid; + bool isAutoConnect; + QString m_psk; + NetworkManager::Setting::SecretFlags m_secretFlag; + KyKeyMgmt m_type; + //only if m_type == WpaEap + KyEapMethodType m_eapMethodType; +}; + + +class KyWirelessConnectOperation : public KyConnectOperation +{ + Q_OBJECT +public: + explicit KyWirelessConnectOperation(QObject *parent = nullptr); + ~KyWirelessConnectOperation(); + + //无线开关 + void setWirelessEnabled(bool enabled); + bool getWirelessEnabled(); + + //获取密码保存策略 + bool getConnSecretFlags(QString &connUuid, NetworkManager::Setting::SecretFlags &); + + //获取KeyMgmt + KyKeyMgmt getConnectKeyMgmt(const QString &uuid); + + //获取企业网类型 + bool getEnterpiseEapMethod(const QString &uuid, KyEapMethodType &type); + + //激活连接 + void activeWirelessConnect(QString , QString); + //断开连接 + void deActivateWirelessConnection(const QString activeConnectName, const QString &activeConnectUuid); + //新增普通连接 + void addConnect(const KyWirelessConnectSetting &connSettingInfo); + //新增TLS连接 + void addTlsConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodTlsInfo &tlsinfo); + //新增PEAP连接 + void addPeapConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodPeapInfo &peapInfo); + //新增TTLS连接 + void addTtlsConnect(const KyWirelessConnectSetting &connSettingInfo, const KyEapMethodTtlsInfo &ttlsInfo); + //新增连接并激活(普通wifi) + void addAndActiveWirelessConnect(QString & devIface,KyWirelessConnectSetting &connSettingInfo,bool isHidden); + + //新增连接并激活(企业wifi) + void addAndActiveWirelessEnterPriseTlsConnect(KyEapMethodTlsInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden); + void addAndActiveWirelessEnterPrisePeapConnect(KyEapMethodPeapInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden); + void addAndActiveWirelessEnterPriseTtlsConnect(KyEapMethodTtlsInfo &info, KyWirelessConnectSetting &connSettingInfo, + QString & devIface, bool isHidden); + //属性页 page1 AutoConnect + void setWirelessAutoConnect(const QString &uuid, bool bAutoConnect); + //属性页 page2 page3 ipv6 + void updateIpv4AndIpv6SettingInfo(const QString &uuid, const KyConnectSetting &connectSettingsInfo); + //属性页 page4 wifi Security + //连接修改(安全改为个人/None) + void updateWirelessPersonalConnect(const QString &uuid, const KyWirelessConnectSetting &connSettingInfo, bool bPwdChange); + //连接修改(安全改为改为企业) + void updateWirelessEnterPriseTlsConnect(const QString &uuid, const KyEapMethodTlsInfo &tlsinfo); + void updateWirelessEnterPrisePeapConnect(const QString &uuid, const KyEapMethodPeapInfo &peapInfo); + void updateWirelessEnterPriseTtlsConnect(const QString &uuid, const KyEapMethodTtlsInfo &ttlsInfo); + //忘记 + void deleteWirelessConnect(const QString &connectUuid); + //获取密码 + QString getPsk(const QString &connectUuid); + QString getPrivateKeyPassword(const QString &connectUuid); + QString get8021xPassword(const QString &connectUuid); + + //申请扫描 + void requestWirelessScan(); + + void activeWirelessAp(const QString apUuid, const QString apName, + const QString apPassword, const QString apDevice, + const QString wirelessBand); + void deactiveWirelessAp(const QString apName, const QString apUuid); + +private: + NetworkManager::ConnectionSettings::Ptr createWirelessApSetting(const QString apSsid, + const QString apPassword, + const QString apDevice, + const QString wirelessBand); + void updateWirelessApSetting(NetworkManager::Connection::Ptr apConnectPtr, + const QString apName, + const QString apPassword, + const QString apDevice, + const QString wirelessBand); + +Q_SIGNALS: + void wifiEnabledChanged(bool); + void enabledWirelessNetwork(bool enabled); + void addAndActivateConnectionError(QString errorMessage); + +private: + NetworkManager::WirelessNetwork::Ptr checkWifiNetExist(QString ssid, QString devName); + void updateWirelessSecu(NetworkManager::ConnectionSettings::Ptr connSettingPtr, const KyWirelessConnectSetting &connSettingInfo, bool bPwdChange = false); + void setIpv4AndIpv6Setting(NetworkManager::ConnectionSettings::Ptr connSetting, const KyConnectSetting &connSettingInfo); + void setWirelessSecuWpaXEap(NetworkManager::ConnectionSettings::Ptr connSettingPtr); + void activateApConnectionByUuid(const QString apUuid, const QString apDevice); +}; + +#endif // KYWIRELESSCONNECTOPERATION_H diff --git a/src/backend/dbus-interface/kywirelessnetitem.cpp b/src/backend/dbus-interface/kywirelessnetitem.cpp new file mode 100644 index 00000000..9d823693 --- /dev/null +++ b/src/backend/dbus-interface/kywirelessnetitem.cpp @@ -0,0 +1,223 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kywirelessnetitem.h" +#include +#include "kylinutil.h" + +const QString ENTERPRICE_TYPE = "802.1X"; +const QString WPA1_AND_WPA2 = "WPA"; +const QString WPA3 = "WPA3"; + +#define FREQ_5GHZ 5000 + +QString enumToQstring(NetworkManager::AccessPoint::Capabilities cap, NetworkManager::AccessPoint::WpaFlags wpa_flags,NetworkManager::AccessPoint::WpaFlags rsn_flags) +{ + QString out; + if ( (cap & NM_802_11_AP_FLAGS_PRIVACY) + && (wpa_flags == NM_802_11_AP_SEC_NONE) + && (rsn_flags == NM_802_11_AP_SEC_NONE)) { + out += "WEP "; + } + if (wpa_flags != NM_802_11_AP_SEC_NONE) { + out += "WPA1 "; + } + if ((rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) + || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + out += "WPA2 "; + } + if (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE) { + out += "WPA3 "; + } + if ( (wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) + || (rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { + out += "802.1X "; + } + return out; +} + +KyWirelessNetItem::KyWirelessNetItem(NetworkManager::WirelessNetwork::Ptr net) +{ + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); + + m_bssid = ""; + m_connectUuid = ""; + m_isConfigured = false; + m_connName = ""; + m_connDbusPath = ""; + m_secuType = ""; + m_kySecuType = NONE; + m_device = ""; + m_channel = 0; + m_isMix = false; + + init(net); +} + + +KyWirelessNetItem::~KyWirelessNetItem() +{ + m_networkResourceInstance = nullptr; +} + + +void KyWirelessNetItem::init(NetworkManager::WirelessNetwork::Ptr net) +{ + // m_NetSsid = net->ssid(); + + NetworkManager::AccessPoint::Ptr accessPointPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPointPtr->rawSsid(); + m_NetSsid = getSsidFromByteArray(rawSsid); + + m_signalStrength = net->signalStrength(); + m_frequency = net->referenceAccessPoint()->frequency(); + m_channel = NetworkManager::findChannel(m_frequency); + NetworkManager::AccessPoint::Capabilities cap = net->referenceAccessPoint()->capabilities(); + NetworkManager::AccessPoint::WpaFlags wpaFlag = net->referenceAccessPoint()->wpaFlags(); + NetworkManager::AccessPoint::WpaFlags rsnFlag = net->referenceAccessPoint()->rsnFlags(); + m_secuType = enumToQstring(cap, wpaFlag, rsnFlag); +// if (m_secuType.indexOf(ENTERPRICE_TYPE) >= 0) { +// m_kySecuType = WPA_AND_WPA2_ENTERPRISE; +// } else if (m_secuType.indexOf(WPA3) >= 0) { +// m_kySecuType = WPA3_PERSONAL; +// } else if ( m_secuType.indexOf(WPA1_AND_WPA2) >= 0) { +// m_kySecuType = WPA_AND_WPA2_PERSONAL; +// } + setKySecuType(m_secuType); + m_bssid = net->referenceAccessPoint()->hardwareAddress(); + m_device = net->device(); + m_uni = net->referenceAccessPoint()->uni(); + + NetworkManager::Device::Ptr devicePtr = nullptr; + devicePtr = m_networkResourceInstance->findDeviceInterface(m_device); + if (!devicePtr.isNull()) { + QString devUni = devicePtr->uni(); + NetworkManager::WirelessNetwork::Ptr wirelessPtr = nullptr; + wirelessPtr = m_networkResourceInstance->findWifiNetwork(m_NetSsid, devUni); + if (!wirelessPtr.isNull()) { + NetworkManager::AccessPoint::List apList = wirelessPtr->accessPoints(); + bool b2G = false; + bool b5G = false; + if (!apList.empty()) { + for (int i = 0; i < apList.count(); ++i) { + if (apList.at(i)->frequency() < FREQ_5GHZ) { + b2G = true; + } + if (apList.at(i)->frequency() >= FREQ_5GHZ) { + b5G = true; + } + if (b2G && b5G) { + m_isMix = true; + break; + } + } + } + devicePtr = m_networkResourceInstance->findDeviceInterface(m_device); + if (!devicePtr.isNull()) { + QString devUni = devicePtr->uni(); + NetworkManager::WirelessNetwork::Ptr wirelessPtr = nullptr; + wirelessPtr = m_networkResourceInstance->findWifiNetwork(m_NetSsid, devUni); + if (!wirelessPtr.isNull()) { + NetworkManager::AccessPoint::List apList = wirelessPtr->accessPoints(); + bool b2G = false; + bool b5G = false; + if (!apList.empty()) { + for (int i = 0; i < apList.count(); ++i) { + if (apList.at(i)->frequency() < FREQ_5GHZ) { + b2G = true; + } + if (apList.at(i)->frequency() >= FREQ_5GHZ) { + b5G = true; + } + if (b2G && b5G) { + m_isMix = true; + break; + } + + } + } + } + } + } + } + initInfoBySsid(); +} + +void KyWirelessNetItem::initInfoBySsid() +{ + for (auto const & conn : m_networkResourceInstance->m_connections) { + NetworkManager::ConnectionSettings::Ptr settings = conn->settings(); + if (settings->connectionType() != NetworkManager::ConnectionSettings::Wireless) { + continue; + } + + NetworkManager::WirelessSetting::Ptr wifi_sett + = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); + QString devName = m_networkResourceInstance->findDeviceUni(m_device)->interfaceName(); + QByteArray rawSsid = wifi_sett->ssid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + if (wifiSsid == m_NetSsid + && (settings->interfaceName().compare(devName) == 0 || settings->interfaceName().isEmpty())) { + m_connectUuid = settings->uuid(); + m_connName = conn->name(); + m_connDbusPath = conn->path(); + m_isConfigured = true; + /* + * 如果有激活的链接,则取激活的链接,没有则取最后一个,因为一个热点可以创建多个链接 + */ + if (nullptr != m_networkResourceInstance->getActiveConnect(m_connectUuid)) { + break; + } + } + } + + return; +} + +int KyWirelessNetItem::getCategory(QString uni) +{ + + QDBusInterface interface( "org.freedesktop.NetworkManager", uni, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus() ); + if (!interface.isValid()) { + qDebug() << Q_FUNC_INFO << "dbus is invalid"; + return -1; + } + + QDBusReply reply = interface.call("Get", "org.freedesktop.NetworkManager.AccessPoint", "Category"); + if (!reply.isValid()) { + //qDebug()<<"can not get the attribute 'Category' in func getCategory()"; + return 0; + } else { + return reply.value().toInt(); + } + +} + +void KyWirelessNetItem::setKySecuType(QString strSecuType) +{ + if (strSecuType.indexOf(ENTERPRICE_TYPE) >= 0) { + m_kySecuType = WPA_AND_WPA2_ENTERPRISE; + } else if (strSecuType.indexOf(WPA3) >= 0) { + m_kySecuType = WPA3_PERSONAL; + } else if ( strSecuType.indexOf(WPA1_AND_WPA2) >= 0) { + m_kySecuType = WPA_AND_WPA2_PERSONAL; + } else { + m_kySecuType = NONE; + } +} diff --git a/src/backend/dbus-interface/kywirelessnetitem.h b/src/backend/dbus-interface/kywirelessnetitem.h new file mode 100644 index 00000000..4a6716f4 --- /dev/null +++ b/src/backend/dbus-interface/kywirelessnetitem.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYWIRELESSNETITEM_H +#define KYWIRELESSNETITEM_H + +#include + +#include "kylinnetworkresourcemanager.h" +#include "kywirelessconnectoperation.h" + +QString enumToQstring(NetworkManager::AccessPoint::Capabilities, NetworkManager::AccessPoint::WpaFlags, NetworkManager::AccessPoint::WpaFlags); + +class KyWirelessNetItem +{ +public: + KyWirelessNetItem(NetworkManager::WirelessNetwork::Ptr net); + KyWirelessNetItem() {;} + ~KyWirelessNetItem(); + +private: + void init(NetworkManager::WirelessNetwork::Ptr net); + void initInfoBySsid(); + +public: + QString m_NetSsid; + QString m_connectUuid; + QString m_bssid; + int m_signalStrength; + uint m_frequency; + QString m_secuType; + KySecuType m_kySecuType; + QString m_uni; + bool m_isMix; + + //only for m_isConfiged = true + bool m_isConfigured; + QString m_connName; + QString m_connDbusPath; + uint m_channel; + + int getCategory(QString uni); + void setKySecuType(QString strSecuType); + +private: + KyNetworkResourceManager *m_networkResourceInstance = nullptr; + QString m_device; + +}; + +#endif // KYWIRELESSNETITEM_H diff --git a/src/backend/dbus-interface/kywirelessnetresource.cpp b/src/backend/dbus-interface/kywirelessnetresource.cpp new file mode 100644 index 00000000..e851b539 --- /dev/null +++ b/src/backend/dbus-interface/kywirelessnetresource.cpp @@ -0,0 +1,784 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kywirelessnetresource.h" +#include "kylinutil.h" + +#define LOG_FLAG "[KyWirelessNetResource]" +const QString ENTERPRICE_TYPE = "802.1X"; +const QString WPA1_AND_WPA2 = "WPA"; +const QString WPA3 = "WPA3"; + +static bool subWifiListSort(const KyWirelessNetItem info1, const KyWirelessNetItem info2) +{ + if (info1.m_isConfigured == info2.m_isConfigured) { + if (info1.m_signalStrength != info2.m_signalStrength) { + return info1.m_signalStrength > info2.m_signalStrength; + } else { + if (QString::compare(info1.m_NetSsid, info2.m_NetSsid, Qt::CaseInsensitive) > 0) { + return false; + } else { + return true; + } + } + } + return info1.m_isConfigured; +} + +static void wifiListSort(QList &list) +{ + qSort(list.begin(), list.end(), subWifiListSort); +} + +KyWirelessNetResource::KyWirelessNetResource(QObject *parent) + : QObject(parent) +{ + qDebug()<< LOG_FLAG <<"KyWirelessNetResource"; + + qRegisterMetaType("KyWirelessNetItem&"); + + m_networkResourceInstance = KyNetworkResourceManager::getInstance(); + m_operation = new KyWirelessConnectOperation(this); + m_networkDevice = new KyNetworkDeviceResourse(this); + + kyWirelessNetItemListInit(); + + //TODO:connect device signal + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiNetworkAdded, + this, &KyWirelessNetResource::onWifiNetworkAdded, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiNetworkRemoved, + this, &KyWirelessNetResource::onWifiNetworkRemoved, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiNetworkPropertyChange, + this, &KyWirelessNetResource::onWifiNetworkPropertyChange, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiNetworkSecuChange, + this, &KyWirelessNetResource::onWifiNetworkSecuChange, Qt::ConnectionType::DirectConnection); + connect(m_networkResourceInstance, &KyNetworkResourceManager::wifiNetworkDeviceDisappear, + this, &KyWirelessNetResource::onWifiNetworkDeviceDisappear, Qt::ConnectionType::DirectConnection); + + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionAdd, + this, &KyWirelessNetResource::onConnectionAdd); + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionRemove, + this, &KyWirelessNetResource::onConnectionRemove); + connect(m_networkResourceInstance, &KyNetworkResourceManager::connectionUpdate, + this, &KyWirelessNetResource::onConnectionUpdate); + + connect(m_networkDevice, &KyNetworkDeviceResourse::deviceAdd, this, &KyWirelessNetResource::onDeviceAdd); + connect(m_networkDevice, &KyNetworkDeviceResourse::deviceRemove, this, &KyWirelessNetResource::onDeviceRemove); + connect(m_networkDevice, &KyNetworkDeviceResourse::deviceNameUpdate, this, &KyWirelessNetResource::onDeviceNameUpdate); +} + +KyWirelessNetResource::~KyWirelessNetResource() +{ + m_networkResourceInstance = nullptr; +} + +bool KyWirelessNetResource::getAllDeviceWifiNetwork(QMap> &map) +{ +// onWifiNetworkDeviceDisappear(); + if (m_WifiNetworkList.isEmpty()) { + return false; + } else { + QMap >::iterator iter = m_WifiNetworkList.begin(); + while (iter != m_WifiNetworkList.end()) { + wifiListSort(m_WifiNetworkList[iter.key()]); + iter++; + } + map = m_WifiNetworkList; + return true; + } +} + + +bool KyWirelessNetResource::getDeviceWifiNetwork(QString devIfaceName, QList &wirelessNetResource) +{ + if (!m_WifiNetworkList.contains(devIfaceName)) { + return false; + } else { + wifiListSort(m_WifiNetworkList[devIfaceName]); + wirelessNetResource = m_WifiNetworkList[devIfaceName]; + return true; + } +} + +bool KyWirelessNetResource::getWifiNetwork(const QString &devIfaceName, + const QString &ssid, + KyWirelessNetItem &wirelessNetResource) +{ + if (!m_WifiNetworkList.contains(devIfaceName)) { + qDebug()<< LOG_FLAG << "getWifiNetwork fail, not contain " << devIfaceName; + return false; + } else { + for (int index = 0; index < m_WifiNetworkList[devIfaceName].size(); index++){ + if (m_WifiNetworkList[devIfaceName].at(index).m_NetSsid == ssid) { + wirelessNetResource = m_WifiNetworkList[devIfaceName].at(index); + qDebug()<< LOG_FLAG << "getWifiNetwork success"; + return true; + } + } + } + + qDebug()<< LOG_FLAG << "getWifiNetwork fail, not contain " << ssid; + + return false; +} + +void KyWirelessNetResource::getWirelessActiveConnection(NetworkManager::ActiveConnection::State state, QMap &map) +{ + int index = 0; + map.clear(); + NetworkManager::ActiveConnection::List activeConnectionList; + + activeConnectionList.clear(); + activeConnectionList = m_networkResourceInstance->getActiveConnectList(); + if (activeConnectionList.isEmpty()) { + return; + } + + NetworkManager::ActiveConnection::Ptr activeConnectionPtr = nullptr; + for (; index < activeConnectionList.size(); index++) { + activeConnectionPtr = activeConnectionList.at(index); + if (activeConnectionPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless != activeConnectionPtr->type()) { + continue; + } + + if (state != activeConnectionPtr->state()) { + continue; + } + + qDebug()<< LOG_FLAG << "getWirelessActiveConnection " << activeConnectionPtr->uuid(); + QString ssid; + QString ifaceName = getDeviceIFace(activeConnectionPtr, ssid); + if(ifaceName.isEmpty() || ssid.isNull()) { + continue; + } + + if (map.contains(ifaceName)) { + map[ifaceName].append(activeConnectionPtr->uuid()); + } else { + QStringList list; + list.append(activeConnectionPtr->uuid()); + map.insert(ifaceName,list); + } + } + + return; +} + +QString KyWirelessNetResource::getActiveConnectSsidByDevice(QString deviceName) +{ + QString ssid = ""; + + NetworkManager::ActiveConnection::List activeConnectionList; + activeConnectionList.clear(); + activeConnectionList = m_networkResourceInstance->getActiveConnectList(); + if (activeConnectionList.isEmpty()) { + return ssid; + } + + NetworkManager::ActiveConnection::Ptr activeConnectionPtr = nullptr; + for (int index = 0; index < activeConnectionList.size(); index++) { + activeConnectionPtr = activeConnectionList.at(index); + if (activeConnectionPtr.isNull()) { + continue; + } + + if (NetworkManager::ConnectionSettings::ConnectionType::Wireless != activeConnectionPtr->type()) { + continue; + } + + if (NetworkManager::ActiveConnection::State::Activated != activeConnectionPtr->state()) { + continue; + } + + QStringList interfaces = activeConnectionPtr->devices(); + if(interfaces.isEmpty()) { + qWarning()<< LOG_FLAG <<"get active device failed."; + continue; + } + + QString ifaceUni = interfaces.at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + if (deviceName != devicePtr->interfaceName()) { + continue; + } + + NetworkManager::Connection::Ptr connectPtr = activeConnectionPtr->connection(); + NetworkManager::ConnectionSettings::Ptr settingPtr = connectPtr->settings(); + NetworkManager::WirelessSetting::Ptr wirelessSettingPtr = + settingPtr->setting(NetworkManager::Setting::Wireless).dynamicCast(); + + QByteArray rawSsid = wirelessSettingPtr->ssid(); + ssid = getSsidFromByteArray(rawSsid); + + break; + } + + return ssid; +} + +bool KyWirelessNetResource::getActiveWirelessNetItem(QString deviceName, KyWirelessNetItem &wirelessNetItem) +{ + if (!m_WifiNetworkList.contains(deviceName)) { + qDebug() << "getWifiNetwork fail,not contain " << deviceName; + return false; + } + + QString ssid = getActiveConnectSsidByDevice(deviceName); + if (ssid.isEmpty()) { + return false; + } + + for (int index = 0; index < m_WifiNetworkList[deviceName].size(); index ++) { + if (m_WifiNetworkList[deviceName].at(index).m_NetSsid == ssid) { + wirelessNetItem = m_WifiNetworkList[deviceName].at(index); + qDebug()<< LOG_FLAG << "getWifiNetwork success"; + return true; + } + } + + return false; +} + +QString KyWirelessNetResource::getDeviceIFace(NetworkManager::ActiveConnection::Ptr actConn, + QString &wirelessNetResourcessid) +{ + if (actConn.isNull()) { + return ""; + } + + NetworkManager::Connection::Ptr conn = actConn->connection(); + if (conn.isNull()) { + return ""; + } + + NetworkManager::ConnectionSettings::Ptr sett = conn->settings(); + if (sett.isNull()) { + return ""; + } + + NetworkManager::WirelessSetting::Ptr wireless_sett = sett->setting(NetworkManager::Setting::Wireless).dynamicCast(); + if (wireless_sett.isNull()) { + return ""; + } + + QByteArray rawSsid = wireless_sett->ssid(); + wirelessNetResourcessid = getSsidFromByteArray(rawSsid); + + QStringList interfaces = actConn->devices(); + if (interfaces.isEmpty()) { + return ""; + } + + QString ifaceUni = interfaces.at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + + return devicePtr->interfaceName(); +} + +void KyWirelessNetResource::getSsidByUuid(const QString uuid, QString &ssid) +{ + ssid.clear(); + NetworkManager::Connection::Ptr connectPtr = m_networkResourceInstance->getConnect(uuid); + if (connectPtr.isNull()) { + return; + } + + NetworkManager::WirelessSetting::Ptr wireless_sett + = connectPtr->settings()->setting(NetworkManager::Setting::Wireless).dynamicCast(); + if (wireless_sett.isNull()) { + qDebug()<< LOG_FLAG << "don't have WirelessSetting connection"; + return; + } + + QByteArray rawSsid = wireless_sett->ssid(); + ssid = getSsidFromByteArray(rawSsid); + + qDebug()<< LOG_FLAG << "getSsidByUuid success " << ssid; + + return; +} + +void KyWirelessNetResource::getDeviceByUuid(const QString uuid, QString &deviceName) +{ + deviceName.clear(); + + NetworkManager::ActiveConnection::Ptr activeConnectionPtr = m_networkResourceInstance->getActiveConnect(uuid); + if (!activeConnectionPtr.isNull()) { + QStringList interfaces = activeConnectionPtr->devices(); + if (interfaces.size() > 0) { + QString ifaceUni = interfaces.at(0); + NetworkManager::Device:: Ptr devicePtr = + m_networkResourceInstance->findDeviceUni(ifaceUni); + deviceName = devicePtr->interfaceName(); + return; + } else { + qDebug() << LOG_FLAG << "get device of active connection failed."; + } + } + + NetworkManager::Connection::Ptr connectPtr = m_networkResourceInstance->getConnect(uuid); + if (connectPtr.isNull()) { + return; + } + + deviceName = connectPtr->settings()->interfaceName(); + + return; +} + +void KyWirelessNetResource::kyWirelessNetItemListInit() +{ + qDebug()<< LOG_FLAG << "wireless net size:" << m_networkResourceInstance->m_wifiNets.size(); + for (auto const & net : m_networkResourceInstance->m_wifiNets) { + QString devIface = getDeviceIFace(net); + if (devIface.isEmpty()) { + continue; + } + + KyWirelessNetItem item(net); + if (!m_WifiNetworkList.contains(devIface)){ + QList list; + list.append(item); + m_WifiNetworkList.insert(devIface,list); + } else { + m_WifiNetworkList[devIface].append(item); + } + } + + return; +} + +QString KyWirelessNetResource::getDeviceIFace(NetworkManager::WirelessNetwork::Ptr net) +{ + if (net.isNull()) { + return ""; + } + + QString devUni = net->device(); + NetworkManager::Device::Ptr dev = m_networkResourceInstance->findDeviceUni(devUni); + if (dev.isNull()) { + qDebug()<< LOG_FLAG << "KyWirelessNetResource: can't find " << net->ssid() << " find in device list"; + return ""; + } + + return dev->interfaceName(); +} + +void KyWirelessNetResource::onWifiNetworkAdded(QString devIfaceName, QString ssid) +{ + + NetworkManager::Device::Ptr dev = m_networkResourceInstance->findDeviceInterface(devIfaceName); + if (dev.isNull()) { + return; + } + + NetworkManager::WirelessDevice* w_dev = qobject_cast(dev.data()); + NetworkManager::WirelessNetwork::Ptr wifi = w_dev->findNetwork(ssid); + + if (wifi.isNull()) { + return; + } + + KyWirelessNetItem item(wifi); + + if (m_WifiNetworkList.contains(devIfaceName)) { + m_WifiNetworkList[devIfaceName].append(item); + } else { + QList list; + list.append(item); + m_WifiNetworkList.insert(devIfaceName,list); + } + + Q_EMIT wifiNetworkAdd(devIfaceName, item); +} + +void KyWirelessNetResource::onWifiNetworkRemoved(QString devIfaceName, QString ssid) +{ + if (m_WifiNetworkList.contains(devIfaceName)) { + int index = 0; + for ( ; index < m_WifiNetworkList.value(devIfaceName).size(); index++) { + if ( m_WifiNetworkList[devIfaceName].at(index).m_NetSsid == ssid) { + m_WifiNetworkList[devIfaceName].removeAt(index); + } + } + //remove后为空则删除 + if (m_WifiNetworkList.value(devIfaceName).isEmpty()) { + m_WifiNetworkList.remove(devIfaceName); + } + Q_EMIT wifiNetworkRemove(devIfaceName,ssid); + } +} + +void KyWirelessNetResource::onWifiNetworkSecuChange(NetworkManager::AccessPoint *accessPointPtr) +{ + QString secuType = enumToQstring(accessPointPtr->capabilities(), + accessPointPtr->wpaFlags(), + accessPointPtr->rsnFlags()); + + + QMap >::iterator iter = m_WifiNetworkList.begin(); + while (iter != m_WifiNetworkList.end()) { + QList::iterator itemIter = iter.value().begin(); + while (itemIter != iter.value().end()) { + if (itemIter->m_NetSsid == accessPointPtr->ssid()) { + QString devName = iter.key(); + itemIter->m_secuType = secuType; + itemIter->setKySecuType(secuType); + //qDebug() << "!!!!" << itemIter->m_NetSsid << itemIter->m_secuType << itemIter->m_kySecuType; + Q_EMIT secuTypeChange(devName, accessPointPtr->ssid(), secuType); + break; + } + itemIter++; + } + iter++; + } + +} + +void KyWirelessNetResource::onWifiNetworkPropertyChange(NetworkManager::WirelessNetwork * net) +{ + if (nullptr == net) { + return; + } + + qDebug() << "onWifiNetworkPropertyChange" << net->ssid(); + NetworkManager::AccessPoint::Ptr accessPointPtr = net->referenceAccessPoint(); + QByteArray rawSsid = accessPointPtr->rawSsid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + + if (net->device().isEmpty()) { + return; + } + + QString devIface = m_networkResourceInstance->findDeviceUni(net->device())->interfaceName(); + if (m_WifiNetworkList.contains(devIface)) { + QList::iterator iter = m_WifiNetworkList[devIface].begin(); + while (iter != m_WifiNetworkList[devIface].end()) { + if (iter->m_NetSsid == wifiSsid) { +// qDebug()<< LOG_FLAG <<"recive properity changed signal, sender is" << iter->m_NetSsid; + if (iter->m_signalStrength != net->signalStrength()) { + iter->m_signalStrength = net->signalStrength(); + Q_EMIT signalStrengthChange(devIface, wifiSsid, iter->m_signalStrength); + } + + if (iter->m_bssid != accessPointPtr->hardwareAddress()) { + iter->m_bssid = accessPointPtr->hardwareAddress(); + Q_EMIT bssidChange(devIface, wifiSsid, iter->m_bssid); + } + + QString secuType = enumToQstring(accessPointPtr->capabilities(), + accessPointPtr->wpaFlags(), + accessPointPtr->rsnFlags()); + if (iter->m_secuType != secuType) { + //qDebug() << "!!!!secuTypeChange" << wifiSsid << iter->m_secuType << "change to " << secuType; + iter->setKySecuType(secuType); + Q_EMIT secuTypeChange(devIface, wifiSsid, secuType); + } + + break; + } + iter++; + } + } +} + +void KyWirelessNetResource::onWifiNetworkDeviceDisappear() +{ + m_WifiNetworkList.clear(); + kyWirelessNetItemListInit(); +} + +bool KyWirelessNetResource::getEnterPriseInfoTls(QString &uuid, KyEapMethodTlsInfo &info) +{ + NetworkManager::Connection::Ptr conn = m_networkResourceInstance->getConnect(uuid); + if (conn.isNull()) { + qDebug()<< LOG_FLAG << "modifyEnterPriseInfoTls connection missing"; + return false; + } + + NetworkManager::WirelessSecuritySetting::Ptr security_sett = + conn->settings()->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + if (security_sett.isNull()) { + qDebug()<< LOG_FLAG << "don't have WirelessSecurity connection"; + return false; + } + if (security_sett->keyMgmt() != NetworkManager::WirelessSecuritySetting::WpaEap) { + return false; + } + NetworkManager::Security8021xSetting::Ptr setting = + conn->settings()->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + if (setting.isNull()) { + qDebug()<< LOG_FLAG << "don't have Security8021x connection"; + return false; + } + + + info.identity = setting->identity(); + info.domain = setting->domainSuffixMatch(); + info.caCertPath = setting->caPath(); + if (info.caCertPath.left(7) == "file://") { + info.caCertPath = info.caCertPath.mid(7); + } + + info.clientCertPath = setting->clientCertificate(); + if (info.clientCertPath.left(7) == "file://") { + info.clientCertPath = info.clientCertPath.mid(7); + } + + info.clientPrivateKey = QString(setting->privateKey()); + if (info.clientPrivateKey.left(7) == "file://") { + info.clientPrivateKey = info.clientPrivateKey.mid(7); + } + + info.m_privateKeyPWDFlag = setting->privateKeyPasswordFlags(); + if (!info.m_privateKeyPWDFlag) { + info.clientPrivateKeyPWD = m_operation->getPrivateKeyPassword(conn->uuid()); + } + + return true; +} + +bool KyWirelessNetResource::getEnterPriseInfoPeap(QString &uuid, KyEapMethodPeapInfo &info) +{ + NetworkManager::Connection::Ptr conn = m_networkResourceInstance->getConnect(uuid); + if (conn.isNull()) { + qDebug()<< LOG_FLAG << "getEnterPriseInfoPeap connection missing"; + return false; + } + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = conn->settings()->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + if (security_sett.isNull()) { + qDebug()<< LOG_FLAG << "don't have WirelessSecurity connection"; + return false; + } + + if (security_sett->keyMgmt() != NetworkManager::WirelessSecuritySetting::WpaEap) { + qDebug()<< LOG_FLAG << "keyMgmt not WpaEap " << security_sett->keyMgmt(); + return false; + } + + NetworkManager::Security8021xSetting::Ptr setting = + conn->settings()->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + if (setting.isNull() || !setting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethod::EapMethodPeap)) { + qDebug()<< LOG_FLAG << "don't have Security8021x connection"; + return false; + } + + info.phase2AuthMethod = (KyNoEapMethodAuth)setting->phase2AuthMethod(); + info.userName = setting->identity(); + info.m_passwdFlag = setting->passwordFlags(); + if (!info.m_passwdFlag) { + info.userPWD = m_operation->get8021xPassword(conn->uuid()); + } + + return true; +} + +bool KyWirelessNetResource::getEnterPriseInfoTtls(QString &uuid, KyEapMethodTtlsInfo &info) +{ + NetworkManager::Connection::Ptr conn = m_networkResourceInstance->getConnect(uuid); + if (conn.isNull()) { + qDebug()<< LOG_FLAG << "modifyEnterPriseInfoTtls connection missing"; + return false; + } + + NetworkManager::WirelessSecuritySetting::Ptr security_sett + = conn->settings()->setting(NetworkManager::Setting::WirelessSecurity).dynamicCast(); + if (security_sett.isNull()) { + qDebug()<< LOG_FLAG << "don't have WirelessSecurity connection"; + return false; + } + if (security_sett->keyMgmt() != NetworkManager::WirelessSecuritySetting::WpaEap) { + qDebug()<< LOG_FLAG << "not wpaeap"<keyMgmt(); + return false; + } + + NetworkManager::Security8021xSetting::Ptr setting = conn->settings()->setting(NetworkManager::Setting::Security8021x).dynamicCast(); + if (setting.isNull() || !setting->eapMethods().contains(NetworkManager::Security8021xSetting::EapMethod::EapMethodTtls)) { + qDebug()<< LOG_FLAG << "don't have Security8021x connection"; + return false; + } + + info.authEapMethod = (KyEapMethodAuth)setting->phase2AuthEapMethod(); + info.authNoEapMethod = (KyNoEapMethodAuth)setting->phase2AuthMethod(); + + info.authType = KyTtlsAuthMethod::AUTH_EAP; + if (info.authEapMethod != KyAuthEapMethodUnknown) { + info.authType = KyTtlsAuthMethod::AUTH_EAP; + } else { + info.authType = KyTtlsAuthMethod::AUTH_NO_EAP; + } + + info.userName = setting->identity(); + info.m_passwdFlag = setting->passwordFlags(); + if (!info.m_passwdFlag) { + info.userPWD = m_operation->get8021xPassword(conn->uuid()); + } + + return true; +} + +void KyWirelessNetResource::onConnectionAdd(QString uuid) +{ + qDebug() << LOG_FLAG << "onConnectionAdd " << uuid; + NetworkManager::Connection::Ptr conn = m_networkResourceInstance->getConnect(uuid); + if (conn.isNull()) { + qDebug()<< LOG_FLAG << "onConnectionAdd can not find connection" << uuid; + return; + } + + NetworkManager::ConnectionSettings::Ptr sett = conn->settings(); + if (sett->connectionType() != NetworkManager::ConnectionSettings::ConnectionType::Wireless) { + qDebug()<< LOG_FLAG << uuid << " is not wireless connection"; + return; + } + NetworkManager::WirelessSetting::Ptr wireless_sett = + sett->setting(NetworkManager::Setting::Wireless).dynamicCast(); + + QByteArray rawSsid = wireless_sett->ssid(); + QString wifiSsid = getSsidFromByteArray(rawSsid); + QMap map; + map.clear(); + QMap >::iterator iter = m_WifiNetworkList.begin(); + while (iter != m_WifiNetworkList.end()) { + for(int i = 0; i < iter.value().size(); i++) { + if (iter.value().at(i).m_NetSsid == wifiSsid + && (sett->interfaceName() == iter.key() || sett->interfaceName().isEmpty())) { + QString devIfaceName; + QString ssid; + m_WifiNetworkList[iter.key()][i].m_isConfigured = true; + m_WifiNetworkList[iter.key()][i].m_connName = conn->name(); + m_WifiNetworkList[iter.key()][i].m_connectUuid = conn->uuid(); + m_WifiNetworkList[iter.key()][i].m_connDbusPath = conn->path(); + m_WifiNetworkList[iter.key()][i].m_channel = wireless_sett->channel(); + + devIfaceName = iter.key(); + ssid = iter.value().at(i).m_NetSsid; + map.insert(devIfaceName, ssid); + + break; + } + } + iter++; + } + + if (!map.isEmpty()) { + for(auto var = map.cbegin(); var != map.cend(); var++) { + QString devIfaceName = var.key(); + QString ssid = var.value(); + Q_EMIT connectionAdd(devIfaceName, ssid); + } + } +} + +void KyWirelessNetResource::onConnectionRemove(QString path) +{ + qDebug()<< LOG_FLAG << "onConnectionRemove remove " << path; + QMap map; + map.clear(); + + QMap >::iterator iter = m_WifiNetworkList.begin(); + while (iter != m_WifiNetworkList.end()) { + qDebug()<< LOG_FLAG <<"wifi network list key:" << iter.key(); + for(int i = 0; i < iter.value().size(); i++) { + qDebug() << LOG_FLAG << "connection path" << iter.value().at(i).m_connDbusPath; + if (iter.value().at(i).m_connDbusPath == path) { + QString devIfaceName; + QString ssid; + m_WifiNetworkList[iter.key()][i].m_isConfigured = false; + m_WifiNetworkList[iter.key()][i].m_connName = ""; + m_WifiNetworkList[iter.key()][i].m_connectUuid = ""; + m_WifiNetworkList[iter.key()][i].m_connDbusPath = ""; + m_WifiNetworkList[iter.key()][i].m_channel = 0; + + devIfaceName = iter.key(); + ssid = iter.value().at(i).m_NetSsid; + map.insert(devIfaceName, ssid); + break; + } + } + iter++; + } + + if (!map.isEmpty()) { + for(auto var = map.cbegin(); var != map.cend(); var++) { + QString devIfaceName = var.key(); + QString ssid = var.value(); + Q_EMIT connectionRemove(devIfaceName, ssid, path); + } + } + +} + + +void KyWirelessNetResource::onConnectionUpdate(QString uuid) +{ + qDebug()<< LOG_FLAG << "onConnectionUpdate " << uuid; + NetworkManager::Connection::Ptr conn = m_networkResourceInstance->getConnect(uuid); + if (conn.isNull()) { + qDebug()<< LOG_FLAG << "onConnectionAdd can not find connection" << uuid; + return; + } + + NetworkManager::ConnectionSettings::Ptr sett= conn->settings(); + if (sett->connectionType() != NetworkManager::ConnectionSettings::ConnectionType::Wireless) { + return; + } + + m_WifiNetworkList.clear(); + kyWirelessNetItemListInit(); + Q_EMIT wifiNetworkUpdate(); +} + + +void KyWirelessNetResource::onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType) +{ + if(deviceType == NetworkManager::Device::Type::Wifi) { + if (!m_WifiNetworkList.contains(deviceName)) { + m_WifiNetworkList.insert(deviceName,QList()); + } + } +} + +void KyWirelessNetResource::onDeviceRemove(QString deviceName) +{ + if (m_WifiNetworkList.contains(deviceName)) { + m_WifiNetworkList.remove(deviceName); + } +} + +void KyWirelessNetResource::onDeviceNameUpdate(QString oldName, QString newName) +{ + if (!m_WifiNetworkList.contains(oldName)) { + return; + } + + QMap> newWifiNetworkList(m_WifiNetworkList); + QList list = m_WifiNetworkList[oldName]; + newWifiNetworkList.remove(oldName); + newWifiNetworkList.insert(newName,list); + m_WifiNetworkList = newWifiNetworkList; + +} diff --git a/src/backend/dbus-interface/kywirelessnetresource.h b/src/backend/dbus-interface/kywirelessnetresource.h new file mode 100644 index 00000000..807746d0 --- /dev/null +++ b/src/backend/dbus-interface/kywirelessnetresource.h @@ -0,0 +1,96 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYWIRELESSNETRESOURCE_H +#define KYWIRELESSNETRESOURCE_H + +#include +#include "kywirelessnetitem.h" +#include "kylinnetworkresourcemanager.h" +#include "kyenterpricesettinginfo.h" +#include "kylinconnectresource.h" +#include "kywirelessconnectoperation.h" +#include "kylinnetworkdeviceresource.h" + + +//class KyWirelessNetItem; + +class KyWirelessNetResource : public QObject +{ + Q_OBJECT +public: + explicit KyWirelessNetResource(QObject *parent = nullptr); + ~KyWirelessNetResource(); + + //ui层调用接口 + bool getWifiNetwork(const QString &devIfaceName, const QString &ssid, KyWirelessNetItem &wirelessNetResource); + bool getAllDeviceWifiNetwork(QMap> &map); + bool getDeviceWifiNetwork(QString devIfaceName, QList &wirelessNetResource); + + bool getEnterPriseInfoTls(QString &uuid, KyEapMethodTlsInfo &info); + bool getEnterPriseInfoPeap(QString &uuid, KyEapMethodPeapInfo &info); + bool getEnterPriseInfoTtls(QString &uuid, KyEapMethodTtlsInfo &info); + + void getWirelessActiveConnection(NetworkManager::ActiveConnection::State state, QMap &map); + bool getActiveWirelessNetItem(QString deviceName, KyWirelessNetItem &wirelessNetItem); + + QString getActiveConnectSsidByDevice(QString deviceName); + void getSsidByUuid(const QString uuid, QString &ssid); + void getDeviceByUuid(const QString uuid, QString &deviceName); + + +private: + void kyWirelessNetItemListInit(); + QString getDeviceIFace(NetworkManager::WirelessNetwork::Ptr net); + QString getDeviceIFace(NetworkManager::ActiveConnection::Ptr actConn, QString &wirelessNetResourcessid); + +public Q_SLOTS: + void onWifiNetworkAdded(QString, QString); + void onWifiNetworkRemoved(QString, QString); + void onWifiNetworkPropertyChange(NetworkManager::WirelessNetwork * net); + void onWifiNetworkSecuChange(NetworkManager::AccessPoint *accessPointPtr); + void onWifiNetworkDeviceDisappear(); + + void onConnectionAdd(QString uuid); + void onConnectionUpdate(QString uuid); + void onConnectionRemove(QString); + + void onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType); + void onDeviceRemove(QString deviceName); + void onDeviceNameUpdate(QString oldName, QString newName); + +Q_SIGNALS: + void signalStrengthChange(QString, QString, int); + void bssidChange(QString, QString, QString); + void secuTypeChange(QString, QString, QString); + void connectionRemove(QString, QString, QString); + void connectionAdd(QString, QString); + void wifiNetworkUpdate(); + void wifiNetworkAdd(QString, KyWirelessNetItem&); + void wifiNetworkRemove(QString, QString); + +private: + KyNetworkResourceManager *m_networkResourceInstance = nullptr; + KyWirelessConnectOperation *m_operation = nullptr; + KyNetworkDeviceResourse *m_networkDevice = nullptr; + QMap > m_WifiNetworkList; + +}; + +#endif // KYWIRELESSNETRESOURCE_H diff --git a/src/backend/dbus-interface/nm-macros-internal.h b/src/backend/dbus-interface/nm-macros-internal.h new file mode 100644 index 00000000..025108a4 --- /dev/null +++ b/src/backend/dbus-interface/nm-macros-internal.h @@ -0,0 +1,1310 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef __NM_MACROS_INTERNAL_H__ +#define __NM_MACROS_INTERNAL_H__ + +#include +#include +#include + +#define _nm_packed __attribute__ ((packed)) +#define _nm_unused __attribute__ ((unused)) +#define _nm_pure __attribute__ ((pure)) +#define _nm_const __attribute__ ((const)) +#define _nm_printf(a,b) __attribute__ ((__format__ (__printf__, a, b))) +#define _nm_align(s) __attribute__ ((aligned (s))) +#define _nm_alignof(type) __alignof (type) +#define _nm_alignas(type) _nm_align (_nm_alignof (type)) + +#if __GNUC__ >= 7 +#define _nm_fallthrough __attribute__ ((fallthrough)) +#else +#define _nm_fallthrough +#endif + +/*****************************************************************************/ + +#ifdef thread_local +#define _nm_thread_local thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#elif __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#define _nm_thread_local _Thread_local +#else +#define _nm_thread_local __thread +#endif + +/*****************************************************************************/ + +#if 0 +#include "nm-glib.h" + +/*****************************************************************************/ + +#define nm_offsetofend(t,m) (G_STRUCT_OFFSET (t,m) + sizeof (((t *) NULL)->m)) + +#define nm_auto(fcn) __attribute__ ((cleanup(fcn))) + +static inline int nm_close (int fd); + +/** + * nm_auto_free: + * + * Call free() on a variable location when it goes out of scope. + */ +#define nm_auto_free nm_auto(_nm_auto_free_impl) +GS_DEFINE_CLEANUP_FUNCTION(void*, _nm_auto_free_impl, free) + +static inline void +nm_free_secret (char *secret) +{ + if (secret) { + memset (secret, 0, strlen (secret)); + g_free (secret); + } +} + +static inline void +_nm_auto_free_secret_impl (char **v) +{ + nm_free_secret (*v); +} + +/** + * nm_auto_free_secret: + * + * Call g_free() on a variable location when it goes out of scope. + * Also, previously, calls memset(loc, 0, strlen(loc)) to clear out + * the secret. + */ +#define nm_auto_free_secret nm_auto(_nm_auto_free_secret_impl) + +static inline void +_nm_auto_unset_gvalue_impl (GValue *v) +{ + g_value_unset (v); +} +#define nm_auto_unset_gvalue nm_auto(_nm_auto_unset_gvalue_impl) + +static inline void +_nm_auto_unref_gtypeclass (gpointer v) +{ + if (v && *((gpointer *) v)) + g_type_class_unref (*((gpointer *) v)); +} +#define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass) + +static inline void +_nm_auto_free_gstring_impl (GString **str) +{ + if (*str) + g_string_free (*str, TRUE); +} +#define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring_impl) + +static inline void +_nm_auto_close_impl (int *pfd) +{ + if (*pfd >= 0) { + int errsv = errno; + + (void) nm_close (*pfd); + errno = errsv; + } +} +#define nm_auto_close nm_auto(_nm_auto_close_impl) + +static inline void +_nm_auto_fclose_impl (FILE **pfd) +{ + if (*pfd) { + int errsv = errno; + + (void) fclose (*pfd); + errno = errsv; + } +} +#define nm_auto_fclose nm_auto(_nm_auto_fclose_impl) + +static inline void +_nm_auto_protect_errno (int *p_saved_errno) +{ + errno = *p_saved_errno; +} +#define NM_AUTO_PROTECT_ERRNO(errsv_saved) nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) + +#endif + +/*****************************************************************************/ + +/* http://stackoverflow.com/a/11172679 */ +#define _NM_UTILS_MACRO_FIRST(...) __NM_UTILS_MACRO_FIRST_HELPER(__VA_ARGS__, throwaway) +#define __NM_UTILS_MACRO_FIRST_HELPER(first, ...) first + +#define _NM_UTILS_MACRO_REST(...) __NM_UTILS_MACRO_REST_HELPER(__NM_UTILS_MACRO_REST_NUM(__VA_ARGS__), __VA_ARGS__) +#define __NM_UTILS_MACRO_REST_HELPER(qty, ...) __NM_UTILS_MACRO_REST_HELPER2(qty, __VA_ARGS__) +#define __NM_UTILS_MACRO_REST_HELPER2(qty, ...) __NM_UTILS_MACRO_REST_HELPER_##qty(__VA_ARGS__) +#define __NM_UTILS_MACRO_REST_HELPER_ONE(first) +#define __NM_UTILS_MACRO_REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__ +#define __NM_UTILS_MACRO_REST_NUM(...) \ + __NM_UTILS_MACRO_REST_SELECT_30TH(__VA_ARGS__, \ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\ + TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) +#define __NM_UTILS_MACRO_REST_SELECT_30TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, ...) a30 + +/*****************************************************************************/ + +/* http://stackoverflow.com/a/2124385/354393 */ + +#define NM_NARG(...) \ + _NM_NARG(__VA_ARGS__,_NM_NARG_RSEQ_N()) +#define _NM_NARG(...) \ + _NM_NARG_ARG_N(__VA_ARGS__) +#define _NM_NARG_ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ + _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ + _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63,N,...) N +#define _NM_NARG_RSEQ_N() \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9,8,7,6,5,4,3,2,1,0 + +/*****************************************************************************/ + +#if defined (__GNUC__) +#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning) +#elif defined (__clang__) +#define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning) +#endif + +/* you can only suppress a specific warning that the compiler + * understands. Otherwise you will get another compiler warning + * about invalid pragma option. + * It's not that bad however, because gcc and clang often have the + * same name for the same warning. */ + +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define NM_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("GCC diagnostic push") \ + _Pragma(_NM_PRAGMA_WARNING_DO(warning)) +#elif defined (__clang__) +#define NM_PRAGMA_WARNING_DISABLE(warning) \ + _Pragma("clang diagnostic push") \ + _Pragma(_NM_PRAGMA_WARNING_DO(warning)) +#else +#define NM_PRAGMA_WARNING_DISABLE(warning) +#endif + +#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +#define NM_PRAGMA_WARNING_REENABLE \ + _Pragma("GCC diagnostic pop") +#elif defined (__clang__) +#define NM_PRAGMA_WARNING_REENABLE \ + _Pragma("clang diagnostic pop") +#else +#define NM_PRAGMA_WARNING_REENABLE +#endif + +/*****************************************************************************/ + +/** + * NM_G_ERROR_MSG: + * @error: (allow-none): the #GError instance + * + * All functions must follow the convention that when they + * return a failure, they must also set the GError to a valid + * message. For external API however, we want to be extra + * careful before accessing the error instance. Use NM_G_ERROR_MSG() + * which is safe to use on NULL. + * + * Returns: the error message. + **/ +static inline const char * +NM_G_ERROR_MSG (GError *error) +{ + return error ? (error->message ? : "(null)") : "(no-error)"; \ +} + +/*****************************************************************************/ + +/* macro to return strlen() of a compile time string. */ +#define NM_STRLEN(str) ( sizeof ("" str) - 1 ) + +/* returns the length of a NULL terminated array of pointers, + * like g_strv_length() does. The difference is: + * - it operats on arrays of pointers (of any kind, requiring no cast). + * - it accepts NULL to return zero. */ +#define NM_PTRARRAY_LEN(array) \ + ({ \ + typeof (*(array)) *const _array = (array); \ + gsize _n = 0; \ + \ + if (_array) { \ + _nm_unused typeof (*(_array[0])) *_array_check = _array[0]; \ + while (_array[_n]) \ + _n++; \ + } \ + _n; \ + }) + +/* Note: @value is only evaluated when *out_val is present. + * Thus, + * NM_SET_OUT (out_str, g_strdup ("hallo")); + * does the right thing. + */ +#define NM_SET_OUT(out_val, value) \ + G_STMT_START { \ + typeof(*(out_val)) *_out_val = (out_val); \ + \ + if (_out_val) { \ + *_out_val = (value); \ + } \ + } G_STMT_END + +/*****************************************************************************/ + +#ifndef _NM_CC_SUPPORT_AUTO_TYPE +#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) +#define _NM_CC_SUPPORT_AUTO_TYPE 1 +#else +#define _NM_CC_SUPPORT_AUTO_TYPE 0 +#endif +#endif + +#ifndef _NM_CC_SUPPORT_GENERIC +#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__)) +#define _NM_CC_SUPPORT_GENERIC 1 +#else +#define _NM_CC_SUPPORT_GENERIC 0 +#endif +#endif + +#if _NM_CC_SUPPORT_AUTO_TYPE +#define _nm_auto_type __auto_type +#endif + +#if _NM_CC_SUPPORT_GENERIC +#define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) +#define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) +#define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const alias_type3 *const: ((const type *) (obj)), \ + const alias_type3 * : ((const type *) (obj)), \ + alias_type3 *const: (( type *) (obj)), \ + alias_type3 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) +#define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \ + (_Generic ((obj_expr), \ + const void *const: ((const type *) (obj)), \ + const void * : ((const type *) (obj)), \ + void *const: (( type *) (obj)), \ + void * : (( type *) (obj)), \ + const alias_type2 *const: ((const type *) (obj)), \ + const alias_type2 * : ((const type *) (obj)), \ + alias_type2 *const: (( type *) (obj)), \ + alias_type2 * : (( type *) (obj)), \ + const alias_type3 *const: ((const type *) (obj)), \ + const alias_type3 * : ((const type *) (obj)), \ + alias_type3 *const: (( type *) (obj)), \ + alias_type3 * : (( type *) (obj)), \ + const alias_type4 *const: ((const type *) (obj)), \ + const alias_type4 * : ((const type *) (obj)), \ + alias_type4 *const: (( type *) (obj)), \ + alias_type4 * : (( type *) (obj)), \ + const type *const: ((const type *) (obj)), \ + const type * : ((const type *) (obj)), \ + type *const: (( type *) (obj)), \ + type * : (( type *) (obj)))) +#define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) (_NM_CONSTCAST_FULL_##n (type, obj_expr, obj, ##__VA_ARGS__)) +#define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) (_NM_CONSTCAST_FULL_x (type, obj_expr, obj, n, ##__VA_ARGS__)) +#define NM_CONSTCAST_FULL( type, obj_expr, obj, ...) (_NM_CONSTCAST_FULL_y (type, obj_expr, obj, NM_NARG (dummy, ##__VA_ARGS__), ##__VA_ARGS__)) +#else +#define NM_CONSTCAST_FULL( type, obj_expr, obj, ...) ((type *) (obj)) +#endif + +#define NM_CONSTCAST(type, obj, ...) \ + NM_CONSTCAST_FULL(type, (obj), (obj), ##__VA_ARGS__) + +#define NM_GOBJECT_CAST(type, obj, is_check, ...) \ + ({ \ + const void *_obj = (obj); \ + \ + nm_assert (_obj || (is_check (_obj))); \ + NM_CONSTCAST_FULL (type, (obj), _obj, GObject, ##__VA_ARGS__); \ + }) + +#define NM_GOBJECT_CAST_NON_NULL(type, obj, is_check, ...) \ + ({ \ + const void *_obj = (obj); \ + \ + nm_assert (is_check (_obj)); \ + NM_CONSTCAST_FULL (type, (obj), _obj, GObject, ##__VA_ARGS__); \ + }) + +#if _NM_CC_SUPPORT_GENERIC +/* returns @value, if the type of @value matches @type. + * This requires support for C11 _Generic(). If no support is + * present, this returns @value directly. + * + * It's useful to check the let the compiler ensure that @value is + * of a certain type. */ +#define _NM_ENSURE_TYPE(type, value) (_Generic ((value), type: (value))) +#else +#define _NM_ENSURE_TYPE(type, value) (value) +#endif + +#if _NM_CC_SUPPORT_GENERIC +#define NM_PROPAGATE_CONST(test_expr, ptr) \ + (_Generic ((test_expr), \ + const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \ + default: (_Generic ((test_expr), \ + typeof (*(test_expr)) *: (ptr))))) +#else +#define NM_PROPAGATE_CONST(test_expr, ptr) (ptr) +#endif + +/*****************************************************************************/ + +#define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y)) +#define _NM_IN_SET_EVAL_2( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_3( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_4( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_3 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_5( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_4 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_6( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_5 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_7( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_6 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_8( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_7 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_9( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_8 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14 (op, _x, __VA_ARGS__) +#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15 (op, _x, __VA_ARGS__) + +#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__)) +#define _NM_IN_SET_EVAL_N(op, type, x, n, ...) \ + ({ \ + type _x = (x); \ + \ + /* trigger a -Wenum-compare warning */ \ + nm_assert (TRUE || _x == (x)); \ + \ + !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \ + }) + +#define _NM_IN_SET(op, type, x, ...) _NM_IN_SET_EVAL_N(op, type, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) + +/* Beware that this does short-circuit evaluation (use "||" instead of "|") + * which has a possibly unexpected non-function-like behavior. + * Use NM_IN_SET_SE if you need all arguments to be evaluted. */ +#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof (x), x, __VA_ARGS__) + +/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do + * short-circuit evaluation, which can make a difference if the arguments have + * side-effects. */ +#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof (x), x, __VA_ARGS__) + +/* the *_TYPED forms allow to explicitly select the type of "x". This is useful + * if "x" doesn't support typeof (bitfields) or you want to gracefully convert + * a type using automatic type conversion rules (but not forcing the conversion + * with a cast). */ +#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__) +#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__) + +/*****************************************************************************/ + +static inline gboolean +_NM_IN_STRSET_streq (const char *x, const char *s) +{ + return s && strcmp (x, s) == 0; +} + +#define _NM_IN_STRSET_EVAL_1( op, _x, y) _NM_IN_STRSET_streq (_x, y) +#define _NM_IN_STRSET_EVAL_2( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_1 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_3( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_2 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_4( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_3 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_5( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_4 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_6( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_5 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_7( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_6 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_8( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_7 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_9( op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_8 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_10(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_9 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_11(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_10 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_12(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_11 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_13(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_12 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_14(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_13 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_15(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_14 (op, _x, __VA_ARGS__) +#define _NM_IN_STRSET_EVAL_16(op, _x, y, ...) _NM_IN_STRSET_streq (_x, y) op _NM_IN_STRSET_EVAL_15 (op, _x, __VA_ARGS__) + +#define _NM_IN_STRSET_EVAL_N2(op, _x, n, ...) (_NM_IN_STRSET_EVAL_##n(op, _x, __VA_ARGS__)) +#define _NM_IN_STRSET_EVAL_N(op, x, n, ...) \ + ({ \ + const char *_x = (x); \ + ( ((_x == NULL) && _NM_IN_SET_EVAL_N2 (op, ((const char *) NULL), n, __VA_ARGS__)) \ + || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2 (op, _x, n, __VA_ARGS__)) \ + ); \ + }) + +/* Beware that this does short-circuit evaluation (use "||" instead of "|") + * which has a possibly unexpected non-function-like behavior. + * Use NM_IN_STRSET_SE if you need all arguments to be evaluted. */ +#define NM_IN_STRSET(x, ...) _NM_IN_STRSET_EVAL_N(||, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) + +/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do + * short-circuit evaluation, which can make a difference if the arguments have + * side-effects. */ +#define NM_IN_STRSET_SE(x, ...) _NM_IN_STRSET_EVAL_N(|, x, NM_NARG (__VA_ARGS__), __VA_ARGS__) + +#define NM_STRCHAR_ALL(str, ch_iter, predicate) \ + ({ \ + gboolean _val = TRUE; \ + const char *_str = (str); \ + \ + if (_str) { \ + for (;;) { \ + const char ch_iter = _str[0]; \ + \ + if (ch_iter != '\0') { \ + if (predicate) {\ + _str++; \ + continue; \ + } \ + _val = FALSE; \ + } \ + break; \ + } \ + } \ + _val; \ + }) + +#define NM_STRCHAR_ANY(str, ch_iter, predicate) \ + ({ \ + gboolean _val = FALSE; \ + const char *_str = (str); \ + \ + if (_str) { \ + for (;;) { \ + const char ch_iter = _str[0]; \ + \ + if (ch_iter != '\0') { \ + if (predicate) { \ + ; \ + } else { \ + _str++; \ + continue; \ + } \ + _val = TRUE; \ + } \ + break; \ + } \ + } \ + _val; \ + }) + +/*****************************************************************************/ + +/* NM_CACHED_QUARK() returns the GQuark for @string, but caches + * it in a static variable to speed up future lookups. + * + * @string must be a string literal. + */ +#define NM_CACHED_QUARK(string) \ + ({ \ + static GQuark _nm_cached_quark = 0; \ + \ + (G_LIKELY (_nm_cached_quark != 0) \ + ? _nm_cached_quark \ + : (_nm_cached_quark = g_quark_from_static_string (""string""))); \ + }) + +/* NM_CACHED_QUARK_FCN() is essentially the same as G_DEFINE_QUARK + * with two differences: + * - @string must be a quoted string-literal + * - @fcn must be the full function name, while G_DEFINE_QUARK() appends + * "_quark" to the function name. + * Both properties of G_DEFINE_QUARK() are non favorable, because you can no + * longer grep for string/fcn -- unless you are aware that you are searching + * for G_DEFINE_QUARK() and omit quotes / append _quark(). With NM_CACHED_QUARK_FCN(), + * ctags/cscope can locate the use of @fcn (though it doesn't recognize that + * NM_CACHED_QUARK_FCN() defines it). + */ +#define NM_CACHED_QUARK_FCN(string, fcn) \ +GQuark \ +fcn (void) \ +{ \ + return NM_CACHED_QUARK (string); \ +} + +/*****************************************************************************/ + +#define nm_streq(s1, s2) (strcmp (s1, s2) == 0) +#define nm_streq0(s1, s2) (g_strcmp0 (s1, s2) == 0) + +/*****************************************************************************/ + +static inline GString * +nm_gstring_prepare (GString **l) +{ + if (*l) + g_string_set_size (*l, 0); + else + *l = g_string_sized_new (30); + return *l; +} + +static inline const char * +nm_str_not_empty (const char *str) +{ + return str && str[0] ? str : NULL; +} + +static inline char * +nm_strdup_not_empty (const char *str) +{ + return str && str[0] ? g_strdup (str) : NULL; +} + +static inline char * +nm_str_realloc (char *str) +{ + gs_free char *s = str; + + /* Returns a new clone of @str and frees @str. The point is that @str + * possibly points to a larger chunck of memory. We want to freshly allocate + * a buffer. + * + * We could use realloc(), but that might not do anything or leave + * @str in its memory pool for chunks of a different size (bad for + * fragmentation). + * + * This is only useful when we want to keep the buffer around for a long + * time and want to re-allocate a more optimal buffer. */ + + return g_strdup (s); +} + +/*****************************************************************************/ + +#define NM_PRINT_FMT_QUOTED(cond, prefix, str, suffix, str_else) \ + (cond) ? (prefix) : "", \ + (cond) ? (str) : (str_else), \ + (cond) ? (suffix) : "" +#define NM_PRINT_FMT_QUOTE_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg), "\"", "(null)") + +/*****************************************************************************/ + +/* glib/C provides the following kind of assertions: + * - assert() -- disable with NDEBUG + * - g_return_if_fail() -- disable with G_DISABLE_CHECKS + * - g_assert() -- disable with G_DISABLE_ASSERT + * but they are all enabled by default and usually even production builds have + * these kind of assertions enabled. It also means, that disabling assertions + * is an untested configuration, and might have bugs. + * + * Add our own assertion macro nm_assert(), which is disabled by default and must + * be explicitly enabled. They are useful for more expensive checks or checks that + * depend less on runtime conditions (that is, are generally expected to be true). */ + +#ifndef NM_MORE_ASSERTS +#define NM_MORE_ASSERTS 0 +#endif + +#if NM_MORE_ASSERTS +#define nm_assert(cond) G_STMT_START { g_assert (cond); } G_STMT_END +#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } else { g_assert (FALSE && (cond)); } } G_STMT_END +#define nm_assert_not_reached() G_STMT_START { g_assert_not_reached (); } G_STMT_END +#else +#define nm_assert(cond) G_STMT_START { if (FALSE) { if (cond) { } } } G_STMT_END +#define nm_assert_se(cond) G_STMT_START { if (G_LIKELY (cond)) { ; } } G_STMT_END +#define nm_assert_not_reached() G_STMT_START { ; } G_STMT_END +#endif + +/*****************************************************************************/ + +#define NM_GOBJECT_PROPERTIES_DEFINE_BASE(...) \ +typedef enum { \ + _PROPERTY_ENUMS_0, \ + __VA_ARGS__ \ + _PROPERTY_ENUMS_LAST, \ +} _PropertyEnums; \ +static GParamSpec *obj_properties[_PROPERTY_ENUMS_LAST] = { NULL, } + +#define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \ +NM_GOBJECT_PROPERTIES_DEFINE_BASE (__VA_ARGS__); \ +static inline void \ +_notify (obj_type *obj, _PropertyEnums prop) \ +{ \ + nm_assert (G_IS_OBJECT (obj)); \ + nm_assert ((gsize) prop < G_N_ELEMENTS (obj_properties)); \ + g_object_notify_by_pspec ((GObject *) obj, obj_properties[prop]); \ +} + +/*****************************************************************************/ + +#define _NM_GET_PRIVATE(self, type, is_check, ...) (&(NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv)) +#if _NM_CC_SUPPORT_AUTO_TYPE +#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \ + ({ \ + _nm_auto_type _self = NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__); \ + \ + NM_PROPAGATE_CONST (_self, _self->_priv); \ + }) +#else +#define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) (NM_GOBJECT_CAST_NON_NULL (type, (self), is_check, ##__VA_ARGS__)->_priv) +#endif + +/*****************************************************************************/ + +static inline gpointer +nm_g_object_ref (gpointer obj) +{ + /* g_object_ref() doesn't accept NULL. */ + if (obj) + g_object_ref (obj); + return obj; +} +#define nm_g_object_ref(obj) ((typeof (obj)) nm_g_object_ref (obj)) + +static inline void +nm_g_object_unref (gpointer obj) +{ + /* g_object_unref() doesn't accept NULL. Usully, we workaround that + * by using g_clear_object(), but sometimes that is not convinient + * (for example as as destroy function for a hash table that can contain + * NULL values). */ + if (obj) + g_object_unref (obj); +} + +/* Assigns GObject @obj to destination @pdst, and takes an additional ref. + * The previous value of @pdst is unrefed. + * + * It makes sure to first increase the ref-count of @obj, and handles %NULL + * @obj correctly. + * */ +#define nm_g_object_ref_set(pp, obj) \ + ({ \ + typeof (*(pp)) *const _pp = (pp); \ + typeof (**_pp) *const _obj = (obj); \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ + \ + if ( _pp \ + && ((_p = *_pp) != _obj)) { \ + if (_obj) { \ + nm_assert (G_IS_OBJECT (_obj)); \ + g_object_ref (_obj); \ + } \ + if (_p) { \ + nm_assert (G_IS_OBJECT (_p)); \ + *_pp = NULL; \ + g_object_unref (_p); \ + } \ + *_pp = _obj; \ + _changed = TRUE; \ + } \ + _changed; \ + }) + +/* basically, replaces + * g_clear_pointer (&location, g_free) + * with + * nm_clear_g_free (&location) + * + * Another advantage is that by using a macro and typeof(), it is more + * typesafe and gives you for example a compiler warning when pp is a const + * pointer or points to a const-pointer. + */ +#define nm_clear_g_free(pp) \ + ({ \ + typeof (*(pp)) *_pp = (pp); \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ + \ + if ( _pp \ + && (_p = *_pp)) { \ + *_pp = NULL; \ + g_free (_p); \ + _changed = TRUE; \ + } \ + _changed; \ + }) + +#define nm_clear_g_object(pp) \ + ({ \ + typeof (*(pp)) *_pp = (pp); \ + typeof (**_pp) *_p; \ + gboolean _changed = FALSE; \ + \ + if ( _pp \ + && (_p = *_pp)) { \ + nm_assert (G_IS_OBJECT (_p)); \ + *_pp = NULL; \ + g_object_unref (_p); \ + _changed = TRUE; \ + } \ + _changed; \ + }) + +static inline gboolean +nm_clear_g_source (guint *id) +{ + if (id && *id) { + g_source_remove (*id); + *id = 0; + return TRUE; + } + return FALSE; +} + +static inline gboolean +nm_clear_g_signal_handler (gpointer self, gulong *id) +{ + if (id && *id) { + g_signal_handler_disconnect (self, *id); + *id = 0; + return TRUE; + } + return FALSE; +} + +static inline gboolean +nm_clear_g_variant (GVariant **variant) +{ + if (variant && *variant) { + g_variant_unref (*variant); + *variant = NULL; + return TRUE; + } + return FALSE; +} + +static inline gboolean +nm_clear_g_cancellable (GCancellable **cancellable) +{ + if (cancellable && *cancellable) { + g_cancellable_cancel (*cancellable); + g_object_unref (*cancellable); + *cancellable = NULL; + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ + +/* Determine whether @x is a power of two (@x being an integer type). + * Basically, this returns TRUE, if @x has exactly one bit set. + * For negative values and zero, this always returns FALSE. */ +#define nm_utils_is_power_of_two(x) ({ \ + typeof(x) __x = (x); \ + \ + ( (__x > ((typeof(__x)) 0)) \ + && ((__x & (__x - (((typeof(__x)) 1)))) == ((typeof(__x)) 0))); \ + }) + +/*****************************************************************************/ + +#define NM_UTILS_LOOKUP_DEFAULT(v) return (v) +#define NM_UTILS_LOOKUP_DEFAULT_WARN(v) g_return_val_if_reached (v) +#define NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(v) { nm_assert_not_reached (); return (v); } +#define NM_UTILS_LOOKUP_ITEM(v, n) (void) 0; case v: return (n); (void) 0 +#define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, ""n"") +#define NM_UTILS_LOOKUP_ITEM_IGNORE(v) (void) 0; case v: break; (void) 0 +#define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() (void) 0; default: break; (void) 0 + +#define _NM_UTILS_LOOKUP_DEFINE(scope, fcn_name, lookup_type, result_type, unknown_val, ...) \ +scope result_type \ +fcn_name (lookup_type val) \ +{ \ + switch (val) { \ + (void) 0, \ + __VA_ARGS__ \ + (void) 0; \ + }; \ + { unknown_val; } \ +} + +#define NM_UTILS_LOOKUP_STR_DEFINE(fcn_name, lookup_type, unknown_val, ...) \ + _NM_UTILS_LOOKUP_DEFINE (, fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__) +#define NM_UTILS_LOOKUP_STR_DEFINE_STATIC(fcn_name, lookup_type, unknown_val, ...) \ + _NM_UTILS_LOOKUP_DEFINE (static, fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__) + +/* Call the string-lookup-table function @fcn_name. If the function returns + * %NULL, the numeric index is converted to string using a alloca() buffer. + * Beware: this macro uses alloca(). */ +#define NM_UTILS_LOOKUP_STR(fcn_name, idx) \ + ({ \ + typeof (idx) _idx = (idx); \ + const char *_s; \ + \ + _s = fcn_name (_idx); \ + if (!_s) { \ + _s = g_alloca (30); \ + \ + g_snprintf ((char *) _s, 30, "(%lld)", (long long) _idx); \ + } \ + _s; \ + }) + +/*****************************************************************************/ + +/* check if @flags has exactly one flag (@check) set. You should call this + * only with @check being a compile time constant and a power of two. */ +#define NM_FLAGS_HAS(flags, check) \ + ( G_STATIC_ASSERT_EXPR ((check) > 0 && ((check) & ((check) - 1)) == 0), NM_FLAGS_ANY ((flags), (check)) ) + +#define NM_FLAGS_ANY(flags, check) ( ( ((flags) & (check)) != 0 ) ? TRUE : FALSE ) +#define NM_FLAGS_ALL(flags, check) ( ( ((flags) & (check)) == (check) ) ? TRUE : FALSE ) + +#define NM_FLAGS_SET(flags, val) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags | _val; \ + }) + +#define NM_FLAGS_UNSET(flags, val) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + _flags & (~_val); \ + }) + +#define NM_FLAGS_ASSIGN(flags, val, assign) ({ \ + const typeof(flags) _flags = (flags); \ + const typeof(flags) _val = (val); \ + \ + (assign) \ + ? _flags | (_val) \ + : _flags & (~_val); \ + }) + +/*****************************************************************************/ + +#define _NM_BACKPORT_SYMBOL_IMPL(VERSION, RETURN_TYPE, ORIG_FUNC, VERSIONED_FUNC, ARGS_TYPED, ARGS) \ +RETURN_TYPE VERSIONED_FUNC ARGS_TYPED; \ +RETURN_TYPE VERSIONED_FUNC ARGS_TYPED \ +{ \ + return ORIG_FUNC ARGS; \ +} \ +RETURN_TYPE ORIG_FUNC ARGS_TYPED; \ +__asm__(".symver "G_STRINGIFY(VERSIONED_FUNC)", "G_STRINGIFY(ORIG_FUNC)"@"G_STRINGIFY(VERSION)) + +#define NM_BACKPORT_SYMBOL(VERSION, RETURN_TYPE, FUNC, ARGS_TYPED, ARGS) \ +_NM_BACKPORT_SYMBOL_IMPL(VERSION, RETURN_TYPE, FUNC, _##FUNC##_##VERSION, ARGS_TYPED, ARGS) + +/*****************************************************************************/ + +#define nm_str_skip_leading_spaces(str) \ + ({ \ + typeof (*(str)) *_str = (str); \ + _nm_unused const char *_str_type_check = _str; \ + \ + if (_str) { \ + while (g_ascii_isspace (_str[0])) \ + _str++; \ + } \ + _str; \ + }) + +static inline char * +nm_strstrip (char *str) +{ + /* g_strstrip doesn't like NULL. */ + return str ? g_strstrip (str) : NULL; +} + +static inline const char * +nm_strstrip_avoid_copy (const char *str, char **str_free) +{ + gsize l; + char *s; + + nm_assert (str_free && !*str_free); + + if (!str) + return NULL; + + str = nm_str_skip_leading_spaces (str); + l = strlen (str); + if ( l == 0 + || !g_ascii_isspace (str[l - 1])) + return str; + while ( l > 0 + && g_ascii_isspace (str[l - 1])) + l--; + + s = g_new (char, l + 1); + memcpy (s, str, l); + s[l] = '\0'; + *str_free = s; + return s; +} + +/* g_ptr_array_sort()'s compare function takes pointers to the + * value. Thus, you cannot use strcmp directly. You can use + * nm_strcmp_p(). + * + * Like strcmp(), this function is not forgiving to accept %NULL. */ +static inline int +nm_strcmp_p (gconstpointer a, gconstpointer b) +{ + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); + + return strcmp (s1, s2); +} + +/* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data(). + * g_ptr_array_sort() just casts nm_strcmp_p() to a function of different + * signature. I guess, in glib there are knowledgeable people that ensure + * that this additional argument doesn't cause problems due to different ABI + * for every architecture that glib supports. + * For NetworkManager, we'd rather avoid such stunts. + **/ +static inline int +nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data) +{ + const char *s1 = *((const char **) a); + const char *s2 = *((const char **) b); + + return strcmp (s1, s2); +} + +static inline int +nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + const guint32 a = *((const guint32 *) p_a); + const guint32 b = *((const guint32 *) p_b); + + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + +/*****************************************************************************/ + +/* Taken from systemd's UNIQ_T and UNIQ macros. */ + +#define NM_UNIQ_T(x, uniq) G_PASTE(__unique_prefix_, G_PASTE(x, uniq)) +#define NM_UNIQ __COUNTER__ + +/*****************************************************************************/ + +/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate + * the argument possibly twice. + * + * Taken from systemd's MIN()/MAX() macros. */ + +#define NM_MIN(a, b) __NM_MIN(NM_UNIQ, a, NM_UNIQ, b) +#define __NM_MIN(aq, a, bq, b) \ + ({ \ + typeof (a) NM_UNIQ_T(A, aq) = (a); \ + typeof (b) NM_UNIQ_T(B, bq) = (b); \ + ((NM_UNIQ_T(A, aq) < NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \ + }) + +#define NM_MAX(a, b) __NM_MAX(NM_UNIQ, a, NM_UNIQ, b) +#define __NM_MAX(aq, a, bq, b) \ + ({ \ + typeof (a) NM_UNIQ_T(A, aq) = (a); \ + typeof (b) NM_UNIQ_T(B, bq) = (b); \ + ((NM_UNIQ_T(A, aq) > NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \ + }) + +#define NM_CLAMP(x, low, high) __NM_CLAMP(NM_UNIQ, x, NM_UNIQ, low, NM_UNIQ, high) +#define __NM_CLAMP(xq, x, lowq, low, highq, high) \ + ({ \ + typeof(x)NM_UNIQ_T(X,xq) = (x); \ + typeof(low) NM_UNIQ_T(LOW,lowq) = (low); \ + typeof(high) NM_UNIQ_T(HIGH,highq) = (high); \ + \ + ( (NM_UNIQ_T(X,xq) > NM_UNIQ_T(HIGH,highq)) \ + ? NM_UNIQ_T(HIGH,highq) \ + : (NM_UNIQ_T(X,xq) < NM_UNIQ_T(LOW,lowq)) \ + ? NM_UNIQ_T(LOW,lowq) \ + : NM_UNIQ_T(X,xq)); \ + }) + +/*****************************************************************************/ + +static inline guint +nm_encode_version (guint major, guint minor, guint micro) +{ + /* analog to the preprocessor macro NM_ENCODE_VERSION(). */ + return (major << 16) | (minor << 8) | micro; +} + +static inline void +nm_decode_version (guint version, guint *major, guint *minor, guint *micro) +{ + *major = (version & 0xFFFF0000u) >> 16; + *minor = (version & 0x0000FF00u) >> 8; + *micro = (version & 0x000000FFu); +} + +/*****************************************************************************/ + +/* taken from systemd's DECIMAL_STR_MAX() + * + * Returns the number of chars needed to format variables of the + * specified type as a decimal string. Adds in extra space for a + * negative '-' prefix (hence works correctly on signed + * types). Includes space for the trailing NUL. */ +#define NM_DECIMAL_STR_MAX(type) \ + (2+(sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + +/*****************************************************************************/ + +/* if @str is NULL, return "(null)". Otherwise, allocate a buffer using + * alloca() of and fill it with @str. @str will be quoted with double quote. + * If @str is longer then @trunc_at, the string is truncated and the closing + * quote is instead '^' to indicate truncation. + * + * Thus, the maximum stack allocated buffer will be @trunc_at+3. */ +#define nm_strquote_a(trunc_at, str) \ + ({ \ + const char *const _str = (str); \ + \ + (_str \ + ? ({ \ + const gsize _trunc_at = (trunc_at); \ + const gsize _strlen_trunc = NM_MIN (strlen (_str), _trunc_at); \ + char *_buf; \ + \ + _buf = g_alloca (_strlen_trunc + 3); \ + _buf[0] = '"'; \ + memcpy (&_buf[1], _str, _strlen_trunc); \ + _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"'; \ + _buf[_strlen_trunc + 2] = '\0'; \ + _buf; \ + }) \ + : "(null)"); \ + }) + +#define nm_sprintf_buf(buf, format, ...) \ + ({ \ + char * _buf = (buf); \ + int _buf_len; \ + \ + /* some static assert trying to ensure that the buffer is statically allocated. + * It disallows a buffer size of sizeof(gpointer) to catch that. */ \ + G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \ + _buf_len = g_snprintf (_buf, sizeof (buf), \ + ""format"", ##__VA_ARGS__); \ + nm_assert (_buf_len < sizeof (buf)); \ + _buf; \ + }) + +#define nm_sprintf_bufa(n_elements, format, ...) \ + ({ \ + char *_buf; \ + int _buf_len; \ + typeof (n_elements) _n_elements = (n_elements); \ + \ + _buf = g_alloca (_n_elements); \ + _buf_len = g_snprintf (_buf, _n_elements, \ + ""format"", ##__VA_ARGS__); \ + nm_assert (_buf_len < _n_elements); \ + _buf; \ + }) + +/* aims to alloca() a buffer and fill it with printf(format, name). + * Note that format must not contain any format specifier except + * "%s". + * If the resulting string would be too large for stack allocation, + * it allocates a buffer with g_malloc() and assigns it to *p_val_to_free. */ +#define nm_construct_name_a(format, name, p_val_to_free) \ + ({ \ + const char *const _name = (name); \ + char **const _p_val_to_free = (p_val_to_free); \ + const gsize _name_len = strlen (_name); \ + char *_buf2; \ + \ + nm_assert (_p_val_to_free && !*_p_val_to_free); \ + if (NM_STRLEN (format) + _name_len < 200) \ + _buf2 = nm_sprintf_bufa (NM_STRLEN (format) + _name_len, format, _name); \ + else { \ + _buf2 = g_strdup_printf (format, _name); \ + *_p_val_to_free = _buf2; \ + } \ + (const char *) _buf2; \ + }) + +/*****************************************************************************/ + +/** + * The boolean type _Bool is C99 while we mostly stick to C89. However, _Bool is too + * convinient to miss and is effectively available in gcc and clang. So, just use it. + * + * Usually, one would include "stdbool.h" to get the "bool" define which aliases + * _Bool. We provide this define here, because we want to make use of it anywhere. + * (also, stdbool.h is again C99). + * + * Using _Bool has advantages over gboolean: + * + * - commonly _Bool is one byte large, instead of gboolean's 4 bytes (because gboolean + * is a typedef for gint). Especially when having boolean fields in a struct, we can + * thereby easily save some space. + * + * - _Bool type guarantees that two "true" expressions compare equal. E.g. the follwing + * will not work: + * gboolean v1 = 1; + * gboolean v2 = 2; + * g_assert_cmpint (v1, ==, v2); // will fail + * For that, we often to use !! to coerce gboolean values to 0 or 1: + * g_assert_cmpint (!!v2, ==, TRUE); + * With _Bool type, this will be handled properly by the compiler. + * + * - For structs, we might want to safe even more space and use bitfields: + * struct s1 { + * gboolean v1:1; + * }; + * But the problem here is that gboolean is signed, so that + * v1 will be either 0 or -1 (not 1, TRUE). Thus, the following + * fails: + * struct s1 s = { .v1 = TRUE, }; + * g_assert_cmpint (s1.v1, ==, TRUE); + * It will however work just fine with bool/_Bool while retaining the + * notion of having a boolean value. + * + * Also, add the defines for "true" and "false". Those are nicely highlighted by the editor + * as special types, contrary to glib's "TRUE"/"FALSE". + */ + +#ifndef bool +#define bool _Bool +#define true 1 +#define false 0 +#endif + + +#ifdef _G_BOOLEAN_EXPR +/* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR(). + * As glib's implementation uses a local variable _g_boolean_var_, + * we cannot do + * g_assert (some_macro ()); + * where some_macro() itself expands to ({g_assert(); ...}). + * In other words, you cannot have a g_assert() inside a g_assert() + * without getting a -Werror=shadow failure. + * + * Workaround that by re-defining _G_BOOLEAN_EXPR() + **/ +#undef _G_BOOLEAN_EXPR +#define __NM_G_BOOLEAN_EXPR_IMPL(v, expr) \ + ({ \ + int NM_UNIQ_T(V, v); \ + \ + if (expr) \ + NM_UNIQ_T(V, v) = 1; \ + else \ + NM_UNIQ_T(V, v) = 0; \ + NM_UNIQ_T(V, v); \ + }) +#define _G_BOOLEAN_EXPR(expr) __NM_G_BOOLEAN_EXPR_IMPL (NM_UNIQ, expr) +#endif + +/*****************************************************************************/ + +static inline int +nm_steal_fd (int *p_fd) +{ + int fd; + + if ( p_fd + && ((fd = *p_fd) >= 0)) { + *p_fd = -1; + return fd; + } + return -1; +} + +/** + * nm_close: + * + * Like close() but throws an assertion if the input fd is + * invalid. Closing an invalid fd is a programming error, so + * it's better to catch it early. + */ +static inline int +nm_close (int fd) +{ + int r; + + r = close (fd); + nm_assert (r != -1 || fd < 0 || errno != EBADF); + return r; +} + +#endif /* __NM_MACROS_INTERNAL_H__ */ diff --git a/src/backend/dbusadaptor.cpp b/src/backend/dbusadaptor.cpp new file mode 100644 index 00000000..0f22c845 --- /dev/null +++ b/src/backend/dbusadaptor.cpp @@ -0,0 +1,279 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp com.kylin.weather.xml -a dbusadaptor -c DbusAdaptor -l MainWindow + * + * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd. + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#include "dbusadaptor.h" +#include +#include +#include +#include +#include +#include +#include + +const QByteArray GSETTINGS_SCHEMA_KYLIN_NM = "org.ukui.kylin-nm.switch"; +const QString KEY_WIRELESS_SWITCH = "wirelessswitch"; +const QString KEY_WIRED_SWITCH = "wiredswitch"; + +/* + * Implementation of adaptor class DbusAdaptor + */ + +DbusAdaptor::DbusAdaptor(MainWindow *parent) + : QDBusAbstractAdaptor(parent) +{ + // constructor + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >>(); + //setAutoRelaySignals(true)后会自动转发mainwindow发出的同名信号,因此不必再额外写一个转发 + setAutoRelaySignals(true); +} + +DbusAdaptor::~DbusAdaptor() +{ + // destructor +} + +//无线列表 +QMap > DbusAdaptor::getWirelessList() +{ + QMap > map; + parent()->getWirelessList(map); + return map; +} + +bool DbusAdaptor::getWirelessSwitchBtnState() +{ + return parent()->getWirelessSwitchBtnState(); +} + +//有线列表 +QMap> DbusAdaptor::getWiredList() +{ + QMap> map; + parent()->getWiredList(map); + return map; +} + +//有线开关 +void DbusAdaptor::setWiredSwitchEnable(bool enable) +{ + //todo mainwindow调用backend 对开关 打开/关闭 + if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA_KYLIN_NM)) { + QGSettings *gsetting = new QGSettings(GSETTINGS_SCHEMA_KYLIN_NM); + if (gsetting->get(KEY_WIRED_SWITCH).toBool() != enable) { + gsetting->set(KEY_WIRED_SWITCH, enable); + } + delete gsetting; + gsetting = nullptr; + } else { + qDebug()<<"isSchemaInstalled false"; + } +} + +//无线开关 +void DbusAdaptor::setWirelessSwitchEnable(bool enable) +{ + //todo mainwindow调用backend 对开关 打开/关闭 +// if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA_KYLIN_NM)) { +// QGSettings *gsetting = new QGSettings(GSETTINGS_SCHEMA_KYLIN_NM); +// if (gsetting->get(KEY_WIRELESS_SWITCH).toBool() != enable) { +// gsetting->set(KEY_WIRELESS_SWITCH, enable); +// } +// delete gsetting; +// gsetting = nullptr; +// } else { +// qDebug()<<"isSchemaInstalled false"; +// } + parent()->setWirelessSwitchEnable(enable); +} + +//启用/禁用网卡 +void DbusAdaptor::setDeviceEnable(QString devName, bool enable) +{ + parent()->setWiredDeviceEnable(devName, enable); +} + +//设置默认网卡 +//void DbusAdaptor::setDefaultWiredDevice(QString deviceName) +//{ +// if (!checkDeviceExist(WIRED, deviceName)) { +// return; +// } +// setDefaultDevice(WIRED, deviceName); +// parent()->setWiredDefaultDevice(deviceName); +// return; +//} + +//QString DbusAdaptor::getDefaultWiredDevice() +//{ +// QSettings * m_settings = new QSettings(CONFIG_FILE_PATH, QSettings::IniFormat); +// m_settings->beginGroup("DEFAULTCARD"); +// QString key("wired"); +// QString deviceName = m_settings->value(key, "").toString(); +// m_settings->endGroup(); +// delete m_settings; +// m_settings = nullptr; +// return deviceName; +//} + +//void DbusAdaptor::setDefaultWirelessDevice(QString deviceName) +//{ +// if (!checkDeviceExist(WIRED, deviceName)) { +// return; +// } +// setDefaultDevice(WIRELESS, deviceName); +// parent()->setWirelessDefaultDevice(deviceName); +// return; +//} + +//QString DbusAdaptor::getDefaultWirelessDevice() +//{ +// QSettings * m_settings = new QSettings(CONFIG_FILE_PATH, QSettings::IniFormat); +// m_settings->beginGroup("DEFAULTCARD"); +// QString key("wireless"); +// QString deviceName = m_settings->value(key, "").toString(); +// m_settings->endGroup(); +// delete m_settings; +// m_settings = nullptr; +// return deviceName; +//} + +//连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid +void DbusAdaptor::activateConnect(int type, QString devName, QString ssid) +{ + if (type == WIRED) { + parent()->activateWired(devName,ssid); + } else if (type == WIRELESS) { + parent()->activateWireless(devName,ssid); + } else { + qDebug() << "[DbusAdaptor] activateConnect type is invalid"; + } +} + +//断开连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid +void DbusAdaptor::deActivateConnect(int type, QString devName, QString ssid) +{ + if (type == WIRED) { + qDebug() << "deactivateWired"; + parent()->deactivateWired(devName,ssid); + } else if (type == WIRELESS) { + parent()->deactivateWireless(devName,ssid); + } else { + qDebug() << "[DbusAdaptor] deactivateConnect type is invalid"; + } +} + +//获取设备列表和启用/禁用状态 +QMap DbusAdaptor::getDeviceListAndEnabled(int devType) +{ + QMap map; + map.clear(); + getDeviceEnableState(devType, map); + return map; +} + +//获取无线设备能力 +QMap DbusAdaptor::getWirelessDeviceCap() +{ + QMap map; + parent()->getWirelessDeviceCap(map); + return map; +} + +//唤起属性页 根据网卡类型 参数2 为ssid/uuid +void DbusAdaptor::showPropertyWidget(QString devName, QString ssid) +{ + qDebug() << "showPropertyWidget"; + parent()->showPropertyWidget(devName,ssid); +} + +//唤起新建有线连接界面 +void DbusAdaptor::showCreateWiredConnectWidget(QString devName) +{ + qDebug() << "showCreateWiredConnectWidget"; + parent()->showCreateWiredConnectWidget(devName); +} + +//唤起加入其他无线网络界面 +void DbusAdaptor::showAddOtherWlanWidget(QString devName) +{ + qDebug() << "showAddOtherWlanWidget"; + parent()->showAddOtherWlanWidget(devName); +} + +//开启热点 +void DbusAdaptor::activeWirelessAp(const QString apName, const QString apPassword, const QString band, const QString apDevice) +{ + parent()->activeWirelessAp(apName, apPassword, band, apDevice); +} + +//断开热点 +void DbusAdaptor::deactiveWirelessAp(const QString apName, const QString uuid) +{ + parent()->deactiveWirelessAp(apName, uuid); +} + +//获取热点 +QStringList DbusAdaptor::getStoredApInfo() +{ + QStringList list; + list.clear(); + parent()->getStoredApInfo(list); + return list; +} + +//获取热点path +QString DbusAdaptor::getApConnectionPath(QString uuid) +{ + QString path; + path.clear(); + parent()->getApConnectionPath(path, uuid); + return path; +} + +//获取热点path +QString DbusAdaptor::getActiveConnectionPath(QString uuid) +{ + QString path; + path.clear(); + parent()->getActiveConnectionPath(path, uuid); + return path; +} + +QStringList DbusAdaptor::getApInfoBySsid(QString devName, QString ssid) +{ + QStringList list; + list.clear(); + parent()->getApInfoBySsid(devName, ssid, list); + return list; +} + +void DbusAdaptor::showKylinNM(int type) +{ + parent()->onShowMainWindow(type); +} + +//扫描 +void DbusAdaptor::reScan() +{ + parent()->rescan(); +} + +void DbusAdaptor::keyRingInit() +{ + parent()->keyRingInit(); +} + +void DbusAdaptor::keyRingClear() +{ + parent()->keyRingClear(); +} diff --git a/src/backend/dbusadaptor.h b/src/backend/dbusadaptor.h new file mode 100644 index 00000000..6cb0f411 --- /dev/null +++ b/src/backend/dbusadaptor.h @@ -0,0 +1,128 @@ +/* + * This file was generated by qdbusxml2cpp version 0.8 + * Command line was: qdbusxml2cpp com.kylin.weather.xml -a dbusadaptor -c DbusAdaptor -l MainWindow + * + * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd. + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#ifndef DBUSADAPTOR_H +#define DBUSADAPTOR_H + +#include +#include +#include + +#include "tabpage.h" +#include "../dbus-interface/kylinnetworkdeviceresource.h" +QT_BEGIN_NAMESPACE +class QByteArray; +//template class QList; +template class QMap; +class QString; +class QStringList; +class QVariant; +template class QVector; +QT_END_NAMESPACE + +/* + * Adaptor class for interface com.kylin.weather + */ + +#include "mainwindow.h" + +class DbusAdaptor: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.kylin.network") +public: + DbusAdaptor(MainWindow *parent); + virtual ~DbusAdaptor(); + + inline MainWindow *parent() const + { return static_cast(QObject::parent()); } + +public: // PROPERTIES +public Q_SLOTS: // METHODS + //无线列表 + QMap > getWirelessList(); + //有线列表 + QMap> getWiredList(); + //有线总开关 + Q_NOREPLY void setWiredSwitchEnable(bool enable); + //无线总开关 + Q_NOREPLY void setWirelessSwitchEnable(bool enable); + //有线网卡开关 + Q_NOREPLY void setDeviceEnable(QString devName, bool enable); + //设置默认网卡 +// Q_NOREPLY void setDefaultWiredDevice(QString deviceName); +// QString getDefaultWiredDevice(); +// Q_NOREPLY void setDefaultWirelessDevice(QString deviceName); +// QString getDefaultWirelessDevice(); + //连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid + Q_NOREPLY void activateConnect(int type, QString devName, QString ssid); + //断开连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid + Q_NOREPLY void deActivateConnect(int type, QString devName, QString ssid); + //获取设备列表和启用/禁用状态 + QMap getDeviceListAndEnabled(int devType); + //获取无线设备能力 + QMap getWirelessDeviceCap(); + //唤起属性页 根据网卡类型 参数2 为ssid/uuid + Q_NOREPLY void showPropertyWidget(QString devName, QString ssid); + //唤起新建有线连接界面 + Q_NOREPLY void showCreateWiredConnectWidget(QString devName); + //唤起加入其他无线网络界面 + Q_NOREPLY void showAddOtherWlanWidget(QString devName); + //开启热点 + void activeWirelessAp(const QString apName, const QString apPassword, const QString band, const QString apDevice); + //断开热点 + void deactiveWirelessAp(const QString apName, const QString uuid); + //获取热点 + QStringList getStoredApInfo(); + QStringList getApInfoBySsid(QString devName, QString ssid); + QString getApConnectionPath(QString uuid); + QString getActiveConnectionPath(QString uuid); + //wifi扫描 + void reScan(); + //keyring + void keyRingInit(); + void keyRingClear(); + //just show + void showKylinNM(int type); + + bool getWirelessSwitchBtnState(); + +Q_SIGNALS: // SIGNALS +// void wirelessActivating(QString devName, QString ssid); +// void wiredActivating(QString devName, QString ssid); + void lanAdd(QString devName, QStringList info); + void lanRemove(QString dbusPath); + void lanUpdate(QString devName, QStringList info); + void wlanAdd(QString devName, QStringList info); + void wlanRemove(QString devName,QString ssid); + void wlanactiveConnectionStateChanged(QString devName, QString ssid, QString uuid, int status); + void lanActiveConnectionStateChanged(QString devName, QString uuid, int status); + //仅失败,若成功直接发listUpdate + void activateFailed(QString errorMessage); + void deactivateFailed(QString errorMessage); + //设备插拔 + void deviceStatusChanged(); + void deviceNameChanged(QString oldName, QString newName, int type); + void wirelessSwitchBtnChanged(bool state); + //热点断开 + void hotspotDeactivated(QString devName, QString ssid); + //热点连接 + void hotspotActivated(QString devName, QString ssid, QString uuid, QString activePath, QString settingPath); + + //信号强度变化 + void signalStrengthChange(QString devName, QString ssid, int strength); + //安全性变化 + void secuTypeChange(QString devName, QString ssid, QString secuType); + //列表排序 + void timeToUpdate(); +}; + +#endif diff --git a/src/backend/hotspot/dlghotspotcreate.cpp b/src/backend/hotspot/dlghotspotcreate.cpp new file mode 100644 index 00000000..ba48b4f2 --- /dev/null +++ b/src/backend/hotspot/dlghotspotcreate.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see setupUi(this); + + this->setWindowFlags(Qt::FramelessWindowHint); + this->setStyleSheet("background-color:white;"); + + ui->lbLeftup->setStyleSheet("QLabel{background-color:#266ab5;}"); + ui->lbLeftupIcon->setStyleSheet("QLabel{background-image:url(:/res/h/no-pwd-wifi.png);background-color:transparent;}"); + ui->lbLeftupTitle->setStyleSheet("QLabel{font-size:12px;color:#ffffff;background-color:transparent;}"); + ui->btnCancel->setStyleSheet("QPushButton{border:1px solid #aaaaaa;background-color:#f5f5f5;}" + "QPushButton:Hover{border:2px solid #629ee8;background-color:#eeeeee;}" + "QPushButton:Pressed{border:1px solid #aaaaaa;background-color:#d8d8d8;}"); + ui->btnOk->setStyleSheet("QPushButton{border:1px solid #aaaaaa;background-color:#f5f5f5;}" + "QPushButton:Hover{border:2px solid #629ee8;background-color:#eeeeee;}" + "QPushButton:Pressed{border:1px solid #aaaaaa;background-color:#d8d8d8;}"); + ui->checkBoxPwd->setStyleSheet("QCheckBox::indicator {width: 18px; height: 9px;}" + "QCheckBox::indicator:checked {image: url(:/res/h/show-pwd.png);}" + "QCheckBox::indicator:unchecked {image: url(:/res/h/hide-pwd.png);}"); + + ui->lbLeftupTitle->setText(tr("Create Hotspot")); //创建个人热点 + ui->lbNetName->setText(tr("Network name")); //网络名称: + ui->lbSecurity->setText(tr("WLAN security")); //WLAN 安全性: + ui->lbPassword->setText(tr("Password")); //密码: + ui->btnCancel->setText(tr("Cancel")); //取消 + ui->btnOk->setText(tr("Ok")); //确定 + ui->btnOk->setEnabled(false); + + ui->cbxSecurity->addItem(tr("None")); //无 + ui->cbxSecurity->addItem(tr("WPA and WPA2 Personal")); //WPA 及 WPA2 个人 + ui->cbxSecurity->setCurrentIndex(1); + connect(ui->cbxSecurity,SIGNAL(currentIndexChanged(QString)),this,SLOT(changeDialog())); +} + +DlgHotspotCreate::~DlgHotspotCreate() +{ + delete ui; +} + +void DlgHotspotCreate::mousePressEvent(QMouseEvent *event){ + if(event->button() == Qt::LeftButton){ + this->isPress = true; + this->winPos = this->pos(); + this->dragPos = event->globalPos(); + event->accept(); + } +} +void DlgHotspotCreate::mouseReleaseEvent(QMouseEvent *event){ + this->isPress = false; + this->setWindowOpacity(1); +} +void DlgHotspotCreate::mouseMoveEvent(QMouseEvent *event){ + if(this->isPress){ + this->move(this->winPos - (this->dragPos - event->globalPos())); + this->setWindowOpacity(0.9); + event->accept(); + } +} + +void DlgHotspotCreate::on_btnCancel_clicked() +{ + this->close(); + Q_EMIT btnHotspotState(); +} + +void DlgHotspotCreate::on_btnOk_clicked() +{ + //nmcli device wifi hotspot [ifname ifname] [con-name name] [ssid SSID] [band {a | bg}] [channel channel] [password password] + //example: nmcli device wifi hotspot ifname wlan0 con-name MyHostspot ssid MyHostspotSSID password 12345678 + QString str; + if(ui->cbxSecurity->currentIndex() == 0 ){ + str = "nmcli device wifi hotspot ifname '" + wirelessCardName + "' con-name '" + ui->leNetName->text() + "' ssid '" + ui->leNetName->text() + "' SSID"; + }else{ + str = "nmcli device wifi hotspot ifname '" + wirelessCardName + "' con-name '" + ui->leNetName->text() + "' ssid '" + ui->leNetName->text() + "' password '" + ui->lePassword->text() + "'"; + } + Utils::m_system(str.toUtf8().data()); + + this->close(); + Q_EMIT updateHotspotList(); +} + +void DlgHotspotCreate::on_checkBoxPwd_stateChanged(int arg1) +{ + if (arg1 == 0) { + ui->lePassword ->setEchoMode(QLineEdit::Password); + } else { + ui->lePassword->setEchoMode(QLineEdit::Normal); + } +} + +void DlgHotspotCreate::on_leNetName_textEdited(const QString &arg1) +{ + if(ui->cbxSecurity->currentIndex() == 0 ){ + if (ui->leNetName->text() == ""){ + ui->btnOk->setEnabled(false); + } else { + ui->btnOk->setEnabled(true); + } + }else{ + if (ui->leNetName->text() == "" || ui->lePassword->text().size() < 5){ + ui->btnOk->setEnabled(false); + } else { + ui->btnOk->setEnabled(true); + } + } +} + +void DlgHotspotCreate::on_lePassword_textEdited(const QString &arg1) +{ + if (ui->leNetName->text() == "" || ui->lePassword->text().size() < 5){ + ui->btnOk->setEnabled(false); + } else { + ui->btnOk->setEnabled(true); + } +} + +void DlgHotspotCreate::changeDialog() +{ + if(ui->cbxSecurity->currentIndex()==0){ + ui->lbPassword->setEnabled(false); + ui->lePassword->setEnabled(false); + ui->checkBoxPwd->setEnabled(false); + } else { + ui->lbPassword->setEnabled(true); + ui->lePassword->setEnabled(true); + ui->checkBoxPwd->setEnabled(true); + } +} diff --git a/src/backend/hotspot/dlghotspotcreate.h b/src/backend/hotspot/dlghotspotcreate.h new file mode 100644 index 00000000..d3aa5387 --- /dev/null +++ b/src/backend/hotspot/dlghotspotcreate.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include + +namespace Ui { +class DlgHotspotCreate; +} + +class DlgHotspotCreate : public QDialog +{ + Q_OBJECT + +public: + explicit DlgHotspotCreate(QString wiFiCardName, QWidget *parent = nullptr); + ~DlgHotspotCreate(); + +public Q_SLOTS: + void changeDialog(); + +private Q_SLOTS: + void on_btnCancel_clicked(); + + void on_btnOk_clicked(); + + void on_checkBoxPwd_stateChanged(int arg1); + + void on_leNetName_textEdited(const QString &arg1); + + void on_lePassword_textEdited(const QString &arg1); + +private: + Ui::DlgHotspotCreate *ui; + + QString wirelessCardName; + + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + bool isPress; + QPoint winPos; + QPoint dragPos; + +Q_SIGNALS: + void updateHotspotList(); + void btnHotspotState(); +}; + +#endif // DLGHOTSPOTCREATE_H diff --git a/src/backend/hotspot/dlghotspotcreate.ui b/src/backend/hotspot/dlghotspotcreate.ui new file mode 100644 index 00000000..989108f6 --- /dev/null +++ b/src/backend/hotspot/dlghotspotcreate.ui @@ -0,0 +1,169 @@ + + + DlgHotspotCreate + + + + 0 + 0 + 432 + 250 + + + + Dialog + + + + + 0 + 0 + 120 + 32 + + + + + + + + + + 9 + 9 + 16 + 16 + + + + + + + + + + 34 + 6 + 80 + 20 + + + + + + + + + + 215 + 210 + 90 + 30 + + + + + + + + + + 315 + 210 + 90 + 30 + + + + + + + + + + 76 + 60 + 90 + 20 + + + + + + + + + + 175 + 55 + 200 + 32 + + + + + + + 76 + 105 + 90 + 20 + + + + + + + + + + 175 + 100 + 200 + 32 + + + + + + + 76 + 150 + 90 + 20 + + + + + + + + + + 175 + 145 + 200 + 32 + + + + QLineEdit::Password + + + + + + 350 + 157 + 18 + 9 + + + + + + + + + + diff --git a/src/backend/hotspot/hotspot.pri b/src/backend/hotspot/hotspot.pri new file mode 100644 index 00000000..76750347 --- /dev/null +++ b/src/backend/hotspot/hotspot.pri @@ -0,0 +1,11 @@ +INCLUDEPATH += $$PWD + +FORMS += \ + $$PWD/dlghotspotcreate.ui + +HEADERS += \ + $$PWD/dlghotspotcreate.h + +SOURCES += \ + $$PWD/dlghotspotcreate.cpp + diff --git a/src/backend/kylinarping.h b/src/backend/kylinarping.h new file mode 100644 index 00000000..b1aa98be --- /dev/null +++ b/src/backend/kylinarping.h @@ -0,0 +1,120 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINARPING_H +#define KYLINARPING_H + +#include +#include +#include + +static cap_flag_value_t cap_raw = CAP_CLEAR; +static const cap_value_t caps[] = { CAP_NET_RAW }; + +static void limit_capabilities() +{ + cap_t cap_p; + + cap_p = cap_get_proc(); + if (!cap_p) { + qWarning()<<"cap_get_proc failed."; + } + + cap_get_flag(cap_p, CAP_NET_RAW, CAP_PERMITTED, &cap_raw); + + if (cap_raw != CAP_CLEAR) { + if (cap_clear(cap_p) < 0) { + qWarning()<<"cap clear failed"< +#include +#include + +#define FINAL_PACKS 2 + +__attribute__((const)) static inline size_t sll_len(const size_t halen) +{ + struct sockaddr_ll unused; + const size_t len = offsetof(struct sockaddr_ll, sll_addr) + halen; + + if (len < sizeof(unused)) + return sizeof(unused); + + return len; +} + + +KyIpv4Arping::KyIpv4Arping(QString ifaceName, QString ipAddress, int retryCount, int timeout, QObject *parent) : QObject(parent) +{ + m_ifaceName = ifaceName; + m_ipv4Address = ipAddress; + m_retryCount = retryCount; + m_timeout = timeout; + + memset(&m_srcAddress, 0, sizeof(m_srcAddress)); +} + +KyIpv4Arping::~KyIpv4Arping() +{ + +} + +void KyIpv4Arping::monoGetTime (struct timespec *ts) +{ +#ifdef CLOCK_MONOTONIC + if (clock_gettime (CLOCK_MONOTONIC, ts)) +#endif + { + static long freq = 0; + if (freq == 0) + freq = sysconf (_SC_CLK_TCK); + + struct tms dummy; + clock_t t = times (&dummy); + ts->tv_sec = t / freq; + ts->tv_nsec = (t % freq) * (1000000000 / freq); + } +} + +void KyIpv4Arping::saveMacAddress(const uint8_t *ptr, size_t len) +{ + int index; + char macAddress[64] = {0}; + + for (index = 0; index < len; index++) { + snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%02X", ptr[index]); + if (index != len - 1) { + snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%s", ":"); + } + } + + m_conflictMac = QString(macAddress); + return ; +} + +void KyIpv4Arping::setConflictFlag(bool isConflict) +{ + m_ipConflict = isConflict; +} + +int KyIpv4Arping::sendIpv4Packet() +{ + int err; + unsigned char buf[256]; + struct arphdr *ah = (struct arphdr *)buf; + unsigned char *p = (unsigned char *)(ah + 1); + struct sockaddr_ll *p_me = (struct sockaddr_ll *)&(m_me); + struct sockaddr_ll *p_he = (struct sockaddr_ll *)&(m_he); + + ah->ar_hrd = htons(p_me->sll_hatype); + if (ah->ar_hrd == htons(ARPHRD_FDDI)) + ah->ar_hrd = htons(ARPHRD_ETHER); + ah->ar_pro = htons(ETH_P_IP); + ah->ar_hln = p_me->sll_halen; + ah->ar_pln = 4; + ah->ar_op = htons(ARPOP_REQUEST); + + memcpy(p, &p_me->sll_addr, ah->ar_hln); + p += p_me->sll_halen; + + qWarning()<<"[KyIpv4Arping]" <<"m_src address:" << inet_ntoa(m_srcAddress); + memcpy(p, &m_srcAddress, 4); + p += 4; + + memcpy(p, &p_he->sll_addr, ah->ar_hln); + p += ah->ar_hln; + + memcpy(p, &m_destAddress, 4); + p += 4; + + err = sendto(m_ipv4Socket, buf, p - buf, 0, (struct sockaddr *)p_he, sll_len(ah->ar_hln)); + + return err; +} + +int KyIpv4Arping::ipv4PacketProcess(unsigned char *buf, ssize_t len, struct sockaddr_ll *from) +{ + struct arphdr *ah = (struct arphdr *)buf; + unsigned char *p = (unsigned char *)(ah + 1); + struct in_addr src_ip, dst_ip; + + /* Filter out wild packets */ + if (from->sll_pkttype != PACKET_HOST && + from->sll_pkttype != PACKET_BROADCAST && + from->sll_pkttype != PACKET_MULTICAST) + return 0; + + /* Only these types are recognised */ + if (ah->ar_op != htons(ARPOP_REQUEST) && + ah->ar_op != htons(ARPOP_REPLY)) + return 0; + + /* ARPHRD check and this darned FDDI hack here :-( */ + if (ah->ar_hrd != htons(from->sll_hatype) && + (from->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) + return 0; + + /* Protocol must be IP. */ + if (ah->ar_pro != htons(ETH_P_IP)) + return 0; + if (ah->ar_pln != 4) + return 0; + if (ah->ar_hln != ((struct sockaddr_ll *)&m_me)->sll_halen) + return 0; + + if (len < (ssize_t) sizeof(*ah) + 2 * (4 + ah->ar_hln)) + return 0; + + memcpy(&src_ip, p + ah->ar_hln, 4); + memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); + /* + * DAD packet was: + * src_ip = 0 (or some src) + * src_hw = ME + * dst_ip = tested address + * dst_hw = + * + * We fail, if receive request/reply with: + * src_ip = tested_address + * src_hw != ME + * if src_ip in request was not zero, check + * also that it matches to dst_ip, otherwise + * dst_ip/dst_hw do not matter. + */ + if (src_ip.s_addr != m_destAddress.s_addr) + return 0; + + if (memcmp(p, ((struct sockaddr_ll *)&m_me)->sll_addr, + ((struct sockaddr_ll *)&m_me)->sll_halen) == 0) + return 0; + + saveMacAddress(p, ah->ar_hln); + setConflictFlag(true); + + return FINAL_PACKS; +} + +int KyIpv4Arping::ipv4EventLoop() +{ + int rc = -1; + int ret; + int index; + int exit_loop = 0; + ssize_t bytes; + + int tfd; + struct pollfd pfds[POLLFD_COUNT]; + + struct itimerspec timerfd_vals; + timerfd_vals.it_interval.tv_sec = m_timeout, + timerfd_vals.it_interval.tv_nsec = 0, + timerfd_vals.it_value.tv_sec = m_timeout, + timerfd_vals.it_value.tv_nsec = 0; + + uint64_t exp; + uint64_t total_expires = 1; + + unsigned char packet[4096]; + struct sockaddr_storage from = { 0 }; + socklen_t addr_len = sizeof(from); + + /* timerfd */ + tfd = timerfd_create(CLOCK_MONOTONIC, 0); + if (tfd == -1) { + qWarning()<<"[KyIpv4Arping]" << "timerfd_create failed, errno" << errno; + return -1; + } + + if (timerfd_settime(tfd, 0, &timerfd_vals, NULL)) { + close(tfd); + qWarning()<<"[KyIpv4Arping]" << "timerfd_settime failed, errno" << errno; + return -1; + } + + pfds[POLLFD_TIMER].fd = tfd; + pfds[POLLFD_TIMER].events = POLLIN | POLLERR | POLLHUP; + + /* socket */ + pfds[POLLFD_SOCKET].fd = m_ipv4Socket; + pfds[POLLFD_SOCKET].events = POLLIN | POLLERR | POLLHUP; + sendIpv4Packet(); + + while (!exit_loop) { + ret = poll(pfds, POLLFD_COUNT, -1); + if (ret <= 0) { + if (errno == EAGAIN) { + continue; + } + + if (errno) { + qWarning()<<"[KyIpv4Arping]" <<"poll failed, errno" << errno; + } + + exit_loop = 1; + continue; + } + + for (index = 0; index < POLLFD_COUNT; index++) { + if (pfds[index].revents == 0) { + continue; + } + + switch (index) { + case POLLFD_TIMER: + bytes = read(tfd, &exp, sizeof(uint64_t)); + if (bytes != sizeof(uint64_t)) { + qWarning() <<"[KyIpv4Arping]" << "could not read timerfd"; + continue; + } + + total_expires += exp; + if (0 < m_retryCount && (uint64_t)m_retryCount < total_expires) { + exit_loop = 1; + rc = 0; + continue; + } + + sendIpv4Packet(); + break; + case POLLFD_SOCKET: + bytes = recvfrom(m_ipv4Socket, packet, sizeof(packet), 0, + (struct sockaddr *)&from, &addr_len); + if (bytes < 0) { + qWarning()<<"[KyIpv4Arping]" << "recvfrom function failed, errno" << errno; + continue; + } + if (ipv4PacketProcess(packet, bytes, (struct sockaddr_ll *)&from) == FINAL_PACKS) { + exit_loop = 1; + rc = 0; + } + break; + default: + qWarning()<<"[KyIpv4Arping]" <<"the fd index is undefine" << index; + break; + } + } + } + + close(tfd); + freeifaddrs(m_ifa0); + + return rc; +} + +int KyIpv4Arping::checkIfflags(unsigned int ifflags) +{ + if (!(ifflags & IFF_UP)) { + qWarning()<<"[KyIpv4Arping]" <<"the iface" << m_ifaceName <<" is down."; + return -1; + } + + if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) { + qWarning()<<"[KyIpv4Arping]" << "Interface" << m_ifaceName << "is not ARPable."; + return -1; + } + + return 0; +} + + +int KyIpv4Arping::checkDevice() +{ + int rc; + struct ifaddrs *ifa; + int n = 0; + + rc = getifaddrs(&m_ifa0); + if (rc < 0) { + qWarning()<<"[KyIpv4Arping]" <<"get iface address failed, erron"<< errno; + return -errno; + } + + for (ifa = m_ifa0; ifa; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) { + continue; + } + + if (ifa->ifa_addr->sa_family != AF_PACKET) { + continue; + } + + if (!m_ifaceName.isEmpty() + && (NULL != ifa->ifa_name) + && strcmp(ifa->ifa_name, m_ifaceName.toUtf8())) { + continue; + } + + if (checkIfflags(ifa->ifa_flags) < 0) { + continue; + } + + if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen) { + continue; + } + + if (!ifa->ifa_broadaddr) { + continue; + } + + m_ifa = ifa; + + if (n++) + break; + } + + if (n == 1 && m_ifa) { + m_ifindex = if_nametoindex(m_ifa->ifa_name); + if (!m_ifindex) { + qWarning()<<"[KyIpv4Arping]" <<"if_nametoindex is invalid"; + freeifaddrs(m_ifa0); + return -1; + } + m_ifaceName = m_ifa->ifa_name; + + return 0; + } + + freeifaddrs(m_ifa0); + return -1; +} + +void KyIpv4Arping::findBroadcastAddress() +{ + struct sockaddr_ll *he = (struct sockaddr_ll *)&(m_he); + + if (m_ifa) { + struct sockaddr_ll *sll = + (struct sockaddr_ll *)m_ifa->ifa_broadaddr; + + if (sll->sll_halen == he->sll_halen) { + memcpy(he->sll_addr, sll->sll_addr, he->sll_halen); + return; + } + } + + qWarning()<<"[KyIpv4Arping]" <<"using default broadcast address."; + + memset(he->sll_addr, -1, he->sll_halen); + + return; +} + +int KyIpv4Arping::ipv4ConflictCheck() +{ + limit_capabilities(); + + int ret = checkDevice(); + if (ret < 0) { + qWarning()<<"[KyIpv4Arping]"<<"the device is invalid" << m_ifaceName; + return -1; + } + + enable_capability_raw(); + m_ipv4Socket = socket(PF_PACKET, SOCK_DGRAM, 0); + disable_capability_raw(); + if (m_ipv4Socket < 0) { + qWarning()<<"[KyIpv4Arping]" << "create ipv4 socket failed, errno" << errno; + return -1; + } + + inet_aton(m_ipv4Address.toUtf8(), &m_destAddress); + m_destAddressFamily = AF_INET; + + ((struct sockaddr_ll *)&m_me)->sll_family = AF_PACKET; + ((struct sockaddr_ll *)&m_me)->sll_ifindex = m_ifindex; + ((struct sockaddr_ll *)&m_me)->sll_protocol = htons(ETH_P_ARP); + + ret = bind(m_ipv4Socket, (struct sockaddr *)&m_me, sizeof(m_me)); + if (ret < 0) { + qWarning()<<"[KyIpv4Arping]" <<"ipv4 socket bind failed, errno"<< errno; + close(m_ipv4Socket); + return -1; + } + + socklen_t alen = sizeof(m_me); + ret = getsockname(m_ipv4Socket, (struct sockaddr *)&m_me, &alen); + if (ret < 0) { + qWarning()<<"[KyIpv4Arping]" <<"ipv4 get socket name failed, errno" << errno; + close(m_ipv4Socket); + return -1; + } + + if (((struct sockaddr_ll *)&m_me)->sll_halen == 0) { + qWarning()<<"[KyIpv4Arping]" <<"the iface"<< m_ifaceName <<" is not suitable for arp"; + close(m_ipv4Socket); + return -1; + } + + m_he = m_me; + + findBroadcastAddress(); + + drop_capabilities(); + + ret = ipv4EventLoop(); + close(m_ipv4Socket); + + return ret; +} diff --git a/src/backend/kylinipv4arping.h b/src/backend/kylinipv4arping.h new file mode 100644 index 00000000..9aa9cb91 --- /dev/null +++ b/src/backend/kylinipv4arping.h @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLIN_IPV4_ARPING +#define KYLIN_IPV4_ARPING + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kylinarping.h" + +#include +#include +#include + +enum { + POLLFD_TIMER = 0, + POLLFD_SOCKET, + POLLFD_COUNT +}; + +class KyIpv4Arping : public QObject +{ + Q_OBJECT +public: + explicit KyIpv4Arping(QString ifaceName, QString ipAddress, int retryCount=3, int timeout=1, QObject *parent = nullptr); + ~KyIpv4Arping(); + +public: + bool ipv4IsConflict() { + return m_ipConflict; + } + + QString getMacAddress() { + return m_conflictMac; + } + + int ipv4ConflictCheck(); + +private: + void monoGetTime(struct timespec *ts); + void saveMacAddress(const uint8_t *ptr, size_t len); + void findBroadcastAddress(); + int checkDevice(); + int checkIfflags(unsigned int ifflags); + + int sendIpv4Packet(); + int ipv4EventLoop(); + int ipv4PacketProcess(unsigned char *buf, ssize_t len, struct sockaddr_ll *from); + + void setConflictFlag(bool isConflict); + +private: + struct in_addr m_srcAddress; + struct in_addr m_destAddress; + int m_destAddressFamily; + + struct sockaddr_storage m_me; + struct sockaddr_storage m_he; + int m_ipv4Socket = 0; + + QString m_ifaceName; + int m_ifindex; + struct ifaddrs *m_ifa; + struct ifaddrs *m_ifa0; + + QString m_ipv4Address; + int m_retryCount; + int m_timeout; + + bool m_ipConflict = false; + QString m_conflictMac = nullptr; +}; + +#endif diff --git a/src/backend/kylinipv6arping.cpp b/src/backend/kylinipv6arping.cpp new file mode 100644 index 00000000..bb4d78e3 --- /dev/null +++ b/src/backend/kylinipv6arping.cpp @@ -0,0 +1,424 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kylinipv6arping.h" + +#include +#include +#include +#include "kylinarping.h" + +KyIpv6Arping::KyIpv6Arping(QString ifaceName, QString ipAddress, int retryCount, int timeout, QObject *parent) : QObject(parent) +{ + m_ifaceName = ifaceName; + m_ipv6Address = ipAddress; + m_retryCount = retryCount; + m_timeoutMs = timeout; + + m_ipv6Conflict = false; +} + +KyIpv6Arping::~KyIpv6Arping() +{ + +} + +void KyIpv6Arping::monoGetTime (struct timespec *ts) +{ +#ifdef CLOCK_MONOTONIC + if (clock_gettime (CLOCK_MONOTONIC, ts)) +#endif + { + static long freq = 0; + if (freq == 0) + freq = sysconf (_SC_CLK_TCK); + + struct tms dummy; + clock_t t = times (&dummy); + ts->tv_sec = t / freq; + ts->tv_nsec = (t % freq) * (1000000000 / freq); + } +} + +int KyIpv6Arping::getLocalMacAddress(const char *ifname, unsigned char *addr) +{ +# ifdef SIOCGIFHWADDR + struct ifreq req; + memset (&req, 0, sizeof (req)); + + if (((unsigned)strlen (ifname)) >= (unsigned)IFNAMSIZ) { + return -1; /* buffer overflow = local root */ + } + + strcpy (req.ifr_name, ifname); + + int fd = socket (AF_INET6, SOCK_DGRAM, 0); + if (fd == -1) { + return -1; + } + + if (ioctl (fd, SIOCGIFHWADDR, &req)) { + qWarning()<<"[KyIpv6Arping]"<<"get local mac address failed, errno" << errno; + close (fd); + return -1; + } + close (fd); + + memcpy (addr, req.ifr_hwaddr.sa_data, 6); + return 0; +# else + /* No SIOCGIFHWADDR, which seems Linux specific. */ + struct ifaddrs *ifa = NULL; + struct ifaddrs *ifp = NULL; + getifaddrs(&ifa); + ifp = ifa; /* preserve the address of ifa to free memory later */ + while (ifp != NULL) { + if (ifp->ifa_addr->sa_family == AF_LINK && strcmp(ifp->ifa_name, ifname) == 0) { + const struct sockaddr_dl* sdl = (const struct sockaddr_dl*) ifp->ifa_addr; + memcpy(addr, sdl->sdl_data + sdl->sdl_nlen, 6); + freeifaddrs(ifa); + return 0; + } + ifp = ifp->ifa_next; + } + freeifaddrs(ifa); + return -1; +# endif +} + +int KyIpv6Arping::getIpv6ByName(struct sockaddr_in6 *addr) +{ + struct addrinfo hints, *res; + memset (&hints, 0, sizeof (hints)); + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_DGRAM; /* dummy */ + hints.ai_flags = 0; + + int val = getaddrinfo (m_ipv6Address.toUtf8(), NULL, &hints, &res); + if (val) { + qWarning()<<"[KyIpv6Arping]" << m_ipv6Address <<"get addrinfo failed, errno" << val; + return -1; + } + + memcpy (addr, res->ai_addr, sizeof (struct sockaddr_in6)); + freeaddrinfo (res); + + val = if_nametoindex (m_ifaceName.toUtf8()); + if (val == 0) { + qWarning()<<"[KyIpv6Arping]" <<"if_nametoindex failed, errno" << errno; + return -1; + } + addr->sin6_scope_id = val; + + return 0; +} + +int KyIpv6Arping::buildSolicitationPacket(solicit_packet *ns, struct sockaddr_in6 *tgt, const char *ifname) +{ + /* builds ICMPv6 Neighbor Solicitation packet */ + ns->hdr.nd_ns_type = ND_NEIGHBOR_SOLICIT; + ns->hdr.nd_ns_code = 0; + ns->hdr.nd_ns_cksum = 0; /* computed by the kernel */ + ns->hdr.nd_ns_reserved = 0; + memcpy (&ns->hdr.nd_ns_target, &tgt->sin6_addr, 16); + + /* determines actual multicast destination address */ + memcpy (&tgt->sin6_addr.s6_addr, "\xff\x02\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x01\xff", 13); + + /* gets our own interface's link-layer address (MAC) */ + if (getLocalMacAddress (m_ifaceName.toUtf8().constData(), ns->hw_addr)) { + return sizeof (ns->hdr); + } + + ns->opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; + ns->opt.nd_opt_len = 1; /* 8 bytes */ + return sizeof (*ns); +} + +void KyIpv6Arping::saveMacAddress (const uint8_t *ptr, size_t len) +{ + int index; + char macAddress[64] = {0}; + + for (index = 0; index < len; index++) { + snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%02X", ptr[index]); + if (index != len - 1) { + snprintf(&macAddress[strlen(macAddress)], sizeof(macAddress) - strlen(macAddress), "%s", ":"); + } + } + + m_conflictMacAddress = QString(macAddress); + return ; +} + +int KyIpv6Arping::parseIpv6Packet(const uint8_t *buf, size_t len, const struct sockaddr_in6 *tgt) +{ + const struct nd_neighbor_advert *na = + (const struct nd_neighbor_advert *)buf; + const uint8_t *ptr; + + /* checks if the packet is a Neighbor Advertisement, and + * if the target IPv6 address is the right one */ + if ((len < sizeof (struct nd_neighbor_advert)) + || (na->nd_na_type != ND_NEIGHBOR_ADVERT) + || (na->nd_na_code != 0) + || memcmp (&na->nd_na_target, &tgt->sin6_addr, 16)) { + return -1; + } + len -= sizeof (struct nd_neighbor_advert); + + /* looks for Target Link-layer address option */ + ptr = buf + sizeof (struct nd_neighbor_advert); + + while (len >= 8) + { + uint16_t optlen; + + optlen = ((uint16_t)(ptr[1])) << 3; + if (optlen == 0) + break; /* invalid length */ + + if (len < optlen) /* length > remaining bytes */ + break; + len -= optlen; + + + /* skips unrecognized option */ + if (ptr[0] != ND_OPT_TARGET_LINKADDR) + { + ptr += optlen; + continue; + } + + /* Found! displays link-layer address */ + ptr += 2; + optlen -= 2; + + saveMacAddress (ptr, optlen); + setIpv6ConflictFlag(true); + return 0; + } + + return -1; +} + +int KyIpv6Arping::readIpv6Packet(void *buf, + size_t len, + int flags, + struct sockaddr_in6 *addr) +{ + char cbuf[CMSG_SPACE (sizeof (int))]; + + struct iovec iov = { + .iov_base = buf, + .iov_len = len + }; + + struct msghdr hdr = { + .msg_name = addr, + .msg_namelen = sizeof (*addr), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cbuf, + .msg_controllen = sizeof (cbuf) + }; + + ssize_t val = recvmsg (m_ipv6Socket, &hdr, flags); + if (val == -1) { + return val; + } + + /* ensures the hop limit is 255 */ + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR (&hdr); + cmsg != NULL; cmsg = CMSG_NXTHDR (&hdr, cmsg)) { + if ((cmsg->cmsg_level == IPPROTO_IPV6) + && (cmsg->cmsg_type == IPV6_HOPLIMIT)) { + if (255 != *(int *)CMSG_DATA (cmsg)) { + // pretend to be a spurious wake-up + errno = EAGAIN; + return -1; + } + } + } + + return val; +} + +int KyIpv6Arping::reciveAndProcessIpv6Packet(const struct sockaddr_in6 *tgt, unsigned wait_ms) +{ + struct timespec end; + struct pollfd fds; + + /* computes deadline time */ + monoGetTime (&end); + div_t d; + d = div (wait_ms, 1000); + end.tv_sec = end.tv_sec + d.quot; + end.tv_nsec = end.tv_nsec + (d.rem * 1000000); + + /* receive loop */ + for (;;) + { + /* waits for reply until deadline */ + struct timespec now; + int val = 0; + + monoGetTime (&now); + if (end.tv_sec >= now.tv_sec) { + val = (end.tv_sec - now.tv_sec) * 1000 + + (int)((end.tv_nsec - now.tv_nsec) / 1000000); + if (val < 0) { + val = 0; + } + } + + fds.fd = m_ipv6Socket; + fds.events = POLLIN; + val = poll (&fds, 1, val); + if (val < 0) + break; + + if (val == 0) + return 0; + + /* receives an ICMPv6 packet */ + // TODO: use interface MTU as buffer size + uint8_t buf[1460]; + struct sockaddr_in6 addr; + + val = readIpv6Packet(buf, sizeof (buf), MSG_DONTWAIT, &addr); + if (val < 0) { + if (errno != EAGAIN) + qWarning()<<"[KyIpv6Arping]"<<"Receiving ICMPv6 packet failed"; + continue; + } + + /* ensures the response came through the right interface */ + if (addr.sin6_scope_id + && (addr.sin6_scope_id != tgt->sin6_scope_id)) + continue; + + if (parseIpv6Packet(buf, val, tgt) == 0) { + return 1 /* = responses */; + } + } + + return -1; /* error */ +} + + +int KyIpv6Arping::ipv6ConflictCheck() +{ + struct sockaddr_in6 tgt; + struct icmp6_filter filter; + int retry = 0; + + limit_capabilities(); + + enable_capability_raw(); + m_ipv6Socket = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + disable_capability_raw(); + if (m_ipv6Socket < 0) { + qDebug()<<"[KyIpv6Arping]" <<"create ipv6 socket failed:"; + return -1; + } + + fcntl (m_ipv6Socket, F_SETFD, FD_CLOEXEC); + + /* set ICMPv6 filter */ + ICMP6_FILTER_SETBLOCKALL (&filter); + ICMP6_FILTER_SETPASS (ND_NEIGHBOR_ADVERT, &filter); + + enable_capability_raw(); + setsockopt (m_ipv6Socket, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter)); + + int soDontRoute = 1; + setsockopt (m_ipv6Socket, SOL_SOCKET, SO_DONTROUTE, &soDontRoute, sizeof(soDontRoute)); + + /* sets Hop-by-hop limit to 255 */ + int multicastHopLimit = 255; + setsockopt (m_ipv6Socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &multicastHopLimit, sizeof (multicastHopLimit)); + + int unicastHops = 255; + setsockopt (m_ipv6Socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + &unicastHops, sizeof (unicastHops)); + + int recvHopLimit = 1; + setsockopt(m_ipv6Socket, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + &recvHopLimit, sizeof (recvHopLimit)); + + disable_capability_raw(); + + drop_capabilities(); + + /* resolves target's IPv6 address */ + int ret = getIpv6ByName(&tgt); + if (ret < 0) { + qWarning()<<"[KyIpv6Arping]"<<"get ipv6 by name failed."; + close (m_ipv6Socket); + return ret; + } + + solicit_packet packet; + struct sockaddr_in6 dst; + ssize_t plen; + + memcpy (&dst, &tgt, sizeof (dst)); + plen = buildSolicitationPacket(&packet, &dst, m_ifaceName.toUtf8().constData()); + if (plen == -1) { + qWarning()<<"[KyIpv6Arping]"<<"build solicit packet failed."; + close (m_ipv6Socket); + return -1; + } + + while (retry < m_retryCount) { + /* sends a Solitication */ + if (sendto (m_ipv6Socket, &packet, plen, MSG_DONTROUTE, + (const struct sockaddr *)&dst, + sizeof (dst)) != plen) { + qWarning()<<"[KyIpv6Arping]"<<"Sending ICMPv6 packet failed."; + close (m_ipv6Socket); + return -1; + } + + retry++; + + /* receives an Advertisement */ + ssize_t val = reciveAndProcessIpv6Packet(&tgt, m_timeoutMs); + if (val > 0) { + close (m_ipv6Socket); + return 0; + } else if (val == 0) { + continue; + } else { + close (m_ipv6Socket); + return -1; + } + } + + close(m_ipv6Socket); + + if (retry == m_retryCount) { + return 0; + } else { + return -2; + } +} diff --git a/src/backend/kylinipv6arping.h b/src/backend/kylinipv6arping.h new file mode 100644 index 00000000..faa08c25 --- /dev/null +++ b/src/backend/kylinipv6arping.h @@ -0,0 +1,128 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLINIPV6ARPING_H +#define KYLINIPV6ARPING_H + +//#include + +#include +#include +#include /* div() */ +#include /* uint8_t */ +#include /* UINT_MAX */ +#include +#include + +#include /* EMFILE */ +#include +#include /* close() */ +#include /* clock_gettime() */ +#include /* poll() */ +#include +#include +#include + +//#include "gettime.h" + +#ifdef HAVE_GETOPT_H +# include +#endif + +#include /* getaddrinfo() */ +#include /* inet_ntop() */ +#include /* if_nametoindex() */ + +#include +#include + +#ifndef IPV6_RECVHOPLIMIT +/* Using obsolete RFC 2292 instead of RFC 3542 */ +# define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT +#endif + +/* BSD-like systems define ND_RA_FLAG_HA instead of ND_RA_FLAG_HOME_AGENT */ +#ifndef ND_RA_FLAG_HOME_AGENT +# ifdef ND_RA_FLAG_HA +# define ND_RA_FLAG_HOME_AGENT ND_RA_FLAG_HA +# endif +#endif + +#ifndef AI_IDN +# define AI_IDN 0 +#endif + + +#include +#include +#include + +typedef struct +{ + struct nd_neighbor_solicit hdr; + struct nd_opt_hdr opt; + uint8_t hw_addr[6]; +} solicit_packet; + +class KyIpv6Arping: public QObject +{ + Q_OBJECT +public: + explicit KyIpv6Arping(QString ifaceName, QString ipAddress, int retryCount=3, int timeout=1000, QObject *parent = nullptr); + ~KyIpv6Arping(); + +public: + bool ipv6IsConflict() { + return m_ipv6Conflict; + } + + void setIpv6ConflictFlag(bool conflict) { + m_ipv6Conflict = conflict; + } + + QString getConflictMacAddress() { + return m_conflictMacAddress; + } + + int ipv6ConflictCheck(); + +private: + void monoGetTime (struct timespec *ts); + void saveMacAddress (const uint8_t *ptr, size_t len); + int getLocalMacAddress(const char *ifname, unsigned char *addr); + + int getIpv6ByName(struct sockaddr_in6 *addr); + int buildSolicitationPacket(solicit_packet *ns, struct sockaddr_in6 *tgt, const char *ifname); + int parseIpv6Packet(const uint8_t *buf, size_t len, const struct sockaddr_in6 *tgt); + int readIpv6Packet(void *buf, size_t len, int flags, struct sockaddr_in6 *addr); + int reciveAndProcessIpv6Packet(const struct sockaddr_in6 *tgt, unsigned wait_ms); + +private: + int m_ipv6Socket = 0; + + QString m_ifaceName; + QString m_ipv6Address; + int m_retryCount; + int m_timeoutMs; + + bool m_ipv6Conflict = false; + QString m_conflictMacAddress = nullptr; +}; + +#endif // KYLINIPV6ARPING_H diff --git a/src/backend/sysdbusregister.cpp b/src/backend/sysdbusregister.cpp new file mode 100644 index 00000000..fa1d5a38 --- /dev/null +++ b/src/backend/sysdbusregister.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include + +SysdbusRegister::SysdbusRegister() +{ +} + +SysdbusRegister::~SysdbusRegister() +{ +} + +void SysdbusRegister::systemRun(QString cmd){ + QProcess::execute(cmd); +} + +QStringList SysdbusRegister::getWifiInfo(QString wifiName) { + //返回名为wifiName的企业wifi的配置信息,包括eap,inner和用户列表 + QStringList wlist; + QString filename = "/usr/share/kylin-nm/wpaconn.conf"; + QFile file(filename); + if(!file.exists()) { + return wlist; + } + QSharedPointer autoSettings = QSharedPointer(new QSettings(filename, QSettings::IniFormat)); + wlist << autoSettings.get()->value("eap").toString(); + wlist << autoSettings.get()->value("inner").toString(); + int size = autoSettings.get()->beginReadArray(wifiName); + for (int i = 0; i < size; ++i) { + autoSettings.get()->setArrayIndex(i); + wlist << autoSettings.get()->value("user").toString(); + } + autoSettings.get()->endArray(); + return wlist; +} + +bool SysdbusRegister::appendWifiInfo(QString name, QString eap, QString inner, QString user) { + //向配置文件添加名为name的wifi配置,包括eap,inner和它的第一个用户 + QString filename = "/usr/share/kylin-nm/wpaconn.conf"; + QSharedPointer autoSettings = QSharedPointer(new QSettings(filename, QSettings::IniFormat)); + autoSettings.get()->beginGroup(name); + autoSettings.get()->setValue("eap", eap); + autoSettings.get()->setValue("inner", inner); + //以数组形式写入用户名 + autoSettings.get()->beginWriteArray(name); + autoSettings.get()->setArrayIndex(0); + autoSettings.get()->setValue("user", user); + autoSettings.get()->endArray(); + return true; +} + +bool SysdbusRegister::appendWifiUser(QString name, QString user) { + //向名为name的wifi用户列表添加名为user的用户名 + QString filename = "/usr/share/kylin-nm/wpaconn.conf"; + QSharedPointer autoSettings = QSharedPointer(new QSettings(filename, QSettings::IniFormat)); + autoSettings.get()->beginWriteArray(name); + autoSettings.get()->setArrayIndex(0); + //读到用户名列表长度并在队尾添加一个用户名 + int size = autoSettings.get()->beginReadArray(name); + autoSettings.get()->setArrayIndex(size); + autoSettings.get()->setValue("user", user); + autoSettings.get()->endArray(); + return true; +} diff --git a/src/backend/sysdbusregister.h b/src/backend/sysdbusregister.h new file mode 100644 index 00000000..cbbe2b61 --- /dev/null +++ b/src/backend/sysdbusregister.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include +#include +#include + +#include + +class SysdbusRegister : public QObject +{ + Q_OBJECT + + Q_CLASSINFO("D-Bus Interface", "com.kylin.NetworkManager.interface") + +public: + explicit SysdbusRegister(); + ~SysdbusRegister(); + +private: +// QString m_name; + +Q_SIGNALS: +// Q_SCRIPTABLE void nameChanged(QString); +// Q_SCRIPTABLE void computerinfo(QString); + +public Q_SLOTS: + + Q_SCRIPTABLE void systemRun(QString cmd); + Q_SCRIPTABLE QStringList getWifiInfo(QString wifiName); + Q_SCRIPTABLE bool appendWifiInfo(QString name, QString eap, QString inner, QString user); + Q_SCRIPTABLE bool appendWifiUser(QString name, QString user); + +}; + +#endif // SYSDBUSREGISTER_H diff --git a/src/backend/utils.cpp b/src/backend/utils.cpp new file mode 100644 index 00000000..8c2959b0 --- /dev/null +++ b/src/backend/utils.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include +#include +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +// The Utils class + +Utils::Utils(){} + +int Utils::m_system(char *cmd) +{ + int status = 0; + pid_t pid; + clock_t start,finish; + if ((pid = vfork()) <0) { + qDebug()<<"failed to create a subprocess by using vfork"; + status = -1; + } else if (pid==0) { + const char *new_argv[4]; + struct sigaction sa_cld; + sa_cld.sa_handler = SIG_DFL; + sa_cld.sa_flags = 0; + + // 在子进程中放开SIGINT信号 + sigemptyset(&sa_cld.sa_mask); + sigaction (SIGINT, &sa_cld, NULL); + sigaction (SIGQUIT, &sa_cld, NULL); + + new_argv[0] = "sh"; + new_argv[1] = "-c"; + new_argv[2] = cmd; + new_argv[3] = NULL; + + // execl("/bin/sh","sh","-c" ,cmd,(char *)0); + start = clock(); + if (execve("/bin/sh",(char *const *) new_argv, NULL) <0) { + qDebug()<<"failed to execve a shell command in function m_system"; + exit(1); + } else { + exit(0); + } + } else { + waitpid(pid,&status,0); + finish = clock(); + } + //double duration = (double)(finish-start)/CLOCKS_PER_SEC; + //qDebug()<<"It takes "< args; + args<<(tr("Kylin NM")) + <<((unsigned int) 0) + < +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* qt会将glib里的signals成员识别为宏,所以取消该宏 + * 后面如果用到signals时,使用Q_SIGNALS代替即可 + * +#ifdef signals +#undef signals +#endif + +extern "C" { +#include +#include +} + */ + + +/////////////////////////////////////////////////////////////////////////////// +// wifi property struct + typedef struct structWifiProperty{ + QString objectPath; + QString bssid; + int priority; +}structWifiProperty; + + +/////////////////////////////////////////////////////////////////////////////// +// The Utils class, used to do some assist function + +class Utils : public QObject +{ + Q_OBJECT +public: + Utils(); + + static int m_system(char *cmd); + +public Q_SLOTS: + void onRequestSendDesktopNotify(QString message); + +}; + + +/////////////////////////////////////////////////////////////////////////////// +// The UseQssFile class, set control style by using .qss file + +class UseQssFile +{ +public: + static void setStyle(const QString &style) + { + QString styleName = ":/qss/" + style; + + QFile qss(styleName); + qss.open(QFile::ReadOnly); + qApp->setStyleSheet(qss.readAll()); + qss.close(); + } +}; + + +/////////////////////////////////////////////////////////////////////////////// +// The NetworkSpeed class, get the network upload and download speed + +class NetworkSpeed : public QObject +{ + Q_OBJECT +public: + explicit NetworkSpeed(QObject *parent = nullptr); + + int getCurrentDownloadRates(char *netname,long int * save_rate,long int * tx_rate); //获取当前的流量,参数为将获取到的流量保 +}; + +#endif // UTILS_H diff --git a/src/backend/wifi-auth-thread.cpp b/src/backend/wifi-auth-thread.cpp new file mode 100644 index 00000000..a53b8e83 --- /dev/null +++ b/src/backend/wifi-auth-thread.cpp @@ -0,0 +1,72 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wifi-auth-thread.h" + +#include + +WifiAuthThread::WifiAuthThread() +{ + //检查连接状态 + naManager = new QNetworkAccessManager(this); +// QString url=QString("http://nmcheck.gnome.org/check_network_status.txt"); + QString url=QString("http://connectivity-check.ubuntu.com/"); + request.setUrl(QUrl(url)); + naManager->get(request); + //qDebug()<<"-------------------Network state check!----------------------"; + connect(naManager,&QNetworkAccessManager::finished,this,[=](QNetworkReply* reply){ + _isReply=true; + QNetworkReply::NetworkError err = reply->error(); + //qDebug()<<"----------------NetworkReply error:----------------------"<readAll().isEmpty()) + _isConnect=false; + } + else + _isConnect=false; + }); +} + +WifiAuthThread::~WifiAuthThread() +{ + delete naManager; +} + +void WifiAuthThread::run() +{ + sleep(3); + QDBusInterface interface( "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager", + "org.freedesktop.NetworkManager", + QDBusConnection::systemBus() ); + QDBusReply reply= interface.call("CheckConnectivity"); + if (reply.isValid()) { + //qDebug()<<"---------------------wifi type:----------------------"< +#include +#include +#include +#include +#include +#include + +class WifiAuthThread:public QThread +{ +protected: + virtual void run(); + QNetworkRequest request; + QNetworkAccessManager* naManager=nullptr; + bool _isConnect=true;//是否已联网 + bool _isReply=false;//联网状态检查是否收到回复 + +public: + WifiAuthThread(); + ~WifiAuthThread(); +}; + +#endif //WIFI_AUTH_THREAD_H diff --git a/src/frontend/customstyle.cpp b/src/frontend/customstyle.cpp new file mode 100644 index 00000000..829550f9 --- /dev/null +++ b/src/frontend/customstyle.cpp @@ -0,0 +1,171 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "customstyle.h" + +CustomStyle::CustomStyle(const QString &proxyStyleName) : QProxyStyle (proxyStyleName) +{ + +} + +QSize CustomStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const +{ + switch (type) { + case CT_TabBarTab: { + QSize size(0,40); + if (const QStyleOptionTab *tab= qstyleoption_cast(option)) { + switch (tab->shape) { + case QTabBar::RoundedNorth: + case QTabBar::RoundedSouth: { + return size + QSize(50,0); + break; + } + case QTabBar::RoundedWest: + case QTabBar::RoundedEast: { + return size + QSize(0,50); + break; + } + default: { + break; + } + } + } + return size; + break; + } + default: { + break; + } + } + return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); +} +void CustomStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ +// switch (element) { +// case CE_TabBarTab: { +// if (QStyle::State_Selected != option->state) { +// painter->save(); +// painter->setBrush(QColor(0,0,0,0)); +// painter->drawRect(widget->rect()); +//// painter->setOpacity(0.1); +// painter->restore(); +// } +// break; +// } +// default: { +// break; +// } +// } + return QProxyStyle::drawControl(element, option, painter, widget); +} + +//void CustomStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +//{ +// return QProxyStyle::drawComplexControl(control, option, painter, widget); +//} + +//void CustomStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const +//{ +// return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); +//} + +//void CustomStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +//{ +// return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); +//} + +//void CustomStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +//{ +// return QProxyStyle::drawPrimitive(element, option, painter, widget); +//} + +//QPixmap CustomStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const +//{ +// return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); +//} + +//QStyle::SubControl CustomStyle::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const +//{ +// return QProxyStyle::hitTestComplexControl(control, option, position, widget); +//} + +//QRect CustomStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const +//{ +// return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); +//} + +//QRect CustomStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const +//{ +// return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); +//} + +//int CustomStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +//{ +// return QProxyStyle::pixelMetric(metric, option, widget); +//} + +//void CustomStyle::polish(QWidget *widget) +//{ +// return QProxyStyle::polish(widget); +//} + +//void CustomStyle::polish(QApplication *application) +//{ +// return QProxyStyle::polish(application); +//} + +//void CustomStyle::polish(QPalette &palette) +//{ +// return QProxyStyle::polish(palette); +//} + +//void CustomStyle::unpolish(QWidget *widget) +//{ +// return QProxyStyle::unpolish(widget); +//} + +//void CustomStyle::unpolish(QApplication *application) +//{ +// return QProxyStyle::unpolish(application); +//} + +//QIcon CustomStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const +//{ +// return QProxyStyle::standardIcon(standardIcon, option, widget); +//} + +//QPalette CustomStyle::standardPalette() const +//{ +// return QProxyStyle::standardPalette(); +//} + +//int CustomStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +//{ +// return QProxyStyle::styleHint(hint, option, widget, returnData); +//} + +//QRect CustomStyle::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const +//{ +// return QProxyStyle::subControlRect(control, option, subControl, widget); +//} + +//QRect CustomStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const +//{ +// return QProxyStyle::subElementRect(element, option, widget); +//} diff --git a/src/frontend/customstyle.h b/src/frontend/customstyle.h new file mode 100644 index 00000000..db7f0c1b --- /dev/null +++ b/src/frontend/customstyle.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CUSTOMSTYLE_H +#define CUSTOMSTYLE_H + +#include +#include +#include +#include +#include +#include +#include + +class CustomStyle : public QProxyStyle +{ + Q_OBJECT +public: + explicit CustomStyle(const QString &proxyStyleName = "windows"); + ~CustomStyle() = default; + virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; + virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; +// virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; + +// virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; +// virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; + +// virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; +// virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; +// virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; +// virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; +// virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; +// //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); +// virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; + +// virtual void polish(QWidget *widget); +// virtual void polish(QApplication *application); +// virtual void polish(QPalette &palette); +// virtual void unpolish(QWidget *widget); +// virtual void unpolish(QApplication *application); + +// virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; +// virtual QPalette standardPalette() const; + +// virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; +// virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; +// virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; +}; + +#endif // CUSTOMSTYLE_H diff --git a/src/frontend/enterprise-wlan/enterprise-wlan.pri b/src/frontend/enterprise-wlan/enterprise-wlan.pri new file mode 100644 index 00000000..c4571359 --- /dev/null +++ b/src/frontend/enterprise-wlan/enterprise-wlan.pri @@ -0,0 +1,9 @@ +INCLUDEPATH += $$PWD + +FORMS += \ + +HEADERS += \ + $$PWD/enterprisewlandialog.h \ + +SOURCES += \ + $$PWD/enterprisewlandialog.cpp \ diff --git a/src/frontend/enterprise-wlan/enterprisewlandialog.cpp b/src/frontend/enterprise-wlan/enterprisewlandialog.cpp new file mode 100644 index 00000000..bc050651 --- /dev/null +++ b/src/frontend/enterprise-wlan/enterprisewlandialog.cpp @@ -0,0 +1,291 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "enterprisewlandialog.h" +#include +#include +#include "xatom-helper.h" +#define MAIN_SIZE_EXPAND 480,580 +#define MAIN_SIZE_NARROW 480,484 +#define PEAP_SCRO_HEIGHT 390 +#define TLS_SCRO_HEIGHT 590 +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define CENTER_LAYOUT_MARGINS 24, 16, 24, 8 +#define BUTTON_LAYOUT_MARGINS 24, 24, 24, 24 +#define MAIN_LAYOUT_SPACING 0 +#define BUTTON_SPACING 16 +#define LABEL_MIN_WIDTH 146 +#define MEDIUM_WEIGHT_VALUE 57 + +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" + +EnterpriseWlanDialog::EnterpriseWlanDialog(KyWirelessNetItem &wirelessNetItem, QString device, QWidget *parent) : QWidget(parent) +{ +// //设置窗口无边框,阴影 +//#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +// MotifWmHints window_hints; +// window_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; +// window_hints.functions = MWM_FUNC_ALL; +// window_hints.decorations = MWM_DECOR_BORDER; +// XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), window_hints); +//#else +// this->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); +//#endif + this->setAttribute(Qt::WA_DeleteOnClose); + this->setWindowFlag(Qt::Window); +// this->setWindowTitle(tr("Connect Enterprise WLAN")); + this->setWindowIcon(QIcon::fromTheme("kylin-network")); + + m_wirelessNetItem = wirelessNetItem; + m_deviceName = device; + m_connectOperation = new KyWirelessConnectOperation(); + m_resource = new KyWirelessNetResource(); + + initUI(); + initData(); + centerToScreen(); +} + +EnterpriseWlanDialog::~EnterpriseWlanDialog() { + if (m_securityPage) { + delete m_securityPage; + m_securityPage = nullptr; + } + if (m_connectOperation) { + delete m_connectOperation; + m_connectOperation = nullptr; + } +} + +void EnterpriseWlanDialog::closeEvent(QCloseEvent *event) +{ + Q_EMIT this->enterpriseWlanDialogClose(false); + return QWidget::closeEvent(event); +} + +void EnterpriseWlanDialog::paintEvent(QPaintEvent *event) +{ +// QPalette pal = qApp->palette(); +// QPainter painter(this); +// painter.setBrush(pal.color(QPalette::Base)); +// painter.drawRect(this->rect()); +// painter.fillRect(rect(), QBrush(pal.color(QPalette::Base))); + + return QWidget::paintEvent(event); +} + +void EnterpriseWlanDialog::initUI() +{ + m_mainLayout = new QVBoxLayout(this); + this->setLayout(m_mainLayout); + m_mainLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); + m_mainLayout->setSpacing(MAIN_LAYOUT_SPACING); + + m_centerWidget = new QWidget(this); + QVBoxLayout *centerLayout = new QVBoxLayout(m_centerWidget); + centerLayout->setContentsMargins(CENTER_LAYOUT_MARGINS); + centerLayout->setSpacing(MAIN_LAYOUT_SPACING); + + m_descriptionLabel = new QLabel(this); + m_descriptionLabel->setText(tr("Wi-Fi network requires authentication")); //Wi-Fi网络要求认证 + QFont font = m_descriptionLabel->font(); + font.setWeight(MEDIUM_WEIGHT_VALUE); + m_descriptionLabel->setFont(font); + m_ssidLabel = new QLabel(this); + QString str = tr("Access to Wi-Fi network \""); //访问Wi-Fi网络 + str.append(m_wirelessNetItem.m_NetSsid); + str.append(tr("\" requires a password or encryption key.")); //需要密码或加密秘钥 + m_ssidLabel->setText(str); + m_ssidLabel->setWordWrap(true); + m_securityPage = new SecurityPage(false, this); + m_securityPage->setSecurity(KySecuType::WPA_AND_WPA2_ENTERPRISE); +// m_securityPage->setSecurityVisible(false); + + centerLayout->addWidget(m_descriptionLabel); + centerLayout->addSpacing(8); + centerLayout->addWidget(m_ssidLabel); + centerLayout->addSpacing(BUTTON_SPACING); + centerLayout->addWidget(m_securityPage); + centerLayout->addStretch(); + m_enterWlanScrollArea = new QScrollArea(this); + m_enterWlanScrollArea->setFrameShape(QFrame::NoFrame); + m_enterWlanScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_enterWlanScrollArea->setWidget(m_centerWidget); + QPalette pal = m_enterWlanScrollArea->palette(); + pal.setBrush(QPalette::Base, QColor(0,0,0,0)); + m_enterWlanScrollArea->setPalette(pal); + + m_bottomDivider = new Divider(this); + + QWidget *bottomWidget = new QWidget(this); + QHBoxLayout *btnLayout = new QHBoxLayout(bottomWidget); + btnLayout->setContentsMargins(BUTTON_LAYOUT_MARGINS); + btnLayout->setSpacing(BUTTON_SPACING); + m_cancelBtn = new QPushButton(this); + m_connectBtn = new QPushButton(this); + m_cancelBtn->setText(tr("Cancel")); + m_connectBtn->setText(tr("Connect")); + m_connectBtn->setEnabled(false); + btnLayout->addStretch(); + btnLayout->addWidget(m_cancelBtn); + btnLayout->addWidget(m_connectBtn); + + m_mainLayout->addWidget(m_enterWlanScrollArea); + m_mainLayout->addWidget(m_bottomDivider); + m_mainLayout->addWidget(bottomWidget); + + this->setFixedSize(MAIN_SIZE_EXPAND); + this->setWindowTitle(m_wirelessNetItem.m_NetSsid); + initConnections(); + onPaletteChanged(); +} + +void EnterpriseWlanDialog::centerToScreen() +{ + QDesktopWidget* m = QApplication::desktop(); + QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos())); + int desk_x = desk_rect.width(); + int desk_y = desk_rect.height(); + int x = this->width(); + int y = this->height(); + this->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top()); +} + +void EnterpriseWlanDialog::initConnections() +{ + connect(m_closeBtn, &QPushButton::clicked, this, &EnterpriseWlanDialog::close); + connect(m_cancelBtn, &QPushButton::clicked, this, &EnterpriseWlanDialog::close); + connect(m_connectBtn, &QPushButton::clicked, this, &EnterpriseWlanDialog::onBtnConnectClicked); + connect(m_securityPage, &SecurityPage::eapTypeChanged, this, &EnterpriseWlanDialog::onEapTypeChanged); + connect(m_securityPage, &SecurityPage::setSecuPageState, this, [ = ](bool status) { + m_connectBtn->setEnabled(status); + }); + + connect(qApp, &QApplication::paletteChanged, this, &EnterpriseWlanDialog::onPaletteChanged); + + const QByteArray id(THEME_SCHAME); + if(QGSettings::isSchemaInstalled(id)){ + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("themeColor" == key) { + onPaletteChanged(); + } + }); + } +} + +void EnterpriseWlanDialog::onPaletteChanged() +{ + QPalette pal = qApp->palette(); + + QGSettings * styleGsettings = nullptr; + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + styleGsettings = new QGSettings(style_id); + QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); + if(currentTheme == "ukui-default"){ + pal = lightPalette(this); + } + } + pal.setColor(QPalette::Background, pal.base().color()); + this->setPalette(pal); + + setFramePalette(m_securityPage, pal); + + if (styleGsettings != nullptr) { + delete styleGsettings; + styleGsettings = nullptr; + } +} + +void EnterpriseWlanDialog::initData() +{ + if (m_wirelessNetItem.m_isConfigured) { + KyEapMethodType type; + m_connectOperation->getEnterpiseEapMethod(m_wirelessNetItem.m_connectUuid, type); + if (type) { + onEapTypeChanged(type); + } else { + qWarning() << "Get eap type failed!" << Q_FUNC_INFO << __LINE__; + } + } +} + +void EnterpriseWlanDialog::onBtnConnectClicked() +{ + qDebug() << "Clicked connectBtn, will connect enterprise WLAN, ssid = " + << m_wirelessNetItem.m_NetSsid << "." << Q_FUNC_INFO << __LINE__; + KySecuType secuType; + KyEapMethodType eapType; + m_securityPage->getSecuType(secuType, eapType); + + KyWirelessConnectSetting connetSetting; + connetSetting.setConnectName(m_wirelessNetItem.m_NetSsid); + connetSetting.setIfaceName(m_deviceName); +// connetSetting.isAutoConnect = true; //ZJP_TODO 自动连接选项 + connetSetting.m_type = KyKeyMgmt::WpaEap; + connetSetting.m_ssid = m_wirelessNetItem.m_NetSsid; + connetSetting.m_secretFlag = 0; + connetSetting.dumpInfo(); + + if (eapType == KyEapMethodType::TLS) { + m_info.tlsInfo.devIfaceName = m_deviceName; + m_securityPage->updateTlsChange(m_info.tlsInfo); + m_connectOperation->addAndActiveWirelessEnterPriseTlsConnect(m_info.tlsInfo, connetSetting, m_deviceName, false); + } else if (eapType == KyEapMethodType::PEAP) { + m_securityPage->updatePeapChange(m_info.peapInfo); + m_connectOperation->addAndActiveWirelessEnterPrisePeapConnect(m_info.peapInfo, connetSetting, m_deviceName, false); + } else if (eapType == KyEapMethodType::TTLS) { + m_securityPage->updateTtlsChange(m_info.ttlsInfo); + m_connectOperation->addAndActiveWirelessEnterPriseTtlsConnect(m_info.ttlsInfo, connetSetting, m_deviceName, false); + } else { + qWarning() << "Connect enterprise wlan failed!(Unknown eap type)" << Q_FUNC_INFO << __LINE__; + } + close(); +} + +void EnterpriseWlanDialog::onEapTypeChanged(const KyEapMethodType &type) +{ + switch (type) { + case KyEapMethodType::TLS: + if (!m_wirelessNetItem.m_connectUuid.isEmpty()) { + m_resource->getEnterPriseInfoTls(m_wirelessNetItem.m_connectUuid, m_info.tlsInfo); + } + this->setFixedSize(MAIN_SIZE_EXPAND); + m_centerWidget->setFixedHeight(TLS_SCRO_HEIGHT); + break; + case KyEapMethodType::PEAP: + if (m_wirelessNetItem.m_connectUuid.isEmpty()) { + m_resource->getEnterPriseInfoPeap(m_wirelessNetItem.m_connectUuid, m_info.peapInfo); + } + this->setFixedSize(MAIN_SIZE_NARROW); + m_centerWidget->setFixedHeight(PEAP_SCRO_HEIGHT); + break; + case KyEapMethodType::TTLS: + if (!m_wirelessNetItem.m_connectUuid.isEmpty()) { + m_resource->getEnterPriseInfoTtls(m_wirelessNetItem.m_connectUuid, m_info.ttlsInfo); + } + this->setFixedSize(MAIN_SIZE_NARROW); + m_centerWidget->setFixedHeight(PEAP_SCRO_HEIGHT); + break; + default: + break; + } +} diff --git a/src/frontend/enterprise-wlan/enterprisewlandialog.h b/src/frontend/enterprise-wlan/enterprisewlandialog.h new file mode 100644 index 00000000..e193b1be --- /dev/null +++ b/src/frontend/enterprise-wlan/enterprisewlandialog.h @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef ENTERPRISEWLANDIALOG_H +#define ENTERPRISEWLANDIALOG_H +#include +#include +#include +#include + +#include "securitypage.h" +#include "divider.h" +#include "kywirelessnetitem.h" +#include "coninfo.h" + +class EnterpriseWlanDialog : public QWidget +{ + Q_OBJECT +public: + EnterpriseWlanDialog(KyWirelessNetItem &wirelessNetItem, QString device, QWidget *parent = nullptr); + ~EnterpriseWlanDialog(); + +protected: + void closeEvent(QCloseEvent *event); + void paintEvent(QPaintEvent *event); + +private: + void initUI(); //初始化UI界面 + void centerToScreen(); + void initConnections(); + void initData(); + +private: + KyWirelessNetItem m_wirelessNetItem; + ConInfo m_info; + QString m_deviceName; + KyWirelessConnectOperation *m_connectOperation = nullptr; + KyWirelessNetResource *m_resource = nullptr; + + /* 弹窗布局 + * Connect Enterprise WLAN············X + * SSID··························[SSID] + * -----------SecurityPage------------- + * | | + * ------------------------------------ + * ····················CANCEL···CONNECT + */ + QVBoxLayout *m_mainLayout = nullptr; + + QHBoxLayout *m_titleLayout = nullptr; + QLabel *m_titleLabel = nullptr; + QPushButton *m_closeBtn = nullptr; + + QWidget *m_centerWidget = nullptr; + QLabel *m_descriptionLabel = nullptr; + QLabel *m_ssidLabel = nullptr; + + SecurityPage *m_securityPage = nullptr; + + QScrollArea *m_enterWlanScrollArea = nullptr; + + Divider *m_bottomDivider = nullptr; + + QPushButton *m_cancelBtn = nullptr; + QPushButton *m_connectBtn = nullptr; + +private Q_SLOTS: + void onBtnConnectClicked(); + void onEapTypeChanged(const KyEapMethodType &type); + void onPaletteChanged(); + +Q_SIGNALS: + void enterpriseWlanDialogClose(bool); +}; + +#endif // ENTERPRISEWLANDIALOG_H diff --git a/src/frontend/frontend.pri b/src/frontend/frontend.pri new file mode 100644 index 00000000..b7703595 --- /dev/null +++ b/src/frontend/frontend.pri @@ -0,0 +1,24 @@ +INCLUDEPATH += $$PWD +include(tools/tools.pri) +include(xatom/xatom.pri) +include(tab-pages/tab-pages.pri) +include(list-items/list-items.pri) +include(netdetails/netdetails.pri) +include(enterprise-wlan/enterprise-wlan.pri) +include(networkmode/networkmode.pri) + +FORMS += \ + $$PWD/wificonfigdialog.ui + +HEADERS += \ + $$PWD/customstyle.h \ + $$PWD/mainwindow.h \ + $$PWD/wificonfigdialog.h + +SOURCES += \ + $$PWD/customstyle.cpp \ + $$PWD/mainwindow.cpp \ + $$PWD/wificonfigdialog.cpp + +DISTFILES += \ + $$PWD/networkmode/networkmode.pri diff --git a/src/frontend/list-items/lanlistitem.cpp b/src/frontend/list-items/lanlistitem.cpp new file mode 100644 index 00000000..e0165227 --- /dev/null +++ b/src/frontend/list-items/lanlistitem.cpp @@ -0,0 +1,281 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "lanlistitem.h" +#include "backend/dbus-interface/kylinconnectitem.h" + +#include + +#define LOG_FLAG "[LanListItem]" + +LanListItem::LanListItem(const KyConnectItem *lanConnectItem, + const QString &deviceName, QWidget *parent):ListItem(parent) +{ + m_connectOperation = new KyWiredConnectOperation(this); + m_deviceResource = new KyNetworkDeviceResourse(this); + + connectItemCopy(lanConnectItem); + m_deviceName = deviceName; + + m_nameLabel->setMinimumWidth(180); + m_nameLabel->setLabelText(m_lanConnectItem.m_connectName); + m_netButton->setButtonIcon(QIcon::fromTheme("network-wired-connected-symbolic")); + + qDebug() << "LanListItem init:" << m_lanConnectItem.m_connectName << m_lanConnectItem.m_connectState << m_lanConnectItem.m_ifaceName; + + if (Deactivated == m_lanConnectItem.m_connectState || Activated == m_lanConnectItem.m_connectState) { + m_netButton->stopLoading(); + if (m_lanConnectItem.m_connectState == Activated) { + setIcon(true); + } else { + setIcon(false); + } + } else { + m_netButton->startLoading(); + } + + m_itemFrame->installEventFilter(this); +// connect(this->m_infoButton, &InfoButton::clicked, this, &LanListItem::onInfoButtonClicked); + connect(m_menu, &QMenu::triggered, this, &LanListItem::onMenuTriggered); + connect(m_hoverButton, &QPushButton::clicked, this, &LanListItem::onNetButtonClicked); +} + + +LanListItem::LanListItem(QWidget *parent) : ListItem(parent) +{ + m_isActive = false; + m_netButton->setButtonIcon(QIcon::fromTheme("network-wired-disconnected-symbolic")); + setIcon(false); + const QString str=tr("Not connected"); + m_nameLabel->setLabelText(str); +// this->m_infoButton->hide(); +} + +LanListItem::~LanListItem() +{ + qDebug()<<"[LanPage] lan list item is deleted." << m_lanConnectItem.m_connectName; +} + +void LanListItem::setIcon(bool isOn) +{ + if (isOn) { + m_netButton->setActive(true); //设置图标显示不同颜色 + } else { + m_netButton->setActive(false); + } +} + +void LanListItem::connectItemCopy(const KyConnectItem *lanConnectItem) +{ + if (lanConnectItem) { + m_lanConnectItem.m_connectName = lanConnectItem->m_connectName; + m_lanConnectItem.m_connectPath = lanConnectItem->m_connectPath; + m_lanConnectItem.m_connectState = lanConnectItem->m_connectState; + m_lanConnectItem.m_connectUuid = lanConnectItem->m_connectUuid; + m_lanConnectItem.m_ifaceName = lanConnectItem->m_ifaceName; + m_lanConnectItem.m_itemType = lanConnectItem->m_itemType; + } else { + qDebug() << LOG_FLAG <<"the connect item is nullptr"; + m_lanConnectItem.m_connectName = ""; + m_lanConnectItem.m_connectPath = ""; + m_lanConnectItem.m_connectState = NetworkManager::ActiveConnection::State::Unknown; + m_lanConnectItem.m_connectUuid = ""; + m_lanConnectItem.m_ifaceName = ""; + m_lanConnectItem.m_itemType = NetworkManager::ConnectionSettings::ConnectionType::Unknown; + } + + return; +} + +void LanListItem::onNetButtonClicked() +{ + if (m_lanConnectItem.m_connectUuid.isEmpty()) { + qDebug() << LOG_FLAG << "connect is empty, so can not connect or disconnect."; + return; + } + + if (Deactivated == m_lanConnectItem.m_connectState) { + //断开的连接,点击激活连接 + if (m_deviceResource->wiredDeviceIsCarriered(m_deviceName)) { + m_connectOperation->activateWiredConnection(m_lanConnectItem.m_connectUuid, m_deviceName); + qDebug() << LOG_FLAG << "it will activate connection" << m_lanConnectItem.m_connectName + << ". it's device is" << m_deviceName; + m_netButton->startLoading(); + } else { + qDebug() << LOG_FLAG << m_deviceName << "is not carried, so can not activate connection"; + this->showDesktopNotify(tr("Wired Device not carried"), "networkwrong"); + } + } else { + m_connectOperation->deactivateWiredConnection(m_lanConnectItem.m_connectName, m_lanConnectItem.m_connectUuid); + } + + return; + +} + +void LanListItem::onRightButtonClicked() +{ + //右键点击事件 + qDebug()<< LOG_FLAG <<"onRightButtonClicked"; + if (!m_menu) { + return; + } + + m_menu->clear(); + if (Activated == m_lanConnectItem.m_connectState || Activating == m_lanConnectItem.m_connectState) { + m_menu->addAction(new QAction(tr("Disconnect"), this)); + } else if (Deactivated == m_lanConnectItem.m_connectState) { + m_menu->addAction(new QAction(tr("Connect"), this)); + } else { + return; + } + m_menu->addAction(new QAction(tr("Property"), this)); + m_menu->addAction(new QAction(tr("Delete"), this)); + + m_menu->move(cursor().pos()); + m_menu->show(); + return; +} + +void LanListItem::onMenuTriggered(QAction *action) +{ + if (action->text() == tr("Connect")) { + this->onNetButtonClicked(); + } else if (action->text() == tr("Disconnect")) { + m_connectOperation->deactivateWiredConnection(m_lanConnectItem.m_connectName, m_lanConnectItem.m_connectUuid); + qDebug() << LOG_FLAG << "it will disconnect connection" << m_lanConnectItem.m_connectName + << ". it's device is" << m_deviceName; + m_netButton->startLoading(); + } else if (action->text() == tr("Property")) { + onInfoButtonClicked(); + } else if (action->text() == tr("Delete")) { + m_connectOperation->deleteConnect(m_lanConnectItem.m_connectUuid); + } + return; +} + + +void LanListItem::onInfoButtonClicked() +{ + if (m_lanConnectItem.m_connectUuid.isEmpty()) { + qDebug() << LOG_FLAG << "connect is empty, so can not show detail info."; + return; + } + + if(netDetail != nullptr){ + netDetail->activateWindow(); + return; + } + + qDebug()<< LOG_FLAG << "the info button of lan is clicked! uuid = " + << m_lanConnectItem.m_connectUuid << "; name = " << m_lanConnectItem.m_connectName + << "." <show(); + Q_EMIT this->detailShow(true); + + return; +} + +void LanListItem::updateConnectionState(ConnectState state) +{ + m_lanConnectItem.m_connectState = (NetworkManager::ActiveConnection::State)state; + + if (Deactivated == state || Activated == state) { + m_netButton->stopLoading(); + if (state == Activated) { + setIcon(true); + } else { + setIcon(false); + } + } else { + m_netButton->startLoading(); + } + + return; +} + +QString LanListItem::getConnectionName() +{ + return m_lanConnectItem.m_connectName; +} + +void LanListItem::updateConnectionName(QString connectionName) +{ + m_lanConnectItem.m_connectName = connectionName; + m_nameLabel->setLabelText(m_lanConnectItem.m_connectName); + return; +} + +QString LanListItem::getConnectionPath() +{ + return m_lanConnectItem.m_connectPath; +} + +void LanListItem::updateConnectionPath(QString connectionPath) +{ + m_lanConnectItem.m_connectPath = connectionPath; +} + +void LanListItem::enterEvent(QEvent *event) +{ + if (m_lanConnectItem.m_connectState != UnknownState) { + if (Deactivated != m_lanConnectItem.m_connectState) { + m_hoverButton->setProperty("useButtonPalette", true); + m_hoverButton->setProperty("isImportant", false); + m_hoverButton->setText(tr("Disconnect")); + } else { + m_hoverButton->setProperty("isImportant", true); + m_hoverButton->setProperty("useButtonPalette", false); + m_hoverButton->setText(tr("Connect")); + } + m_hoverButton->show(); + m_lbLoadUp->hide(); + m_lbLoadDown->hide(); + m_lbLoadDownImg->hide(); + m_lbLoadUpImg->hide(); + } + return ListItem::enterEvent(event); +} + +void LanListItem::leaveEvent(QEvent *event) +{ + m_hoverButton->hide(); + if (m_lanConnectItem.m_connectState == Activated) { + m_lbLoadUp->show(); + m_lbLoadDown->show(); + m_lbLoadDownImg->show(); + m_lbLoadUpImg->show(); + } + return ListItem::leaveEvent(event); +} diff --git a/src/frontend/list-items/lanlistitem.h b/src/frontend/list-items/lanlistitem.h new file mode 100644 index 00000000..d6acd958 --- /dev/null +++ b/src/frontend/list-items/lanlistitem.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef LANLISTITEM_H +#define LANLISTITEM_H +#include "listitem.h" +#include "kylinactiveconnectresource.h" + +#include +#include +#include + +class LanListItem : public ListItem +{ + Q_OBJECT + +public: + LanListItem(const KyConnectItem *lanConnectItem, const QString &deviceName, QWidget *parent = nullptr); + LanListItem(QWidget *parent = nullptr); + + ~LanListItem(); + +public: + void updateConnectionState(ConnectState state); + + QString getConnectionName(); + void updateConnectionName(QString connectionName); + + QString getConnectionPath(); + void updateConnectionPath(QString connectionPath); + +protected: + void setIcon(bool isOn); + void onRightButtonClicked(); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + +private: + void connectItemCopy(const KyConnectItem *lanConnectItem); + +private Q_SLOTS: + void onInfoButtonClicked(); + void onNetButtonClicked(); + void onMenuTriggered(QAction *action); + +private: + KyConnectItem m_lanConnectItem; + + KyWiredConnectOperation *m_connectOperation = nullptr; + KyNetworkDeviceResourse *m_deviceResource = nullptr; + + QString m_deviceName = ""; +}; + +#endif // LANLISTITEM_H diff --git a/src/frontend/list-items/list-items.pri b/src/frontend/list-items/list-items.pri new file mode 100644 index 00000000..8fdc468e --- /dev/null +++ b/src/frontend/list-items/list-items.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +FORMS += \ + $$PWD/oneconnform.ui \ + $$PWD/onelancform.ui + +HEADERS += \ + $$PWD/lanlistitem.h \ + $$PWD/listitem.h \ + $$PWD/wlanlistitem.h \ + $$PWD/wlanmoreitem.h + +SOURCES += \ + $$PWD/lanlistitem.cpp \ + $$PWD/listitem.cpp \ + $$PWD/wlanlistitem.cpp \ + $$PWD/wlanmoreitem.cpp + diff --git a/src/frontend/list-items/listitem.cpp b/src/frontend/list-items/listitem.cpp new file mode 100644 index 00000000..d4121c89 --- /dev/null +++ b/src/frontend/list-items/listitem.cpp @@ -0,0 +1,315 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "listitem.h" +#include + +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_SPACING 0 +#define ITEM_FRAME_MARGINS 12,6,16,6 + +#define ITEM_FRAME_SPACING 8 +#define FRAME_WIDTH 404 +#define INFO_ICON_WIDTH 16 +#define INFO_ICON_HEIGHT 16 +#define LIGHT_HOVER_COLOR QColor(240,240,240,255) +#define DARK_HOVER_COLOR QColor(15,15,15,255) + +#define CONNECT_BUTTON_WIDTH 96 +#define PWD_AREA_HEIGHT 36 + +#define FREQLABLE_HIGHT 18 +#define FREQLABLE_MARGINS 4,0,4,0 +#define LOADIMG_SIZE 16,16 + +#define NAMELABLE_MAX_WIDTH 120 + +FreqLabel::FreqLabel(QWidget *parent) : QLabel(parent) +{ + const QByteArray id("org.ukui.style"); + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + if(QGSettings::isSchemaInstalled(id)){ + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("systemFontSize" ==key) { + changedFontSlot(); + } + }); + } + changedFontSlot(); +} + +void FreqLabel::changedFontSlot() +{ + const QByteArray id("org.ukui.style"); + if(QGSettings::isSchemaInstalled(id)){ + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + QVariant fontVariant = fontSetting->get("systemFontSize"); + QFont font; + font.setPointSize(fontVariant.toInt()*0.85); + this->setFont(font); + } +} + +void FreqLabel::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); //抗锯齿效果 + auto rect = this->rect(); + painter.drawRoundedRect(rect, 6, 6); + QLabel::paintEvent(event); +} + +ListItem::ListItem(QWidget *parent) : QFrame(parent) +{ + m_connectState = UnknownState; + + initUI(); + initConnection(); + connect(qApp, &QApplication::paletteChanged, this, &ListItem::onPaletteChanged); +// m_itemFrame->installEventFilter(this); +} + +ListItem::~ListItem() +{ + if (nullptr != m_netButton) { + delete m_netButton; + m_netButton = nullptr; + } + +// if (nullptr != m_infoButton) { +// delete m_infoButton; +// m_infoButton = nullptr; +// } + +} + +void ListItem::setName(const QString &name) +{ +// m_nameLabel->setMaximumWidth(NAMELABLE_MAX_WIDTH); + m_nameLabel->setLabelText(name); +} + +//仅无线调用,有线自己获取 +void ListItem::setActive(const bool &isActive) +{ + m_netButton->setActive(isActive); + m_isActive = isActive; +} + +void ListItem::setConnectState(ConnectState state) +{ + m_connectState = state; +} + +void ListItem::showDesktopNotify(const QString &message, QString soundName) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QStringList actions; //跳转动作 + actions.append("kylin-nm"); + actions.append("default"); //默认动作:点击消息体时打开麒麟录音 + QMap hints; + if (!soundName.isEmpty()) { + hints.insert("sound-name",soundName); //添加声音 + } + QList args; + args<<(tr("Kylin NM")) + <<((unsigned int) 0) + <button() == Qt::LeftButton) { + onNetButtonClicked(); + } else if (event->button() == Qt::RightButton) { + onRightButtonClicked(); + } + return QFrame::mousePressEvent(event); +} + +void ListItem::enterEvent(QEvent *event) +{ +// QPalette pal = qApp->palette(); +// QColor baseColor = qApp->palette().base().color(); +// if (baseColor.red() > MIDDLE_COLOR) { +// pal.setColor(QPalette::Window, LIGHT_HOVER_COLOR); +// } else { +// pal.setColor(QPalette::Window, DARK_HOVER_COLOR); +// } +// this->setPalette(pal); +// return QFrame::enterEvent(event); +} + +void ListItem::leaveEvent(QEvent *event) +{ +// QPalette pal = qApp->palette(); +// pal.setColor(QPalette::Window, qApp->palette().base().color()); +// this->setPalette(pal); +// return QFrame::leaveEvent(event); +} + +void ListItem::paintEvent(QPaintEvent *event) +{ +// QPainter painter(this); +// painter.setRenderHint(QPainter::Antialiasing); //反锯齿 +// painter.setBrush(this->palette().brush(QPalette::Window)); +// painter.setPen(Qt::transparent); +// painter.drawRoundedRect(this->rect(), 6, 6); +// return QFrame::paintEvent(event); +} + +void ListItem::initUI() +{ + m_menu = new QMenu(this);//右键菜单 +// m_menu->setStyleSheet("QMenu::item{border:3px; border-radius:3px}"); +// m_menu->setStyleSheet("QMenu{border-radius:6px; margin:6px 6px 6px 6px}"); + connect(m_menu, &QMenu::triggered, this, &ListItem::onMenuTriggered); + + m_mainLayout = new QVBoxLayout(this); + m_mainLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); + m_mainLayout->setSpacing(MAIN_LAYOUT_SPACING); + this->setLayout(m_mainLayout); + + m_itemFrame = new QFrame(this); + m_itemFrame->setFixedWidth(FRAME_WIDTH); + + m_hItemLayout = new QHBoxLayout(m_itemFrame); + m_hItemLayout->setContentsMargins(ITEM_FRAME_MARGINS); + m_hItemLayout->setSpacing(ITEM_FRAME_SPACING); + m_hItemLayout->setAlignment(Qt::AlignHCenter); + + m_netButton = new RadioItemButton(m_itemFrame); + m_freq = new FreqLabel(m_itemFrame); + m_freq->setEnabled(false); + m_freq->setText("..."); + m_freq->setAlignment(Qt::AlignCenter); + m_freq->hide(); + m_freq->setFixedHeight(FREQLABLE_HIGHT); + m_freq->setContentsMargins(FREQLABLE_MARGINS); + m_nameLabel = new NameLabel(m_itemFrame); + m_hoverButton = new QPushButton(m_itemFrame); + m_hoverButton->setProperty("needTranslucent", true); + m_hoverButton->setFixedSize(CONNECT_BUTTON_WIDTH, PWD_AREA_HEIGHT); +// m_infoButton = new InfoButton(m_itemFrame); +// m_infoButton->setIconSize(QSize(INFO_ICON_WIDTH,INFO_ICON_HEIGHT)); + + m_lbLoadUp = new QLabel(m_itemFrame); + m_lbLoadUp->setAlignment(Qt::AlignCenter); + m_lbLoadDown = new QLabel(m_itemFrame); + m_lbLoadDown->setAlignment(Qt::AlignCenter); + m_lbLoadDownImg = new QLabel(m_itemFrame); + m_lbLoadUpImg = new QLabel(m_itemFrame); + m_lbLoadUp->hide(); + m_lbLoadDown->hide(); + m_lbLoadDownImg->hide(); + m_lbLoadUpImg->hide(); + m_lbLoadDownImg->setFixedSize(LOADIMG_SIZE); + m_lbLoadDownImg->setAlignment(Qt::AlignCenter); + m_lbLoadUpImg->setFixedSize(LOADIMG_SIZE); + m_lbLoadUpImg->setAlignment(Qt::AlignCenter); + QFont font; + font.setPointSize(10); + m_lbLoadUp->setFont(font); + m_lbLoadDown->setFont(font); + m_lbLoadUp->setText("0KB/s"); + m_lbLoadDown->setText("0KB/s"); + m_lbLoadDownImg->setStyleSheet("QLabel{background-image:url(:/res/x/load-down.png);}"); + m_lbLoadUpImg->setStyleSheet("QLabel{background-image:url(:/res/x/load-up.png);}"); + + m_hItemLayout->addWidget(m_netButton); + m_hItemLayout->addWidget(m_nameLabel); + m_hItemLayout->addWidget(m_freq); + m_hItemLayout->addStretch(); + m_hItemLayout->addWidget(m_lbLoadUpImg); + m_hItemLayout->addWidget(m_lbLoadUp); + m_hItemLayout->addWidget(m_lbLoadDownImg); + m_hItemLayout->addWidget(m_lbLoadDown); + m_hItemLayout->addWidget(m_hoverButton); +// m_hItemLayout->addWidget(m_infoButton); + + m_mainLayout->addWidget(m_itemFrame); + + m_hoverButton->hide(); + +// this->setAutoFillBackground(true); +// this->setBackgroundRole(QPalette::Base); +// QPalette pal = qApp->palette(); +// pal.setColor(QPalette::Window, qApp->palette().base().color()); +// this->setPalette(pal); +} + + +void ListItem::initConnection() +{ + connect(this->m_netButton, &RadioItemButton::clicked, this, &ListItem::onNetButtonClicked); + // connect(this->m_infoButton, &InfoButton::clicked, this, &ListItem::onInfoButtonClicked); +} + +void ListItem::onPaletteChanged() +{ +// QPalette pal = qApp->palette(); +// pal.setColor(QPalette::Window, qApp->palette().base().color()); +// this->setPalette(pal); +} + + +NameLabel::NameLabel(QWidget *parent) + :QLabel(parent) +{ + const QByteArray id("org.ukui.style"); + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + if(QGSettings::isSchemaInstalled(id)){ + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("systemFont" == key || "systemFontSize" ==key) { + changedLabelSlot(); + } + }); + } +} + +void NameLabel::setLabelText(QString text) +{ + m_name = text; + changedLabelSlot(); +} + +void NameLabel::changedLabelSlot() +{ + QFontMetrics fontMetrics(this->font()); + int fontSize = fontMetrics.width(m_name); + if (fontSize > this->width() && fontSize > NAMELABLE_MAX_WIDTH) { + this->setFixedWidth(NAMELABLE_MAX_WIDTH); + setText(fontMetrics.elidedText(m_name, Qt::ElideRight, this->width())); + setToolTip(m_name); + } else { + this->setFixedWidth(fontMetrics.width(m_name)); + setText(m_name); + setToolTip(""); + } +} diff --git a/src/frontend/list-items/listitem.h b/src/frontend/list-items/listitem.h new file mode 100644 index 00000000..925278fc --- /dev/null +++ b/src/frontend/list-items/listitem.h @@ -0,0 +1,126 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef LISTITEM_H +#define LISTITEM_H +#include +#include +#include +#include +#include +#include +#include "radioitembutton.h" +#include "infobutton.h" +#include "netdetails/netdetail.h" + +typedef enum{ + UnknownState = 0, /**< The active connection is in an unknown state */ + Activating, /**< The connection is activating */ + Activated, /**< The connection is activated */ + Deactivating, /**< The connection is being torn down and cleaned up */ + Deactivated /**< The connection is no longer active */ +}ConnectState; + +class FreqLabel : public QLabel +{ + Q_OBJECT +public: + FreqLabel(QWidget *parent = nullptr); + ~FreqLabel() = default; +protected: + void paintEvent(QPaintEvent *event); + +private Q_SLOTS: + void changedFontSlot(); +}; + +class NameLabel : public QLabel +{ + Q_OBJECT +public: + explicit NameLabel(QWidget *parent = 0); + ~NameLabel() = default; + void setLabelText(QString text); + +private: + QString m_name; + +private Q_SLOTS: + void changedLabelSlot(); + +}; + +class ListItem : public QFrame +{ + Q_OBJECT +public: + ListItem(QWidget *parent = nullptr); + ~ListItem(); + void setName(const QString &name); + void setActive(const bool &isActive); + void setConnectState(ConnectState state); + static void showDesktopNotify(const QString &message, QString soundName); + +protected: + void mousePressEvent(QMouseEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void paintEvent(QPaintEvent *event); + virtual void onRightButtonClicked() = 0; + +protected: + QFrame * m_itemFrame = nullptr; + + NameLabel * m_nameLabel = nullptr; + RadioItemButton * m_netButton = nullptr; +// InfoButton * m_infoButton = nullptr; + + bool m_isActive = false; + ConnectState m_connectState; + + QMenu *m_menu = nullptr; + + +public: + QVBoxLayout * m_mainLayout = nullptr; + QHBoxLayout * m_hItemLayout = nullptr; + + QLabel *m_lbLoadDown = nullptr; + QLabel *m_lbLoadUp = nullptr; + QLabel *m_lbLoadDownImg = nullptr; + QLabel *m_lbLoadUpImg = nullptr; + QLabel *m_freq = nullptr; + + NetDetail *netDetail = nullptr; + + QPushButton *m_hoverButton = nullptr; +private: + void initUI(); + void initConnection(); + +public Q_SLOTS: + virtual void onNetButtonClicked() = 0; + void onPaletteChanged(); + virtual void onMenuTriggered(QAction *action)=0; + +Q_SIGNALS: + void detailShow(bool isShow); +}; + +#endif // LISTITEM_H diff --git a/src/frontend/list-items/oneconnform.ui b/src/frontend/list-items/oneconnform.ui new file mode 100644 index 00000000..9e47beaa --- /dev/null +++ b/src/frontend/list-items/oneconnform.ui @@ -0,0 +1,302 @@ + + + OneConnForm + + + + 0 + 0 + 424 + 142 + + + + Form + + + + + 63 + 8 + 241 + 20 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 14 + 14 + 32 + 32 + + + + + + + + + + 63 + 31 + 140 + 20 + + + + + + + + + + 0 + 0 + 424 + 106 + + + + + + 64 + 64 + 352 + 30 + + + + + + + 390 + 75 + 18 + 9 + + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 0 + 0 + 424 + 138 + + + + + + 63 + 64 + 230 + 61 + + + + + + + + + + 63 + 62 + 230 + 20 + + + + + + + + + + 63 + 86 + 230 + 20 + + + + + + + + + + 63 + 110 + 230 + 20 + + + + + + + leInfo_1 + leInfo_2 + leInfo_3 + btnInfo + + + + + 2 + 59 + 421 + 2 + + + + background-color: rgba(156, 156, 156,0.1); + + + Qt::Horizontal + + + + + + 0 + 0 + 424 + 60 + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 380 + 20 + 20 + 20 + + + + + + + + + + 316 + 14 + 70 + 34 + + + + + + + wbg_3 + wbg_2 + lbName + lbSignal + lbConned + line + wbg + btnConnSub + btnConn + btnConnPWD + btnDisConn + btnHideConn + lbWaiting + lbWaitingIcon + btnCancel + + + + diff --git a/src/frontend/list-items/onelancform.ui b/src/frontend/list-items/onelancform.ui new file mode 100644 index 00000000..ee3f4a06 --- /dev/null +++ b/src/frontend/list-items/onelancform.ui @@ -0,0 +1,254 @@ + + + OneLancForm + + + + 0 + 0 + 424 + 167 + + + + Form + + + + + 63 + 8 + 190 + 20 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 63 + 31 + 200 + 20 + + + + + + + + + + 0 + 0 + 424 + 162 + + + + + + 63 + 64 + 238 + 85 + + + + + + + + + + 63 + 62 + 238 + 20 + + + + + + + + + + 63 + 86 + 260 + 20 + + + + + + + + + + 63 + 110 + 238 + 20 + + + + + + + + + + 63 + 134 + 238 + 20 + + + + + + + leInfo_1 + leInfo_2 + leInfo_3 + leInfo_4 + btnInfo + + + + + 14 + 14 + 32 + 32 + + + + + + + + + + 2 + 59 + 421 + 2 + + + + background-color: rgba(156, 156, 156,0.1); + + + Qt::Horizontal + + + + + + 0 + 0 + 424 + 60 + + + + + + + 316 + 14 + 100 + 34 + + + + + + + + + + 380 + 20 + 20 + 20 + + + + + + + + + + 316 + 14 + 70 + 34 + + + + + + + wbg + wbg_2 + lbName + lbConned + lbIcon + line + btnConnSub + btnDisConn + btnConn + lbWaiting + lbWaitingIcon + btnCancel + + + + diff --git a/src/frontend/list-items/wlanlistitem.cpp b/src/frontend/list-items/wlanlistitem.cpp new file mode 100644 index 00000000..d0b05f77 --- /dev/null +++ b/src/frontend/list-items/wlanlistitem.cpp @@ -0,0 +1,725 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wlanlistitem.h" +#include +#include +#include + +#define EMPTY_SSID "EMPTY_SSID" +#define LOG_FLAG "[WlanListItem]" +#define WAIT_US 10*1000 +#define ENABLE_BUTTON_COLOR qApp->palette().highlight().color() +#define UNABLE_BUTTON_COLOR qApp->palette().button().color() + +const QString ENTERPRICE_TYPE = "802.1X"; +const QString WPA1_AND_WPA2 = "WPA"; +const QString WPA3 = "WPA3"; + +WlanListItem::WlanListItem(KyWirelessNetItem &wirelessNetItem, QString device, bool isApMode, QWidget *parent) + : WlanListItem(wirelessNetItem, device, parent) +{ + m_isApMode = isApMode; + refreshIcon(false); // 额外刷新一次图标,因为WlanListItem执行时,m_isApMode尚未赋值 +} + +WlanListItem::WlanListItem(KyWirelessNetItem &wirelessNetItem, QString device, QWidget *parent) : ListItem(parent) +{ + m_wlanDevice = device; + m_wirelessNetItem = wirelessNetItem; + + qDebug()<<"[WlanPage] wlan list item is created." << m_wirelessNetItem.m_NetSsid; + + initWlanUI(); + setExpanded(false); + +// connect(this->m_infoButton, &InfoButton::clicked, this, &WlanListItem::onInfoButtonClicked); + connect(m_menu, &QMenu::triggered, this, &WlanListItem::onMenuTriggered); + connect(m_hoverButton, &QPushButton::clicked, this, &WlanListItem::onNetButtonClicked); + + m_wirelessConnectOperation = new KyWirelessConnectOperation(this); + m_deviceResource = new KyNetworkDeviceResourse(this); +} + +WlanListItem::WlanListItem(QWidget *parent) : ListItem(parent) +{ + m_wirelessNetItem.m_NetSsid = EMPTY_SSID; + + qDebug()<<"[WlanPage] wlan list item is created." << m_wirelessNetItem.m_NetSsid; + + m_netButton->setButtonIcon(QIcon::fromTheme("network-wireless-offline-symbolic")); + m_netButton->setActive(false); +// m_netButton->setDefaultPixmap(); + const QString name = tr("Not connected"); + setExpanded(false); + this->setName(name); +// this->m_netButton->setEnabled(false); +// this->m_infoButton->hide(); +} + +WlanListItem::~WlanListItem() +{ + qDebug()<<"[WlanPage] wlan list item is deleted." << m_wirelessNetItem.m_NetSsid; +} + +QString WlanListItem::getSsid() +{ + return m_wirelessNetItem.m_NetSsid; +} + +QString WlanListItem::getUuid() +{ + return m_wirelessNetItem.m_connectUuid; +} + +QString WlanListItem::getPath() +{ + return m_wirelessNetItem.m_connDbusPath; +} + +void WlanListItem::setSignalStrength(const int &signal) +{ + m_wirelessNetItem.m_signalStrength = signal; + if (Activated == m_connectState) { + refreshIcon(true); + } else if (Deactivated == m_connectState) { + refreshIcon(false); + } + + return; +} + +int WlanListItem::getSignalStrength() +{ + return m_wirelessNetItem.m_signalStrength; +} + +bool WlanListItem::isConfigured() +{ + return m_wirelessNetItem.m_isConfigured; +} + +void WlanListItem::setWlanState(const int &state) +{ +// m_wirelessNetItem.m_state = state; //ZJP_TODO 后端接口待补全 + refreshIcon(false); +} + +void WlanListItem::setExpanded(const bool &expanded) +{ + if (!m_pwdFrame || !m_autoConnectFrame) { + this->setFixedHeight(NORMAL_HEIGHT); + return; + } + + m_pwdFrame->setVisible(expanded); + m_autoConnectFrame->setVisible(expanded); + + if (expanded) { + m_pwdLineEdit->setFocus(); + setFixedHeight(EXPANDED_HEIGHT); + m_hoverButton->hide(); + } else { + setFixedHeight(NORMAL_HEIGHT); + } + + Q_EMIT this->itemHeightChanged(expanded, m_wirelessNetItem.m_NetSsid); + + return; +} + +void WlanListItem::resizeEvent(QResizeEvent *event) +{ + this->blockSignals(true); + + if (this->height() == EXPANDED_HEIGHT) { + this->setExpanded(true); + } else { + this->setExpanded(false); + } + + this->blockSignals(false); + + return ListItem::resizeEvent(event); +} + +void WlanListItem::onRightButtonClicked() +{ + qDebug()<< LOG_FLAG <<"onRightButtonClicked"; + + if (!m_menu) { + return; + } + + m_menu->clear(); + + if (Activated == m_connectState || Activating == m_connectState) { + m_menu->addAction(new QAction(tr("Disconnect"), this)); + } else if (Deactivated == m_connectState) { + m_menu->addAction(new QAction(tr("Connect"), this)); + qDebug() << "add connect action"; + } else { + return; + } + + + if (m_wirelessNetItem.m_isConfigured) { + m_menu->addAction(new QAction(tr("Property"), this)); + m_menu->addAction(new QAction(tr("Forget"), this)); + } + + m_menu->move(cursor().pos()); + m_menu->show(); + + return; +} + +void WlanListItem::enterEvent(QEvent *event) +{ + //qDebug()<< LOG_FLAG <<"enterEvent" << m_wirelessNetItem.m_NetSsid; + m_mouseIsOut = false; + if (m_pwdFrame != nullptr && !m_pwdFrame->isVisible()) { + if (Deactivated != m_connectState) { + m_hoverButton->setProperty("useButtonPalette", true); + m_hoverButton->setProperty("isImportant", false); + m_hoverButton->setText(tr("Disconnect")); + } else { + m_hoverButton->setProperty("isImportant", true); + m_hoverButton->setProperty("useButtonPalette", false); + m_hoverButton->setText(tr("Connect")); + } + m_hoverButton->show(); + m_lbLoadUp->hide(); + m_lbLoadDown->hide(); + m_lbLoadDownImg->hide(); + m_lbLoadUpImg->hide(); + } + return ListItem::enterEvent(event); +} + +void WlanListItem::leaveEvent(QEvent *event) +{ + //qDebug()<< LOG_FLAG <<"leaveEvent"<< m_wirelessNetItem.m_NetSsid; + m_mouseIsOut = true; + m_hoverButton->hide(); + if (m_connectState == Activated) { + m_lbLoadUp->show(); + m_lbLoadDown->show(); + m_lbLoadDownImg->show(); + m_lbLoadUpImg->show(); + } + if (m_pwdFrame && m_pwdFrame->isVisible()) { + if (m_focusIsOut) { + setExpanded(false); + } + return QFrame::leaveEvent(event); + } + + return ListItem::leaveEvent(event); +} + +bool WlanListItem::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == m_autoConnectCheckBox) { + if (event->type() == QEvent::FocusIn) { + m_pwdLineEdit->setFocus(); + } + } + + if (watched == m_pwdLineEdit) { + if (event->type() == QEvent::FocusOut) { + m_focusIsOut = true; + //qDebug()<< LOG_FLAG <<"focusOutEvent" << m_wirelessNetItem.m_NetSsid; + if (m_mouseIsOut) { + setExpanded(false); + } + } else if (event->type() == QEvent::FocusIn) { + //qDebug()<< LOG_FLAG <<"focusInEvent" << m_wirelessNetItem.m_NetSsid; + m_focusIsOut = false; + } + } + + return QFrame::eventFilter(watched, event); +} + +void WlanListItem::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + if (m_pwdFrame && m_pwdFrame->isVisible() && m_pwdLineEdit->text().length() >= PWD_LENGTH_LIMIT) { + onConnectButtonClicked(); + } + } + return QFrame::keyPressEvent(event); +} + +void WlanListItem::paintEvent(QPaintEvent *event) +{ + QPalette pal = qApp->palette(); + if (m_pwdLineEdit != nullptr) { + m_pwdLineEdit->setPalette(pal); + } + + return QWidget::paintEvent(event); +} + +void WlanListItem::initWlanUI() +{ + m_hasPwd = (m_wirelessNetItem.m_secuType.isEmpty() || m_wirelessNetItem.m_secuType == "") ? false : true; + //设置显示的Wlan名称 +// this->setName((m_wirelessNetItem.m_connName != "") ? m_wirelessNetItem.m_connName : m_wirelessNetItem.m_NetSsid); + this->setName(m_wirelessNetItem.m_NetSsid); + //刷新左侧按钮图标 + refreshIcon(false); + +#define PWD_AREA_HEIGHT 36 +#define CONNECT_BUTTON_WIDTH 96 +#define FRAME_CONTENT_MARGINS 56,0,16,4 +#define FRAME_SPACING 8 +#define LINEEDIT_WIDTH 220 +#define PWD_CONTENT_MARGINS 8,0,34,0 +#define SHOW_PWD_BUTTON_SIZE 24,24 +#define PWD_LAYOUT_MARGINS 8,0,8,0 + //密码输入区域的UI + m_pwdFrame = new QFrame(this); + m_pwdFrameLyt = new QHBoxLayout(m_pwdFrame); + m_pwdFrameLyt->setContentsMargins(FRAME_CONTENT_MARGINS); + m_pwdFrameLyt->setSpacing(FRAME_SPACING); + m_pwdFrame->setLayout(m_pwdFrameLyt); + + m_pwdLineEdit = new KPasswordEdit(m_pwdFrame); + m_pwdLineEdit->setFixedWidth(LINEEDIT_WIDTH); + m_pwdLineEdit->setProperty("needTranslucent", true); + m_pwdLineEdit->setUseCustomPalette(true); + m_pwdLineEdit->setClearButtonEnabled(false); //禁用ClearBtn按钮 + m_pwdLineEdit->setAttribute(Qt::WA_InputMethodEnabled, true); //打开输入法 +// m_pwdLineEdit->setAttribute(Qt::WA_InputMethodEnabled, false); +// m_pwdLineEdit->setContextMenuPolicy(Qt::NoContextMenu); + + QRegExp rx("^[A-Za-z0-9`~!@#$%^&*()_-+=<>,.\\\/]+$"); + QRegExpValidator *latitude = new QRegExpValidator(rx, this); + m_pwdLineEdit->setValidator(latitude); + + m_pwdLineEdit->installEventFilter(this); + connect(m_pwdLineEdit, &QLineEdit::textChanged, this, &WlanListItem::onPwdEditorTextChanged); + m_pwdLineEdit->setFixedHeight(PWD_AREA_HEIGHT); + m_pwdFrameLyt->addWidget(m_pwdLineEdit); + + m_connectButton = new QPushButton(m_pwdFrame); + m_connectButton->setProperty("isImportant", true); + m_connectButton->setProperty("needTranslucent", true); + m_connectButton->setFixedSize(CONNECT_BUTTON_WIDTH, PWD_AREA_HEIGHT); + m_connectButton->setText(tr("Connect")); + m_connectButton->setEnabled(false); + connect(m_connectButton, &QPushButton::clicked, this, &WlanListItem::onConnectButtonClicked); + m_pwdFrameLyt->addWidget(m_connectButton); + m_pwdFrameLyt->addStretch(); + + //自动连接选择区域UI + m_autoConnectFrame = new QFrame(this); + + m_autoConnectFrameLyt = new QHBoxLayout(m_autoConnectFrame); + m_autoConnectFrameLyt->setContentsMargins(FRAME_CONTENT_MARGINS); + m_autoConnectFrameLyt->setSpacing(FRAME_SPACING); + m_autoConnectFrame->setLayout(m_autoConnectFrameLyt); + + m_autoConnectCheckBox = new QCheckBox(m_autoConnectFrame); + m_autoConnectCheckBox->installEventFilter(this); + m_autoConnectCheckBox->setChecked(true); + m_autoConnectCheckBox->setFixedSize(SHOW_PWD_BUTTON_SIZE); + m_autoConnectFrameLyt->addWidget(m_autoConnectCheckBox); + + m_autoConnectLabel = new QLabel(m_autoConnectFrame); + m_autoConnectLabel->setText(tr("Auto Connect")); + m_autoConnectFrameLyt->addWidget(m_autoConnectLabel); + m_autoConnectFrameLyt->addStretch(); + + m_mainLayout->addWidget(m_pwdFrame); + m_mainLayout->addWidget(m_autoConnectFrame); + m_mainLayout->addStretch(); + + m_pwdFrame->hide(); + m_autoConnectFrame->hide(); + + this->m_freq->show(); + this->setFrequency(); +} + +QString getIcon(bool isEncrypted, int signalStrength, int category) { + QString iconNameFirst,iconNameLast; + if (category == 0){ + iconNameFirst = "network-wireless-signal-"; + } else if (category == 1) { + iconNameFirst = "ukui-wifi6-"; + } else { + iconNameFirst = "ukui-wifi6+-"; + } + if (!isEncrypted) { + if (signalStrength > EXCELLENT_SIGNAL){ + if (category == 0) { + iconNameLast = "excellent-symbolic"; + } else { + iconNameLast = "full-symbolic"; + } + } else if (signalStrength > GOOD_SIGNAL) { + if (category == 0) { + iconNameLast = "good-symbolic"; + } else { + iconNameLast = "high-symbolic"; + } + } else if (signalStrength > OK_SIGNAL) { + if (category == 0) { + iconNameLast = "ok-symbolic"; + } else { + iconNameLast = "medium-symbolic"; + } + } else if (signalStrength > LOW_SIGNAL) { + if (category == 0) { + iconNameLast = "weak-symbolic"; + } else { + iconNameLast = "low-symbolic"; + } + } else { + iconNameLast = "none-symbolic"; + } + } else { + if (signalStrength > EXCELLENT_SIGNAL){ + if (category == 0) { + iconNameLast = "excellent-secure-symbolic"; + } else { + iconNameLast = "full-pwd-symbolic"; + } + } else if (signalStrength > GOOD_SIGNAL) { + if (category == 0) { + iconNameLast = "good-secure-symbolic"; + } else { + iconNameLast = "high-pwd-symbolic"; + } + } else if (signalStrength > OK_SIGNAL) { + if (category == 0) { + iconNameLast = "ok-secure-symbolic"; + } else { + iconNameLast = "medium-pwd-symbolic"; + } + } else if (signalStrength > LOW_SIGNAL) { + if (category == 0) { + iconNameLast = "weak-secure-symbolic"; + } else { + iconNameLast = "low-pwd-symbolic"; + } + } else { + if (category == 0) { + iconNameLast = "none-secure-symbolic"; + } else { + iconNameLast = "none-pwd-symbolic"; + } + } + } + return iconNameFirst + iconNameLast; +} + +void WlanListItem::refreshIcon(bool isActivated) +{ + if (m_isApMode) { + m_netButton->setButtonIcon(QIcon::fromTheme("network-wireless-hotspot-symbolic", QIcon(":/res/w/wifi-full.png"))); + m_netButton->setActive(isActivated); + return; + } + + int category = 0; + int signalStrength = 0; + QString uni = ""; + QString secuType = ""; + category = m_wirelessNetItem.getCategory(m_wirelessNetItem.m_uni); + signalStrength = m_wirelessNetItem.m_signalStrength; + + if (isActivated) { + if (m_deviceResource->getActiveConnectionInfo(m_wlanDevice, signalStrength, uni, secuType)) { + category = m_wirelessNetItem.getCategory(uni); + m_hasPwd = (secuType.isEmpty() || secuType == "") ? false : true; + } + } + + QString iconPath = getIcon(m_hasPwd, signalStrength, category); + m_netButton->setButtonIcon(QIcon::fromTheme(iconPath)); + + m_netButton->setActive(isActivated); + qDebug() << "refreshIcon" << m_wirelessNetItem.m_NetSsid << "isActivated" << isActivated << "path" << iconPath; +} + +void WlanListItem::onInfoButtonClicked() +{ + //ZJP_TODO 呼出无线详情页 + if(netDetail != nullptr){ + netDetail->activateWindow(); + return; + } + + qDebug() << LOG_FLAG << "Net active or not:"<< m_connectState; + qDebug() << LOG_FLAG << "On wlan info button clicked! ssid = " + << m_wirelessNetItem.m_NetSsid << "; name = " + << m_wirelessNetItem.m_connName << "." <show(); + Q_EMIT this->detailShow(true); +} + +void WlanListItem::onNetButtonClicked() +{ + qDebug() << LOG_FLAG << "onNetButtonClicked"; + if (m_wirelessNetItem.m_NetSsid == EMPTY_SSID) { + return; + } + + if (Deactivated != m_connectState) { + m_wirelessConnectOperation->deActivateWirelessConnection(m_wlanDevice, m_wirelessNetItem.m_connectUuid); + return; + } + + //获取有配置网络的安全类型 + KyKeyMgmt type = m_wirelessConnectOperation->getConnectKeyMgmt(m_wirelessNetItem.m_connectUuid); + KySecuType kySecuType = NONE; + if (type == WpaNone || type == Unknown) { + kySecuType = NONE; + } else if (type == WpaPsk) { + kySecuType = WPA_AND_WPA2_PERSONAL; + } else if (type == SAE) { + kySecuType = WPA3_PERSONAL; + } else if (type == WpaEap) { + kySecuType = WPA_AND_WPA2_ENTERPRISE; + } else { + qDebug() << "KeyMgmt not support now " << type; + } + //qDebug() << "!!!!" << m_wirelessNetItem.m_kySecuType << kySecuType; + //有配置或者无密码的wifi直接连接 + if (m_wirelessNetItem.m_isConfigured) { + if (m_wirelessNetItem.m_kySecuType == kySecuType) { + //安全类型不变直接连接 + m_wirelessConnectOperation->activeWirelessConnect(m_wlanDevice, m_wirelessNetItem.m_connectUuid); + qDebug()<<"[WlanListItem] Has configuration, will be activated. ssid = " + << m_wirelessNetItem.m_NetSsid << Q_FUNC_INFO << __LINE__; + m_netButton->startLoading(); + return; + } else { + //安全类型改变则删除连接 + m_wirelessConnectOperation->deleteWirelessConnect(m_wirelessNetItem.m_connectUuid); + } + } + + if (!this->m_connectButton->isVisible() && m_wirelessNetItem.m_secuType != "") { + if (m_wirelessNetItem.m_secuType.contains("802.1x", Qt::CaseInsensitive)) { + if (isEnterpriseWlanDialogShow && enterpriseWlanDialog != nullptr) { + qDebug() << LOG_FLAG <<"EnterpriseWlanDialog is show do not show again!"; + KWindowSystem::raiseWindow(enterpriseWlanDialog->winId()); + return; + } else { + enterpriseWlanDialog = new EnterpriseWlanDialog(m_wirelessNetItem, m_wlanDevice); + connect(enterpriseWlanDialog, &EnterpriseWlanDialog::enterpriseWlanDialogClose, this, &WlanListItem::onEnterpriseWlanDialogClose); + enterpriseWlanDialog->show(); + isEnterpriseWlanDialogShow = true; + } + } else { + this->setExpanded(true); + } + } else { + onConnectButtonClicked(); + } + + return; +} + +void WlanListItem::updateWirelessNetSecurity(QString ssid, QString securityType) +{ + if (ssid != m_wirelessNetItem.m_NetSsid) { + return; + } + + qDebug() << LOG_FLAG << "Security changed! ssid = " << m_wirelessNetItem.m_NetSsid + << "; security = " << m_wirelessNetItem.m_secuType << "change to "<< securityType <text().length() < PWD_LENGTH_LIMIT) { + m_connectButton->setEnabled(false); + } else { + m_connectButton->setEnabled(true); + } + + return; +} + +void WlanListItem::onConnectButtonClicked() +{ + qDebug()<< LOG_FLAG << "onConnectButtonClicked"; + if ((Activating == m_connectState || Deactivating == m_connectState)) { + qDebug() << LOG_FLAG << "On wlan clicked! But there is nothing to do because it is already activating/deactivating!" + << Q_FUNC_INFO << __LINE__; + return; + } + + if (m_connectButton->isVisible() && !m_connectButton->isEnabled()) { + qWarning() << "Connect wlan failed because of null pointer or button state!" << Q_FUNC_INFO << __LINE__; + return; + } + + KyWirelessConnectSetting settings; + settings.m_connectName = m_wirelessNetItem.m_NetSsid; + settings.m_ssid = m_wirelessNetItem.m_NetSsid; + settings.isAutoConnect = m_autoConnectCheckBox->isChecked(); + settings.m_psk = m_pwdLineEdit->text(); + if (m_wirelessNetItem.m_secuType.isEmpty() || m_wirelessNetItem.m_secuType == "") { + settings.m_type = WpaNone; + } else if (m_wirelessNetItem.m_secuType.contains("WPA1") || m_wirelessNetItem.m_secuType.contains("WPA2")) { + settings.m_type = WpaPsk; + } else if (m_wirelessNetItem.m_secuType.contains("WPA3")) { + settings.m_type = SAE; + } + + qDebug() << "[WlanListItem] On button connect clicked, will connect wlan. ssid = " + << m_wirelessNetItem.m_NetSsid << Q_FUNC_INFO <<__LINE__; + + m_wirelessConnectOperation->addAndActiveWirelessConnect(m_wlanDevice, settings, false); + setExpanded(false); + m_netButton->startLoading(); + return; +} + +ConnectState WlanListItem::getConnectionState() +{ + return m_connectState; +} + +void WlanListItem::updateConnectState(ConnectState state) +{ + m_connectState = state; + + if (Activated == state) { + m_netButton->stopLoading(); + m_netButton->setActive(true); + m_hoverButton->setProperty("useButtonPalette", true); + m_hoverButton->setProperty("isImportant", false); + m_hoverButton->setText(tr("Disconnect")); + } else if(Deactivated == state) { + qDebug() << "[WlanListItem] stop loading connect state:" << state; + m_netButton->stopLoading(); + m_netButton->setActive(false); + m_hoverButton->setProperty("isImportant", true); + m_hoverButton->setProperty("useButtonPalette", false); + m_hoverButton->setText(tr("Connect")); + } else { + qDebug() << "[WlanListItem] start loading connect state:" << state; + m_netButton->startLoading(); + m_hoverButton->setProperty("useButtonPalette", true); + m_hoverButton->setProperty("isImportant", false); + m_hoverButton->setText(tr("Disconnect")); + } + + return; +} + +void WlanListItem::onMenuTriggered(QAction *action) +{ + if (action->text() == tr("Connect")) { + this->onNetButtonClicked(); + } else if (action->text() == tr("Disconnect")) { + m_wirelessConnectOperation->deActivateWirelessConnection(m_wlanDevice, m_wirelessNetItem.m_connectUuid); + qDebug()<<"[WlanListItem] Clicked on connected wifi, it will be inactivated. ssid = " + << m_wirelessNetItem.m_NetSsid << Q_FUNC_INFO << __LINE__; + m_netButton->startLoading(); + } else if (action->text() == tr("Forget")) { + if (m_pwdLineEdit != nullptr) { + m_pwdLineEdit->clear(); + } + m_wirelessConnectOperation->deleteWirelessConnect(m_wirelessNetItem.m_connectUuid); + } else if (action->text() == tr("Property")) { + onInfoButtonClicked(); + } + + return; +} + +void WlanListItem::onEnterpriseWlanDialogClose(bool isShow) +{ + isEnterpriseWlanDialogShow = isShow; + + return; +} + +void WlanListItem::forgetPwd() +{ + if (!this->isConfigured()) { + m_pwdLineEdit->setText(""); + return; + } +} + + +void WlanListItem::setFrequency() +{ + uint freq = m_wirelessNetItem.m_frequency; + bool isMix = m_wirelessNetItem.m_isMix; + + if (isMix) { + this->m_freq->setText("2.4/5G"); + return; + } + if (freq < FREQ_5GHZ) { + this->m_freq->setText("2.4G"); + } else { + this->m_freq->setText("5G"); + } + + return; +} diff --git a/src/frontend/list-items/wlanlistitem.h b/src/frontend/list-items/wlanlistitem.h new file mode 100644 index 00000000..e61d520d --- /dev/null +++ b/src/frontend/list-items/wlanlistitem.h @@ -0,0 +1,142 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef WLANLISTITEM_H +#define WLANLISTITEM_H +#include "listitem.h" +#include "kywirelessnetitem.h" +#include "kywirelessnetresource.h" +#include "wlanpage.h" +#include "kywirelessconnectoperation.h" +#include +#include "kylinactiveconnectresource.h" +#include +#include "enterprisewlandialog.h" + +#include + +#include "kwidget.h" +#include "kpasswordedit.h" + +using namespace kdk; + +#define PSK_SETTING_NAME "802-11-wireless-security" + +#define NORMAL_HEIGHT 48 +#define EXPANDED_HEIGHT 120 +#define PWD_LENGTH_LIMIT 8 + +#define EXCELLENT_SIGNAL 80 +#define GOOD_SIGNAL 55 +#define OK_SIGNAL 30 +#define LOW_SIGNAL 5 +#define NONE_SIGNAL 0 + +#define FREQ_5GHZ 5000 + +class WlanListItem : public ListItem +{ + Q_OBJECT +public: + WlanListItem(KyWirelessNetItem &wirelessNetItem, QString device, bool isApMode, QWidget *parent = nullptr); + WlanListItem(KyWirelessNetItem &wirelessNetItem, QString device, QWidget *parent = nullptr); + WlanListItem(QWidget *parent = nullptr); + ~WlanListItem(); + +public: + QString getSsid(); + QString getUuid(); + + QString getPath(); + + void setSignalStrength(const int &signal); + int getSignalStrength(); + + bool isConfigured(); + + void setWlanState(const int &state); + void setExpanded(const bool &expanded); + + ConnectState getConnectionState(); + void updateConnectState(ConnectState state); + + void updateWirelessNetSecurity(QString ssid, QString securityType); + void updateWirelessNetItem(KyWirelessNetItem &wirelessNetItem); + + void forgetPwd(); + + void setFrequency(); + +protected: + void resizeEvent(QResizeEvent *event); + void onRightButtonClicked(); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + void keyPressEvent(QKeyEvent *event); + void paintEvent(QPaintEvent *event); + +Q_SIGNALS: + void itemHeightChanged(const bool isExpanded, const QString &ssid); + +private: + void initWlanUI(); + void refreshIcon(bool isActivated); + +private: + KyWirelessNetItem m_wirelessNetItem; + KyWirelessConnectOperation *m_wirelessConnectOperation = nullptr; + EnterpriseWlanDialog *enterpriseWlanDialog = nullptr; + KyNetworkDeviceResourse *m_deviceResource = nullptr; + + bool m_hasPwd = true; + QString m_wlanDevice; + + bool isEnterpriseWlanDialogShow = false; + + //密码输入区域的UI + QFrame *m_pwdFrame = nullptr; + QHBoxLayout *m_pwdFrameLyt = nullptr; + KPasswordEdit *m_pwdLineEdit = nullptr; + QPushButton *m_connectButton = nullptr; + + //自动连接选择区域UI + QFrame *m_autoConnectFrame = nullptr; + QHBoxLayout *m_autoConnectFrameLyt = nullptr; + QCheckBox *m_autoConnectCheckBox = nullptr; + QLabel *m_autoConnectLabel = nullptr; + + bool m_focusIsOut = true; + bool m_mouseIsOut = true; + + bool m_forgetConnection = false; + bool m_isApMode = false; + +protected Q_SLOTS: + void onInfoButtonClicked(); + +private Q_SLOTS: + void onNetButtonClicked(); + void onPwdEditorTextChanged(); + void onConnectButtonClicked(); + void onMenuTriggered(QAction *action); + void onEnterpriseWlanDialogClose(bool isShow); +}; + +#endif // WLANLISTITEM_H diff --git a/src/frontend/list-items/wlanmoreitem.cpp b/src/frontend/list-items/wlanmoreitem.cpp new file mode 100644 index 00000000..1eecc9dc --- /dev/null +++ b/src/frontend/list-items/wlanmoreitem.cpp @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wlanmoreitem.h" + +WlanMoreItem::WlanMoreItem(QWidget *parent) : ListItem(parent) +{ + setObjectName(WMI_OB_NAME); + m_netButton->setVisible(false); +// m_infoButton->setVisible(false); + m_nameLabel->setMinimumWidth(180); + m_nameLabel->setLabelText(tr("Add Others...")); +} + +WlanMoreItem::~WlanMoreItem() { + +} + +void WlanMoreItem::onNetButtonClicked() { + Q_EMIT hiddenWlanClicked(); +} + +void WlanMoreItem::onRightButtonClicked() { + // Todo +} + +void WlanMoreItem::onMenuTriggered(QAction *action) { + +} diff --git a/src/frontend/list-items/wlanmoreitem.h b/src/frontend/list-items/wlanmoreitem.h new file mode 100644 index 00000000..81218517 --- /dev/null +++ b/src/frontend/list-items/wlanmoreitem.h @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef WLANMOREITEM_H +#define WLANMOREITEM_H + +#include +#include "listitem.h" + +const QString WMI_OB_NAME = "WlanMoreItemObjName"; + +class WlanMoreItem : public ListItem +{ + Q_OBJECT + +protected: + void onRightButtonClicked(); + +public: + WlanMoreItem(QWidget *parent = nullptr); + ~WlanMoreItem(); + + void onNetButtonClicked(); + void onMenuTriggered(QAction *action); +Q_SIGNALS: + void hiddenWlanClicked(); +}; + +#endif // WLANMOREITEM_H diff --git a/src/frontend/mainwindow.cpp b/src/frontend/mainwindow.cpp new file mode 100644 index 00000000..523bbd20 --- /dev/null +++ b/src/frontend/mainwindow.cpp @@ -0,0 +1,902 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "mainwindow.h" +#include "customstyle.h" +#include +#include +#include +#include +#include +#include + +#include "kylinnetworkdeviceresource.h" +#include "../backend/dbus-interface/kylinagentinterface.h" + +#include "ukuistylehelper/ukuistylehelper.h" +#include "windowmanager/windowmanager.h" +#include "kysdk/kysdk-system/libkysysinfo.h" + +#define MAINWINDOW_WIDTH 420 +#define MAINWINDOW_HEIGHT 476 +#define LAYOUT_MARGINS 0,0,0,0 +#define LOADING_TRAYICON_TIMER_MS 60 +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" + +const QString v10Sp1 = "V10SP1"; +const QString intel = "V10SP1-edu"; + +#define LANPAGE 0 +#define WLANPAGE 1 +#define AUTOSELET 2 + +#define KEY_PRODUCT_FEATURES "PRODUCT_FEATURES" + +#include +#include + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + firstlyStart(); +} + +/** + * @brief MainWindow::showMainwindow show主窗口,同时也作为dbus接口提供给外部组件调用 + */ +void MainWindow::showMainwindow() +{ + if (!m_loadFinished) { + m_secondaryStartTimer->stop(); + secondaryStart(); + } + + /** + * 设置主界面跳过任务栏和分页器的属性,隐藏再次展示有可能辉冲刷掉该属性,需要展示时重新设置 + */ + QString platform = QGuiApplication::platformName(); + if(!platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive)) + { + const KWindowInfo info(this->winId(), NET::WMState); + if (!info.hasState(NET::SkipTaskbar) || !info.hasState(NET::SkipPager)) { + KWindowSystem::setState(this->winId(), NET::SkipTaskbar | NET::SkipPager); + } + } + + this->showByWaylandHelper(); + this->raise(); + this->activateWindow(); + Q_EMIT this->mainWindowVisibleChanged(true); +#ifdef WITHKYSEC + if (!kysec_is_disabled() && kysec_get_3adm_status() && (getuid() || geteuid())){ + if (nullptr != m_wlanWidget) { + m_wlanWidget->hideSetting(); + } + if (nullptr != m_lanWidget) { + m_lanWidget->hideSetting(); + } + } else { + if (nullptr != m_wlanWidget) { + m_wlanWidget->showSetting(); + } + if (nullptr != m_lanWidget) { + m_lanWidget->showSetting(); + } + } +#endif + +} + +/** + * @brief MainWindow::hideMainwindow 隐藏主页面时要进行的操作,后续可以添加到此函数 + */ +void MainWindow::hideMainwindow() +{ + this->hide(); + Q_EMIT this->mainWindowVisibleChanged(false); +} + +/** + * @brief MainWindow::setWiredDefaultDevice 设置有线设备默认网卡 + */ +void MainWindow::setWiredDefaultDevice(QString deviceName) +{ +// m_lanWidget->updateDefaultDevice(deviceName); +} + +/** + * @brief MainWindow::hideMainwindow 设置无线设备默认网卡 + */ +void MainWindow::setWirelessDefaultDevice(QString deviceName) +{ +// m_wlanWidget->updateDefaultDevice(deviceName); +} + +/** + * @brief MainWindow::firstlyStart 一级启动,执行重要且不耗时的启动操作 + */ +void MainWindow::firstlyStart() +{ + initWindowProperties(); + initTransparency(); + initUI(); + initDbusConnnect(); + initWindowTheme(); + initTrayIcon(); + initPlatform(); + m_secondaryStartTimer = new QTimer(this); + connect(m_secondaryStartTimer, &QTimer::timeout, this, [ = ]() { + m_secondaryStartTimer->stop(); + secondaryStart();//满足条件后执行比较耗时的二级启动 + }); + m_secondaryStartTimer->start(5 * 1000); + + m_createPagePtrMap.clear(); + + //加载key ring + agent_init(); +} + +/** + * @brief MainWindow::secondaryStart 二级启动,可以将较耗时的初始化操作放到此处执行 + */ +void MainWindow::secondaryStart() +{ + if (m_loadFinished) + return; + m_loadFinished = true; +} + +/** + * @brief MainWindow::initWindowProperties 初始化平台信息 + */ +void MainWindow::initPlatform() +{ + char* projectName = kdk_system_get_projectName(); + QString strProjectName(projectName); + free(projectName); + projectName = NULL; + if(v10Sp1.compare(strProjectName,Qt::CaseInsensitive) == 0) { + unsigned int feature = kdk_system_get_productFeatures(); + if (feature == 3) { + m_isShowInCenter = true; + } + } else if (intel.compare(strProjectName,Qt::CaseInsensitive) == 0) { + m_isShowInCenter = true; + } + qDebug() << "projectName" << projectName << m_isShowInCenter; +} + +/** + * @brief MainWindow::initWindowProperties 初始化一些窗口属性 + */ +void MainWindow::initWindowProperties() +{ + this->setWindowTitle(tr("kylin-nm")); + this->setWindowIcon(QIcon::fromTheme("kylin-network", QIcon(":/res/x/setup.png"))); + this->setFixedSize(MAINWINDOW_WIDTH, MAINWINDOW_HEIGHT); +// //绘制毛玻璃特效 + this->setAttribute(Qt::WA_TranslucentBackground, true); //透明 + this->setFocusPolicy(Qt::NoFocus); + + QString platform = QGuiApplication::platformName(); + if(!platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive)) + { + QPainterPath path; + auto rect = this->rect(); + // path.addRoundedRect(rect, 12, 12); + path.addRect(rect); + KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); //背景模糊 + } +} + +void MainWindow::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; + painter.setPen(Qt::transparent); +// auto rect = this->rect(); +// painter.drawRoundedRect(rect, 12, 12); //窗口圆角 +} + +void MainWindow::initTransparency() +{ + if(QGSettings::isSchemaInstalled(TRANSPARENCY_GSETTINGS)) { + m_transGsettings = new QGSettings(TRANSPARENCY_GSETTINGS); + if(m_transGsettings->keys().contains(QString("transparency"))) { + m_transparency=m_transGsettings->get("transparency").toDouble() + 0.15; + m_transparency = (m_transparency > 1) ? 1 : m_transparency; + connect(m_transGsettings, &QGSettings::changed, this, &MainWindow::onTransChanged); + } + } +} + +void MainWindow::onTransChanged() +{ + m_transparency = m_transGsettings->get("transparency").toDouble() + 0.15; + m_transparency = (m_transparency > 1) ? 1 : m_transparency; + paintWithTrans(); +} + +void MainWindow::paintWithTrans() +{ + QPalette pal = m_centralWidget->palette(); + QColor color = qApp->palette().base().color(); + color.setAlphaF(m_transparency); + pal.setColor(QPalette::Base, color); + m_centralWidget->setPalette(pal); + + QPalette tabPal = m_centralWidget->tabBar()->palette(); + tabPal.setColor(QPalette::Base, color); + + QColor inactiveColor = qApp->palette().window().color(); + inactiveColor.setAlphaF(0.86 *m_transparency); + tabPal.setColor(QPalette::Window, inactiveColor); + + m_centralWidget->tabBar()->setPalette(tabPal); +} + +/** + * @brief MainWindow::initUI 初始化窗口内控件 + */ +void MainWindow::initUI() +{ + m_centralWidget = new QTabWidget(this); + this->setCentralWidget(m_centralWidget); + m_centralWidget->tabBar()->setFixedWidth(this->width()+1); + m_centralWidget->tabBar()->setProperty("setRadius", 12); +// m_centralWidget->tabBar()->setStyleSheet("QTabBar::tab{min-height:40px}"); + m_lanWidget = new LanPage(m_centralWidget); + m_wlanWidget = new WlanPage(m_centralWidget); + connect(this, &MainWindow::mainWindowVisibleChanged, m_wlanWidget, &WlanPage::onMainWindowVisibleChanged); +// m_centralWidget->addTab(m_lanWidget, QIcon::fromTheme("network-wired-connected-symbolic", QIcon::fromTheme("network-wired-symbolic", QIcon(":/res/l/network-online.svg"))), tr("LAN")); +// m_centralWidget->addTab(m_wlanWidget, QIcon::fromTheme("network-wireless-signal-excellent-symbolic", QIcon(":/res/x/wifi-list-bg.svg")), tr("WLAN")); + + m_centralWidget->addTab(m_lanWidget, tr("")); + m_centralWidget->addTab(m_wlanWidget,tr("")); + m_tabBarLayout = new QHBoxLayout(this); + m_tabBarLayout->setContentsMargins(LAYOUT_MARGINS); + m_lanLabel = new QLabel(tr("LAN")); + m_lanLabel->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); + m_wlanLabel = new QLabel(tr("WLAN")); + m_wlanLabel->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter); + m_tabBarLayout->addWidget(m_lanLabel); + m_tabBarLayout->addWidget(m_wlanLabel); + m_centralWidget->tabBar()->setLayout(m_tabBarLayout); + m_centralWidget->tabBar()->setProperty("useTabbarSeparateLine", false); // 去掉中间的分割线 + m_centralWidget->setAttribute(Qt::WA_TranslucentBackground, true); // 背景透明 解决切换黑屏问题 + connect(m_centralWidget, &QTabWidget::currentChanged, m_wlanWidget, &WlanPage::onWlanPageVisibleChanged); + paintWithTrans(); +} + +/** + * @brief MainWindow::initTrayIcon 初始化托盘图标和托盘右键菜单 + */ +void MainWindow::initTrayIcon() +{ + loadIcons.append(QIcon::fromTheme("ukui-loading-0-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic")); + loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic")); + iconTimer = new QTimer(this); + connect(iconTimer, &QTimer::timeout, this, &MainWindow::onSetTrayIconLoading); + + m_trayIcon = new QSystemTrayIcon(); + m_trayIconMenu = new QMenu(); + m_showMainwindowAction = new QAction(tr("Show MainWindow"),this); + m_showSettingsAction = new QAction(tr("Settings"),this); + + m_trayIcon->setToolTip(QString(tr("Network tool"))); + m_showSettingsAction->setIcon(QIcon::fromTheme("document-page-setup-symbolic", QIcon(":/res/x/setup.png")) ); +// m_trayIconMenu->addAction(m_showMainwindowAction); + m_trayIconMenu->addAction(m_showSettingsAction); + m_trayIcon->setContextMenu(m_trayIconMenu); + m_trayIcon->setIcon(QIcon::fromTheme("network-wired-signal-excellent-symbolic")); + iconStatus = IconActiveType::LAN_CONNECTED; + onRefreshTrayIcon(); + + connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::onTrayIconActivated); +// connect(m_showMainwindowAction, &QAction::triggered, this, &MainWindow::onShowMainwindowActionTriggled); + connect(m_showSettingsAction, &QAction::triggered, this, &MainWindow::onShowSettingsActionTriggled); + m_trayIcon->show(); +} + +void MainWindow::initDbusConnnect() +{ + connect(m_lanWidget, &LanPage::deviceStatusChanged, this, &MainWindow::deviceStatusChanged); + connect(m_lanWidget, &LanPage::deviceNameChanged, this, &MainWindow::deviceNameChanged); + connect(m_wlanWidget, &WlanPage::deviceStatusChanged, this, &MainWindow::deviceStatusChanged); + connect(m_wlanWidget, &WlanPage::deviceNameChanged, this, &MainWindow::deviceNameChanged); + connect(m_wlanWidget, &WlanPage::wirelessSwitchBtnChanged, this, &MainWindow::wirelessSwitchBtnChanged); + + connect(m_wlanWidget, &WlanPage::activateFailed, this, &MainWindow::activateFailed); + connect(m_wlanWidget, &WlanPage::deactivateFailed, this, &MainWindow::deactivateFailed); + connect(m_lanWidget, &LanPage::activateFailed, this, &MainWindow::activateFailed); + connect(m_lanWidget, &LanPage::deactivateFailed, this, &MainWindow::deactivateFailed); + + connect(m_lanWidget, &LanPage::lanAdd, this, &MainWindow::lanAdd); + connect(m_lanWidget, &LanPage::lanRemove, this, &MainWindow::lanRemove); + connect(m_lanWidget, &LanPage::lanUpdate, this, &MainWindow::lanUpdate); + connect(m_lanWidget, &LanPage::lanActiveConnectionStateChanged, this, &MainWindow::lanActiveConnectionStateChanged); + connect(m_lanWidget, &LanPage::lanConnectChanged, this, &MainWindow::onLanConnectStatusToChangeTrayIcon); + + + connect(m_wlanWidget, &WlanPage::wlanAdd, this, &MainWindow::wlanAdd); + connect(m_wlanWidget, &WlanPage::wlanRemove, this, &MainWindow::wlanRemove); + connect(m_wlanWidget, &WlanPage::wlanActiveConnectionStateChanged, this, &MainWindow::wlanactiveConnectionStateChanged); + connect(m_wlanWidget, &WlanPage::wlanConnectChanged, this, &MainWindow::onWlanConnectStatusToChangeTrayIcon); + connect(m_wlanWidget, &WlanPage::hotspotDeactivated, this, &MainWindow::hotspotDeactivated); + connect(m_wlanWidget, &WlanPage::hotspotActivated, this, &MainWindow::hotspotActivated); + connect(m_wlanWidget, &WlanPage::secuTypeChange, this, &MainWindow::secuTypeChange); + connect(m_wlanWidget, &WlanPage::signalStrengthChange, this, &MainWindow::signalStrengthChange); + connect(m_wlanWidget, &WlanPage::timeToUpdate , this, &MainWindow::timeToUpdate); + connect(m_wlanWidget, &WlanPage::showMainWindow, this, &MainWindow::onShowMainWindow); + connect(m_wlanWidget, &WlanPage::connectivityChanged, this, &MainWindow::onConnectivityChanged); + + //模式切换 + QDBusConnection::sessionBus().connect(QString("com.kylin.statusmanager.interfacer"), + QString("/"), + QString("com.kylin.statusmanager.interface"), + QString("mode_change_signal"), this, SLOT(onTabletModeChanged(bool))); + + connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this,[&](WId activeWindowId){ + if (activeWindowId != this->winId() && activeWindowId != 0) { + hideMainwindow(); + } + }); + +} + +/** + * @brief MainWindow::resetWindowPosition 重新计算窗口位置 + */ +void MainWindow::resetWindowPosition() +{ + + if (m_isShowInCenter) { + QRect availableGeometry = qApp->primaryScreen()->availableGeometry(); + QRect rect((availableGeometry.width() - this->width())/2, (availableGeometry.height() - this->height())/2, + this->width(), this->height()); + kdk::WindowManager::setGeometry(this->windowHandle(), rect); + + return; + } + +#define MARGIN 8 +#define PANEL_TOP 1 +#define PANEL_LEFT 2 +#define PANEL_RIGHT 3 +//#define PANEL_BOTTOM 4 + if (!m_positionInterface) { + m_positionInterface = new QDBusInterface("org.ukui.panel", + "/panel/position", + "org.ukui.panel", + QDBusConnection::sessionBus()); + } + QRect rect; + QDBusReply reply = m_positionInterface->call("GetPrimaryScreenGeometry"); + //reply获取的参数共5个,分别是 主屏可用区域的起点x坐标,主屏可用区域的起点y坐标,主屏可用区域的宽度,主屏可用区域高度,任务栏位置 + if (!m_positionInterface->isValid() || !reply.isValid() || reply.value().size() < 5) { + qCritical() << QDBusConnection::sessionBus().lastError().message(); + kdk::WindowManager::setGeometry(this->windowHandle(), QRect(0, 0, this->width(), this->height())); + return; + } + QVariantList position_list = reply.value(); + int position = position_list.at(4).toInt(); + switch(position){ + case PANEL_TOP: + //任务栏位于上方 + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + MARGIN, + this->width(), this->height()); + break; + //任务栏位于左边 + case PANEL_LEFT: + rect = QRect(position_list.at(0).toInt() + MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + //任务栏位于右边 + case PANEL_RIGHT: + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + //任务栏位于下方 + default: + rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN, + position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN, + this->width(), this->height()); + break; + } + kdk::WindowManager::setGeometry(this->windowHandle(), rect); + qDebug() << " Position of ukui-panel is " << position << "; Position of mainwindow is " << this->geometry() << "." << Q_FUNC_INFO << __LINE__; +} + +/** + * @brief MainWindow::resetTrayIconTool 重新获取网络连接状态并重新设置图标和tooltip + */ +void MainWindow::resetTrayIconTool() +{ + //ZJP_TODO 检测当前连接的是有线还是无线,是否可用,设置图标和tooltip,图标最好提前define +// int connectivity = objKyDBus->getNetworkConectivity(); +// qDebug() << "Value of current network Connectivity property : "<< connectivity; +// switch (connectivity) { +// case UnknownConnectivity: +// case Portal: +// case Limited: +// setTrayIcon(iconLanOnlineNoInternet); +// trayIcon->setToolTip(QString(tr("Network Connected But Can Not Access Internet"))); +// break; +// case NoConnectivity: +// case Full: +// setTrayIcon(iconLanOnline); +// trayIcon->setToolTip(QString(tr("kylin-nm"))); +// break; +// } + qDebug() << "Has set tray icon to be XXX." << Q_FUNC_INFO << __LINE__; +} + + +/** + * @brief MainWindow::initWindowTheme 初始化窗口主题并创建信号槽 + */ +void MainWindow::initWindowTheme() +{ + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + m_styleGsettings = new QGSettings(style_id); +// resetWindowTheme(); + connect(m_styleGsettings, &QGSettings::changed, this, &MainWindow::onThemeChanged); + } else { + qWarning() << "Gsettings interface \"org.ukui.style\" is not exist!" << Q_FUNC_INFO << __LINE__; + } +} + +/** + * @brief MainWindow::resetWindowTheme 读取和设置窗口主题 + */ +void MainWindow::resetWindowTheme() +{ + if (!m_styleGsettings) { return; } + QString currentTheme = m_styleGsettings->get(COLOR_THEME).toString(); + auto app = static_cast(QCoreApplication::instance()); + if(currentTheme == "ukui-dark" || currentTheme == "ukui-black"){ + app->setStyle(new CustomStyle("ukui-dark")); + qDebug() << "Has set color theme to ukui-dark." << Q_FUNC_INFO << __LINE__; + Q_EMIT qApp->paletteChanged(qApp->palette()); + return; + } + app->setStyle(new CustomStyle("ukui-light")); + qDebug() << "Has set color theme to " << currentTheme << Q_FUNC_INFO << __LINE__; + Q_EMIT qApp->paletteChanged(qApp->palette()); + return; +} + +/** + * @brief MainWindow::showControlCenter 打开控制面板网络界面 + */ +void MainWindow::showControlCenter() +{ + QProcess process; + if (!m_lanWidget->lanIsConnected() && m_wlanWidget->checkWlanStatus(NetworkManager::ActiveConnection::State::Activated)){ + process.startDetached("ukui-control-center -m wlanconnect"); + } else { + process.startDetached("ukui-control-center -m netconnect"); + } +} + +void MainWindow::showByWaylandHelper() +{ + //去除窗管标题栏,传入参数为QWidget* + kdk::UkuiStyleHelper::self()->removeHeader(this); + this->show(); + resetWindowPosition(); + //设置窗体位置,传入参数为QWindow*,QRect + +} + +void MainWindow::setCentralWidgetType(IconActiveType iconStatus) +{ + if (iconStatus == WLAN_CONNECTED || iconStatus == WLAN_CONNECTED_LIMITED) { + m_centralWidget->setCurrentIndex(WLAN_PAGE_INDEX); + } else if (iconStatus == ACTIVATING) { + if (m_wlanWidget->checkWlanStatus(NetworkManager::ActiveConnection::State::Activating)) { + m_centralWidget->setCurrentIndex(WLAN_PAGE_INDEX); + } else { + m_centralWidget->setCurrentIndex(LAN_PAGE_INDEX); + } + } else { + m_centralWidget->setCurrentIndex(LAN_PAGE_INDEX); + } +} + +/** + * @brief MainWindow::onTrayIconActivated 点击托盘图标的槽函数 + */ +void MainWindow::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason) +{ + setCentralWidgetType(iconStatus); + if (reason == QSystemTrayIcon::ActivationReason::Context) { + m_trayIconMenu->popup(QCursor::pos()); + } else { + if (this->isVisible()) { + qDebug() << "Received signal of tray icon activated, will hide mainwindow." << Q_FUNC_INFO << __LINE__; + hideMainwindow(); + return; + } + qDebug() << "Received signal of tray icon activated, will show mainwindow." << Q_FUNC_INFO << __LINE__; + this->showMainwindow(); + } +} + +void MainWindow::onShowMainwindowActionTriggled() +{ + showMainwindow(); +} + +void MainWindow::onShowSettingsActionTriggled() +{ + showControlCenter(); +} + +void MainWindow::onThemeChanged(const QString &key) +{ + if (key == COLOR_THEME) { + qDebug() << "Received signal of theme changed, will reset theme." << Q_FUNC_INFO << __LINE__; +// resetWindowTheme(); + paintWithTrans(); + Q_EMIT qApp->paletteChanged(qApp->palette()); + } else { + qDebug() << "Received signal of theme changed, key=" << key << " will do nothing." << Q_FUNC_INFO << __LINE__; + } +} + +void MainWindow::onRefreshTrayIcon() +{ + //更新托盘图标显示 + iconTimer->stop(); + if (m_lanWidget->lanIsConnected()) { + m_trayIcon->setIcon(QIcon::fromTheme("network-wired-connected-symbolic")); + iconStatus = IconActiveType::LAN_CONNECTED; + } else if (m_wlanWidget->checkWlanStatus(NetworkManager::ActiveConnection::State::Activated)){ + m_trayIcon->setIcon(QIcon::fromTheme("network-wireless-connected-symbolic")); + iconStatus = IconActiveType::WLAN_CONNECTED; + } else { + m_trayIcon->setIcon(QIcon::fromTheme("network-wired-disconnected-symbolic")); + iconStatus = IconActiveType::NOT_CONNECTED; + } + + NetworkManager::Connectivity connecttivity; + m_wlanWidget->getConnectivity(connecttivity); + if (connecttivity != NetworkManager::Connectivity::Full) { + if (iconStatus == IconActiveType::LAN_CONNECTED) { + m_trayIcon->setIcon(QIcon::fromTheme("network-error-symbolic")); + iconStatus = IconActiveType::LAN_CONNECTED_LIMITED; + } else if (iconStatus == IconActiveType::WLAN_CONNECTED) { + //todo 信号强度 + m_trayIcon->setIcon(QIcon::fromTheme("network-wireless-signal-excellent-error-symbolic")); + iconStatus = IconActiveType::WLAN_CONNECTED_LIMITED; + } + } +} + +void MainWindow::onSetTrayIconLoading() +{ + if (currentIconIndex > 7) { + currentIconIndex = 0; + } + m_trayIcon->setIcon(loadIcons.at(currentIconIndex)); + iconStatus = IconActiveType::ACTIVATING; + currentIconIndex ++; +} + +void MainWindow::onLanConnectStatusToChangeTrayIcon(int state) +{ + qDebug() << "lan state:" << state << Q_FUNC_INFO << __LINE__; + if (state==1 || state==3){ + m_lanIsLoading = true; + iconTimer->start(LOADING_TRAYICON_TIMER_MS); + } else { + m_lanIsLoading = false; + if (m_wlanIsLoading == false) { + onRefreshTrayIcon(); + } + } +} + +void MainWindow::onWlanConnectStatusToChangeTrayIcon(int state) +{ + qDebug() << "wlan state:" << state << Q_FUNC_INFO << __LINE__; + if (state==1 || state==3){ + m_wlanIsLoading = true; + iconTimer->start(LOADING_TRAYICON_TIMER_MS); + } else { + if (m_wlanWidget->checkWlanStatus(NetworkManager::ActiveConnection::State::Activating)) { + return; + } + m_wlanIsLoading = false; + if (m_lanIsLoading == false) { + onRefreshTrayIcon(); + } + } +} + +void MainWindow::onTabletModeChanged(bool mode) +{ + qDebug() << "TabletMode change" << mode; + Q_UNUSED(mode) + //模式切换时,隐藏主界面 + hideMainwindow(); +} + +void MainWindow::onShowMainWindow(int type) +{ + if (type == LANPAGE || type == WLANPAGE) { + m_centralWidget->setCurrentIndex(type); + + if(QApplication::activeWindow() != this) { + this->showMainwindow(); + } + } else if (type == AUTOSELET) { + onTrayIconActivated(QSystemTrayIcon::ActivationReason::Trigger); + } else { + qWarning() << "unsupport parameter"; + } +} + +void MainWindow::onConnectivityChanged(NetworkManager::Connectivity connectivity) +{ + if (!m_trayIcon) { + return; + } + + if (iconStatus == ACTIVATING) { + return; + } + + onRefreshTrayIcon(); +} + +/** + * @brief MainWindow::keyPressEvent 按esc键关闭主界面 + * @param event + */ +void MainWindow::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape) { + hideMainwindow(); + } + return QWidget::keyPressEvent(event); +} + +/** + * @brief MainWindow::getWirelessList 获取wifi列表,供dbus调用 + * @param map + */ +void MainWindow::getWirelessList(QMap > &map) +{ + map.clear(); + if (nullptr != m_wlanWidget) { + m_wlanWidget->getWirelessList(map); + } +} + +bool MainWindow::getWirelessSwitchBtnState() +{ + if (nullptr != m_wlanWidget) { + return m_wlanWidget->getWirelessSwitchBtnState(); + } +} + +/** + * @brief MainWindow::getWiredList 获取lan列表,供dbus调用 + * @param map + */ +void MainWindow::getWiredList(QMap> &map) +{ + map.clear(); + if (nullptr != m_lanWidget) { + m_lanWidget->getWiredList(map); + } +} + +/** + * @brief MainWindow::activeWirelessAp 开启热点,供dbus调用 + * @param apName + * @param apPassword + * @param apDevice + */ +void MainWindow::activeWirelessAp(const QString apName, const QString apPassword, const QString band, const QString apDevice) +{ + m_wlanWidget->activeWirelessAp(apName, apPassword, band, apDevice); +} + +/** + * @brief MainWindow::activeWirelessAp 断开热点,供dbus调用 + * @param apName + */ +void MainWindow::deactiveWirelessAp(const QString apName, const QString uuid) +{ + m_wlanWidget->deactiveWirelessAp(apName, uuid); +} + +/** + * @brief MainWindow::activeWirelessAp 获取热点,供dbus调用 + * @param list + */ +void MainWindow::getApInfoBySsid(QString devName, QString ssid, QStringList &list) +{ + m_wlanWidget->getApInfoBySsid(devName, ssid, list); +} + +void MainWindow::getStoredApInfo(QStringList &list) +{ + m_wlanWidget->getStoredApInfo(list); +} + +void MainWindow::getApConnectionPath(QString &path, QString uuid) +{ + m_wlanWidget->getApConnectionPath(path, uuid); +} + +void MainWindow::getActiveConnectionPath(QString &path, QString uuid) +{ + m_wlanWidget->getActiveConnectionPath(path, uuid); +} + +//无线开关 +void MainWindow::setWirelessSwitchEnable(bool enable) +{ + m_wlanWidget->setWirelessSwitchEnable(enable); +} + +void MainWindow::setWiredDeviceEnable(const QString& devName, bool enable) +{ + m_lanWidget->setWiredDeviceEnable(devName, enable); +} +void MainWindow::showPropertyWidget(QString devName, QString ssid) +{ + KyNetworkDeviceResourse *devResourse = new KyNetworkDeviceResourse(); + QStringList wiredDeviceList; + wiredDeviceList.clear(); + devResourse->getNetworkDeviceList(NetworkManager::Device::Type::Ethernet, wiredDeviceList); + if (wiredDeviceList.contains(devName)) { + qDebug() << "showPropertyWidget device type wired device name " << devName << " uuid " << ssid; + m_lanWidget->showDetailPage(devName, ssid); + delete devResourse; + devResourse = nullptr; + return; + } + + QStringList wirelessDeviceList; + wirelessDeviceList.clear(); + devResourse->getNetworkDeviceList(NetworkManager::Device::Type::Wifi, wirelessDeviceList); + if (wirelessDeviceList.contains(devName)) { + qDebug() << "showPropertyWidget device type wireless device name " << devName << " ssid " << ssid; + m_wlanWidget->showDetailPage(devName, ssid); + delete devResourse; + devResourse = nullptr; + return; + } + + qWarning() << "showPropertyWidget no such device " << devName; + delete devResourse; + devResourse = nullptr; +} + +void MainWindow::showCreateWiredConnectWidget(const QString devName) +{ + qDebug() << "showCreateWiredConnectWidget! devName = " << devName; + if (m_createPagePtrMap.contains(devName)) { + if (m_createPagePtrMap[devName] != nullptr) { + qDebug() << "showCreateWiredConnectWidget" << devName << "already create,just raise"; + + KWindowSystem::raiseWindow(m_createPagePtrMap[devName]->winId()); + return; + } + } + NetDetail *netDetail = new NetDetail(devName, "", "", false, false, true, this); + connect(netDetail, &NetDetail::createPageClose, [&](QString interfaceName){ + if (m_createPagePtrMap.contains(interfaceName)) { + m_createPagePtrMap[interfaceName] = nullptr; + } + }); + m_createPagePtrMap.insert(devName, netDetail); + netDetail->show(); +} + +void MainWindow::showAddOtherWlanWidget(QString devName) +{ + qDebug() << "showAddOtherWlanWidget! devName = " << devName; + if (m_addOtherPagePtrMap.contains(devName)) { + if (m_addOtherPagePtrMap[devName] != nullptr) { + qDebug() << "showAddOtherWlanWidget" << devName << "already create,just raise"; + + KWindowSystem::raiseWindow(m_addOtherPagePtrMap[devName]->winId()); + return; + } + } + +#if 0 + NetDetail *netDetail = new NetDetail(devName, "", "", false, true, true, this); + connect(netDetail, &NetDetail::createPageClose, [&](QString interfaceName){ + if (m_addOtherPagePtrMap.contains(interfaceName)) { + m_addOtherPagePtrMap[interfaceName] = nullptr; + } + }); + m_addOtherPagePtrMap.insert(devName, netDetail); + netDetail->show(); +#endif + + JoinHiddenWiFiPage *hiddenWiFi =new JoinHiddenWiFiPage(devName); + connect(hiddenWiFi, &JoinHiddenWiFiPage::hiddenWiFiPageClose, [&](QString interfaceName){ + if (m_addOtherPagePtrMap.contains(interfaceName)) { + m_addOtherPagePtrMap[interfaceName] = nullptr; + } + }); + m_addOtherPagePtrMap.insert(devName, hiddenWiFi); + connect(hiddenWiFi, &JoinHiddenWiFiPage::showWlanList, this, &MainWindow::onShowMainWindow); + hiddenWiFi->show(); +} + +void MainWindow::getWirelessDeviceCap(QMap &map) +{ + m_wlanWidget->getWirelessDeviceCap(map); +} + +//有线连接断开 +void MainWindow::activateWired(const QString& devName, const QString& connUuid) +{ + m_lanWidget->activateWired(devName, connUuid); +} +void MainWindow::deactivateWired(const QString& devName, const QString& connUuid) +{ + m_lanWidget->deactivateWired(devName, connUuid); +} + +//无线连接断开 +void MainWindow::activateWireless(const QString& devName, const QString& ssid) +{ + m_wlanWidget->activateWirelessConnection(devName, ssid); +} + +void MainWindow::deactivateWireless(const QString& devName, const QString& ssid) +{ + m_wlanWidget->deactivateWirelessConnection(devName, ssid); +} + +void MainWindow::rescan() +{ + m_wlanWidget->requestScan(); +} + +void MainWindow::keyRingInit() +{ + agent_init(); +} + +void MainWindow::keyRingClear() +{ + agent_clear(); +} diff --git a/src/frontend/mainwindow.h b/src/frontend/mainwindow.h new file mode 100644 index 00000000..6a32ba17 --- /dev/null +++ b/src/frontend/mainwindow.h @@ -0,0 +1,217 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lanpage.h" +#include "wlanpage.h" +#include "netdetails/netdetail.h" +#include "netdetails/joinhiddenwifipage.h" +//删除此头文件,别在添加 +//#include + +#ifdef WITHKYSEC +#include +#include +#endif + +enum IconActiveType { + NOT_CONNECTED = 0, + LAN_CONNECTED, + WLAN_CONNECTED, + LAN_CONNECTED_LIMITED, + WLAN_CONNECTED_LIMITED, + ACTIVATING, +}; + +const QByteArray TRANSPARENCY_GSETTINGS = "org.ukui.control-center.personalise"; + +class LanPage; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = nullptr); + void showMainwindow(); + void hideMainwindow(); + + void setWiredDefaultDevice(QString deviceName); + void setWirelessDefaultDevice(QString deviceName); + + //for dbus + void getWirelessList(QMap > &map); + void getWiredList(QMap> &map); + //开启热点 + void activeWirelessAp(const QString apName, const QString apPassword, const QString wirelessBand, const QString apDevice); + //断开热点 + void deactiveWirelessAp(const QString apName, const QString uuid); + //获取热点 + void getStoredApInfo(QStringList &list); + void getApInfoBySsid(QString devName, QString ssid, QStringList &list); + + //获取热点path + void getApConnectionPath(QString &path, QString uuid); + //获取热点ActivePath + void getActiveConnectionPath(QString &path, QString uuid); + //有线连接断开 + void activateWired(const QString& devName, const QString& connUuid); + void deactivateWired(const QString& devName, const QString& connUuid); + //无线连接断开 + void activateWireless(const QString& devName, const QString& ssid); + void deactivateWireless(const QString& devName, const QString& ssid); + //无线总开关 + void setWirelessSwitchEnable(bool enable); + + void setWiredDeviceEnable(const QString& devName, bool enable); + + //唤起属性页 根据网卡类型 参数2 为ssid/uuid + void showPropertyWidget(QString devName, QString ssid); + //唤起新建有线连接界面 + void showCreateWiredConnectWidget(const QString devName); + //唤起加入其他无线网络界面 + void showAddOtherWlanWidget(QString devName); + + void getWirelessDeviceCap(QMap &map); + + void rescan(); + + void keyRingInit(); + void keyRingClear(); + + bool getWirelessSwitchBtnState(); + +Q_SIGNALS: + //设备插拔 + void deviceStatusChanged(); + //设备名称变化 + void deviceNameChanged(QString oldName, QString newName, int type); + void wirelessSwitchBtnChanged(bool state); + //有线无线列表更新(有线增删、无线增加减少) + void lanAdd(QString devName, QStringList info); + void lanRemove(QString dbusPath); + void lanUpdate(QString devName, QStringList info); + void wlanAdd(QString devName, QStringList info); + void wlanRemove(QString devName,QString ssid); + void wlanactiveConnectionStateChanged(QString devName, QString ssid, QString uuid, int status); + void lanActiveConnectionStateChanged(QString devName, QString uuid, int status); + void activateFailed(QString errorMessage); + void deactivateFailed(QString errorMessage); + //热点断开 + void hotspotDeactivated(QString devName, QString ssid); + void hotspotActivated(QString devName, QString ssid, QString uuid, QString activePath, QString settingPath); + //信号强度变化 + void signalStrengthChange(QString devName, QString ssid, int strength); + //安全性变化 + void secuTypeChange(QString devName, QString ssid, QString secuType); + void mainWindowVisibleChanged(const bool &visible); + //列表排序 + void timeToUpdate(); +public Q_SLOTS: + +protected: + void keyPressEvent(QKeyEvent *event); + void paintEvent(QPaintEvent *event); + +private: + void firstlyStart(); //一级启动 + void secondaryStart(); //二级启动 + bool m_loadFinished = false; //是否二级启动已执行完 + QTimer * m_secondaryStartTimer = nullptr; //执行二级启动的倒计时 + void initPlatform(); + void initWindowProperties(); + void initTransparency(); + void paintWithTrans(); + void initUI(); + void initDbusConnnect(); + void initTrayIcon(); + void resetTrayIconTool(); + void initWindowTheme(); + void resetWindowTheme(); + void showControlCenter(); + void showByWaylandHelper(); + void setCentralWidgetType(IconActiveType iconStatus); + double m_transparency=1.0; //透明度 + QGSettings * m_transGsettings; //透明度配置文件 + int currentIconIndex=0; + QList loadIcons; + QTimer *iconTimer = nullptr; + + //主窗口的主要构成控件 + QTabWidget * m_centralWidget = nullptr; + QHBoxLayout * m_tabBarLayout = nullptr; + QLabel * m_lanLabel = nullptr; + QLabel * m_wlanLabel = nullptr; + + LanPage * m_lanWidget = nullptr; + WlanPage * m_wlanWidget = nullptr; + + //监听主题的Gsettings + QGSettings * m_styleGsettings = nullptr; + + //获取和重置窗口位置 + void resetWindowPosition(); + QDBusInterface * m_positionInterface = nullptr; + + //托盘图标,托盘图标右键菜单 + QSystemTrayIcon * m_trayIcon = nullptr; + QMenu * m_trayIconMenu = nullptr; + QAction * m_showMainwindowAction = nullptr; + QAction * m_showSettingsAction = nullptr; + + bool m_lanIsLoading = false; + bool m_wlanIsLoading = false; + + bool m_isShowInCenter = false; + + IconActiveType iconStatus = IconActiveType::NOT_CONNECTED; + + QMap m_createPagePtrMap; +// QMap m_addOtherPagePtrMap; + QMap m_addOtherPagePtrMap; + +public Q_SLOTS: + void onShowMainWindow(int type); + +private Q_SLOTS: + void onTransChanged(); + void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason); + void onShowMainwindowActionTriggled(); + void onShowSettingsActionTriggled(); + void onThemeChanged(const QString &key); + void onRefreshTrayIcon(); + void onSetTrayIconLoading(); + void onLanConnectStatusToChangeTrayIcon(int state); + void onWlanConnectStatusToChangeTrayIcon(int state); + void onConnectivityChanged(NetworkManager::Connectivity connectivity); + void onTabletModeChanged(bool mode); +}; + +#endif // MAINWINDOW_H diff --git a/src/frontend/netdetails/configpage.cpp b/src/frontend/netdetails/configpage.cpp new file mode 100644 index 00000000..0218480a --- /dev/null +++ b/src/frontend/netdetails/configpage.cpp @@ -0,0 +1,124 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "configpage.h" + +#include + +#define VERTICAL_SPACING 24 +#define KSC_FIREWALL_PUBLIC 0 +#define KSC_FIREWALL_PRIVATE 1 + +ConfigPage::ConfigPage(QWidget *parent) +{ + initUi(); + initComponent(); +} + +void ConfigPage::initUi() +{ + m_descriptionLabel = new QLabel(this); + m_publicButton = new QRadioButton(this); + m_privateButton = new QRadioButton(this); + m_publicLabel = new QLabel(this); + m_privateLabel = new QLabel(this); + m_congigBtn = new KBorderlessButton(this); + + QWidget *centerWidget = new QWidget(this); + QGridLayout *gridLayout = new QGridLayout(centerWidget); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->setVerticalSpacing(VERTICAL_SPACING); + gridLayout->addWidget(m_publicButton, 0, 0, Qt::AlignTop); + gridLayout->addWidget(m_publicLabel, 0, 1); + gridLayout->addWidget(m_privateButton, 1, 0, Qt::AlignTop); + gridLayout->addWidget(m_privateLabel, 1, 1); + + m_vBoxLayout = new QVBoxLayout(this); + m_vBoxLayout->setContentsMargins(0, 0, 0, 0); + m_vBoxLayout->setSpacing(VERTICAL_SPACING); + m_vBoxLayout->addWidget(m_descriptionLabel); + m_vBoxLayout->addWidget(centerWidget); + m_vBoxLayout->addWidget(m_congigBtn); + m_vBoxLayout->addStretch(); + + //网络配置文件类型 + m_descriptionLabel->setText(tr("Network profile type")); + m_descriptionLabel->setAlignment(Qt::AlignLeft); + //公用(推荐) 网络中的设备不可发现此电脑。一般情况下适用于公共场所中的网络,如机场或咖啡店等等。 + m_publicLabel->setText(tr("Public(recommended) Devices on the network cannot discover this computer. Generally, " + "it is suitable for networks in public places, such as airports or coffee shops, etc.")); + m_publicLabel->setWordWrap(true); + //专用 网络中的设备可发现此电脑。一般情况下适用于家庭或工作单位的网络,您认识并信任网络上的个人和设备。 + m_privateLabel->setText(tr("Devices on the network can discover this computer. Generally applicable to a network " + "at home or work where you know and trust the individuals and devices on the network.")); + m_privateLabel->setWordWrap(true); + //配置防火墙和安全设置 + m_congigBtn->setText(tr("Config firewall and security settings")); + + QPalette btnPal; + QColor btnColor = palette().highlight().color(); + btnPal.setColor(QPalette::ButtonText, btnColor); + m_congigBtn->setPalette(btnPal); +} + +void ConfigPage::initComponent() +{ + connect(m_congigBtn, &KBorderlessButton::clicked, this, &ConfigPage::onConfigButtonClicked); +} + +void ConfigPage::setConfigState(int type) +{ + if (type == KSC_FIREWALL_PUBLIC) { + m_publicButton->setChecked(true); + + } else if (type == KSC_FIREWALL_PRIVATE) { + m_privateButton->setChecked(true); + } + +} + +bool ConfigPage::checkIsChanged(int type) +{ + if (type == KSC_FIREWALL_PUBLIC && m_publicButton->isChecked()) { + return false; + } else if (type == KSC_FIREWALL_PRIVATE && m_privateButton->isChecked()) { + return false; + } else { + return true; + } +} + +int ConfigPage::getConfigState() +{ + if (m_publicButton->isChecked()) { + return KSC_FIREWALL_PUBLIC; + } else if (m_privateButton->isChecked()) { + return KSC_FIREWALL_PRIVATE; + } +} + + +void ConfigPage::onConfigButtonClicked() +{ + qDebug() << "show ksc defender net protect"; + + QProcess process; + process.startDetached("/usr/sbin/ksc-defender --net-protect"); + +} diff --git a/src/frontend/netdetails/configpage.h b/src/frontend/netdetails/configpage.h new file mode 100644 index 00000000..bc35baa2 --- /dev/null +++ b/src/frontend/netdetails/configpage.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CONFIGPAGE_H +#define CONFIGPAGE_H + +#include +#include +#include +#include +#include +#include + +#include "kwidget.h" +#include "kborderlessbutton.h" + +using namespace kdk; + +class ConfigPage : public QFrame +{ + Q_OBJECT +public: + ConfigPage(QWidget *parent = nullptr); + ~ConfigPage() = default; + + void setConfigState(int type); + bool checkIsChanged(int type); + int getConfigState(); + +private: + void initUi(); + void initComponent(); + + QLabel *m_descriptionLabel = nullptr; + QRadioButton *m_publicButton = nullptr; + QRadioButton *m_privateButton = nullptr; + QLabel *m_publicLabel = nullptr; + QLabel *m_privateLabel = nullptr; + KBorderlessButton *m_congigBtn = nullptr; + QVBoxLayout *m_vBoxLayout = nullptr; + +private Q_SLOTS: + void onConfigButtonClicked(); + +Q_SIGNALS: + void publicConfig(); + void privateConfig(); +}; + +#endif // CONFIGPAGE_H diff --git a/src/frontend/netdetails/coninfo.h b/src/frontend/netdetails/coninfo.h new file mode 100644 index 00000000..1aef5fb4 --- /dev/null +++ b/src/frontend/netdetails/coninfo.h @@ -0,0 +1,264 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CONINFO_H +#define CONINFO_H + +#include +#include +#include +#include +#include +#include +#include +#include "kywirelessnetitem.h" +#include "kylinconnectresource.h" +#include "kylinactiveconnectresource.h" +#include "kywirelessconnectoperation.h" +#include "kywirelessnetresource.h" +#include "kyenterpricesettinginfo.h" + +#define AUTO_CONFIG 0 +#define MANUAL_CONFIG 1 + +enum PeapInnerType +{ + MSCHAPV2_PEAP = 0, + MD5_PEAP, + GTC_PEAP, +}; + +enum TtlsInnerType +{ + PAP = 0, + MSCHAP, + MSCHAPV2_EAP, + MSCHAPV2, + CHAP, + MD5_EAP, + GTC_EAP +}; + +class LineEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit LineEdit(QWidget *parent = nullptr) : QLineEdit(parent) {} + ~LineEdit() {} + +protected: + void contextMenuEvent(QContextMenuEvent *event) { + QMenu *menu = createStandardContextMenu();//默认的标准右键菜单,如果不需要刻意完全自己实现 + menu->setPalette(this->palette()); + menu->exec(event->globalPos()); + delete menu; + } +}; + +class ConInfo { +public: + QString strConName; + QString strConType; + QString strSecType; + KySecuType secType = WPA_AND_WPA2_PERSONAL; + QString strPassword; + QString strChan; + QString strMac; + QString strHz; + QString strBandWidth; + QString strDynamicIpv4; + QString strDynamicIpv6; + QString strDynamicIpv4Dns; + bool isAutoConnect = false; + + KyIpConfigType ipv4ConfigType = CONFIG_IP_DHCP; + QString strIPV4Address; + QString strIPV4NetMask; + QString strIPV4FirDns; + QString strIPV4SecDns; + QString strIPV4GateWay; + + KyIpConfigType ipv6ConfigType = CONFIG_IP_DHCP; + QString strIPV6Address; + int iIPV6Prefix; + QString strIPV6FirDns; + QString strIPV6SecDns; + QString strIPV6GateWay; + + KyEapMethodType enterpriseType; + KyEapMethodTlsInfo tlsInfo; + KyEapMethodPeapInfo peapInfo; + KyEapMethodTtlsInfo ttlsInfo; +}; + +static void setFramePalette(QFrame *widget, QPalette &pal) { + QList lineEditList = widget->findChildren(); + for (int i = 0; i < lineEditList.count(); ++i) { + lineEditList.at(i)->setPalette(pal); + lineEditList.at(i)->setContextMenuPolicy(Qt::DefaultContextMenu); + } + QList comboBoxList = widget->findChildren(); + for (int i = 0; i < comboBoxList.count(); ++i) { + comboBoxList.at(i)->setPalette(pal); + if (comboBoxList.at(i)->view()) { + comboBoxList.at(i)->view()->setPalette(pal); + } + } +} + +static QPalette lightPalette(QWidget *widget) +{ + QPalette palette = qApp->palette(); + + //ukui-light palette UKUI3.1 亮主题色板 + QColor windowText_at(38, 38, 38), + windowText_iat(0, 0, 0, 255 * 0.55), + windowText_dis(0, 0, 0, 255 * 0.3), + button_at(230, 230, 230), + button_iat(230, 230, 230), + button_dis(233, 233, 233), + light_at(255, 255, 255), + light_iat(255, 255, 255), + light_dis(242, 242, 242), + midlight_at(218, 218, 218), + midlight_iat(218, 218, 218), + midlight_dis(230, 230, 230), + dark_at(77, 77, 77), + dark_iat(77, 77, 77), + dark_dis(64, 64, 64), + mid_at(115, 115, 115), + mid_iat(115, 115, 115), + mid_dis(102, 102, 102), + text_at(38, 38, 38), + text_iat(38, 38, 38), + text_dis(0, 0, 0, 255 * 0.3), + brightText_at(0, 0, 0), + brightText_iat(0, 0, 0), + brightText_dis(0, 0, 0), + buttonText_at(38, 38, 38), + buttonText_iat(38, 38, 38), + buttonText_dis(179, 179, 179), + base_at(255, 255, 255), + base_iat(245, 245, 245), + base_dis(237, 237, 237), + window_at(245, 245, 245), + window_iat(237, 237, 237), + window_dis(230, 230, 230), + shadow_at(0, 0, 0, 255 * 0.16), + shadow_iat(0, 0, 0, 255 * 0.16), + shadow_dis(0, 0, 0, 255 * 0.21), + highLightText_at(255, 255, 255), + highLightText_iat(255, 255, 255), + highLightText_dis(179, 179, 179), + alternateBase_at(245, 245, 245), + alternateBase_iat(245, 245, 245), + alternateBase_dis(245, 245, 245), + noRale_at(240, 240, 240), + noRole_iat(240, 240, 240), + noRole_dis(217, 217, 217), + toolTipBase_at(255, 255, 255), + toolTipBase_iat(255, 255, 255), + toolTipBase_dis(255, 255, 255), + toolTipText_at(38, 38, 38), + toolTipText_iat(38, 38, 38), + toolTipText_dis(38, 38, 38), + placeholderText_at(0, 0, 0, 255 * 0.35), + placeholderText_iat(0, 0, 0, 255 * 0.35), + placeholderText_dis(0, 0, 0, 255 * 0.3); + + palette.setColor(QPalette::Active, QPalette::WindowText, windowText_at); + palette.setColor(QPalette::Inactive, QPalette::WindowText, windowText_iat); + palette.setColor(QPalette::Disabled, QPalette::WindowText, windowText_dis); + + palette.setColor(QPalette::Active, QPalette::Button, button_at); + palette.setColor(QPalette::Inactive, QPalette::Button, button_iat); + palette.setColor(QPalette::Disabled, QPalette::Button, button_dis); + + palette.setColor(QPalette::Active, QPalette::Light, light_at); + palette.setColor(QPalette::Inactive, QPalette::Light, light_iat); + palette.setColor(QPalette::Disabled, QPalette::Light, light_dis); + + palette.setColor(QPalette::Active, QPalette::Midlight, midlight_at); + palette.setColor(QPalette::Inactive, QPalette::Midlight, midlight_iat); + palette.setColor(QPalette::Disabled, QPalette::Midlight, midlight_dis); + + palette.setColor(QPalette::Active, QPalette::Dark, dark_at); + palette.setColor(QPalette::Inactive, QPalette::Dark, dark_iat); + palette.setColor(QPalette::Disabled, QPalette::Dark, dark_dis); + + palette.setColor(QPalette::Active, QPalette::Mid, mid_at); + palette.setColor(QPalette::Inactive, QPalette::Mid, mid_iat); + palette.setColor(QPalette::Disabled, QPalette::Mid, mid_dis); + + palette.setColor(QPalette::Active, QPalette::Text, text_at); + palette.setColor(QPalette::Inactive, QPalette::Text, text_iat); + palette.setColor(QPalette::Disabled, QPalette::Text, text_dis); + + palette.setColor(QPalette::Active, QPalette::BrightText, brightText_at); + palette.setColor(QPalette::Inactive, QPalette::BrightText, brightText_iat); + palette.setColor(QPalette::Disabled, QPalette::BrightText, brightText_dis); + + palette.setColor(QPalette::Active, QPalette::ButtonText, buttonText_at); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, buttonText_iat); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, buttonText_dis); + + palette.setColor(QPalette::Active, QPalette::Base, base_at); + palette.setColor(QPalette::Inactive, QPalette::Base, base_iat); + palette.setColor(QPalette::Disabled, QPalette::Base, base_dis); + + palette.setColor(QPalette::Active, QPalette::Window, window_at); + palette.setColor(QPalette::Inactive, QPalette::Window, window_iat); + palette.setColor(QPalette::Disabled, QPalette::Window, window_dis); + + palette.setColor(QPalette::Active, QPalette::Shadow, shadow_at); + palette.setColor(QPalette::Inactive, QPalette::Shadow, shadow_iat); + palette.setColor(QPalette::Disabled, QPalette::Shadow, shadow_dis); + + palette.setColor(QPalette::Active, QPalette::HighlightedText, highLightText_at); + palette.setColor(QPalette::Inactive, QPalette::HighlightedText, highLightText_iat); + palette.setColor(QPalette::Disabled, QPalette::HighlightedText, highLightText_dis); + + palette.setColor(QPalette::Active, QPalette::AlternateBase, alternateBase_at); + palette.setColor(QPalette::Inactive, QPalette::AlternateBase, alternateBase_iat); + palette.setColor(QPalette::Disabled, QPalette::AlternateBase, alternateBase_dis); + + palette.setColor(QPalette::Active, QPalette::NoRole, noRale_at); + palette.setColor(QPalette::Inactive, QPalette::NoRole, noRole_iat); + palette.setColor(QPalette::Disabled, QPalette::NoRole, noRole_dis); + + palette.setColor(QPalette::Active, QPalette::ToolTipBase, toolTipBase_at); + palette.setColor(QPalette::Inactive, QPalette::ToolTipBase, toolTipBase_iat); + palette.setColor(QPalette::Disabled, QPalette::ToolTipBase, toolTipBase_dis); + + palette.setColor(QPalette::Active, QPalette::ToolTipText, toolTipText_at); + palette.setColor(QPalette::Inactive, QPalette::ToolTipText, toolTipText_iat); + palette.setColor(QPalette::Disabled, QPalette::ToolTipText, toolTipText_dis); + +#if (QT_VERSION >= QT_VERSION_CHECK(5,12,0)) + palette.setColor(QPalette::Active, QPalette::PlaceholderText, placeholderText_at); + palette.setColor(QPalette::Inactive, QPalette::PlaceholderText, placeholderText_iat); + palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, placeholderText_dis); +#endif + + return palette; + +} + +#endif // CONINFO_H diff --git a/src/frontend/netdetails/creatnetpage.cpp b/src/frontend/netdetails/creatnetpage.cpp new file mode 100644 index 00000000..abc1d193 --- /dev/null +++ b/src/frontend/netdetails/creatnetpage.cpp @@ -0,0 +1,246 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "creatnetpage.h" +#include "math.h" + +#define MAX_NAME_LENGTH 32 + +CreatNetPage::CreatNetPage(QWidget *parent):QFrame(parent) +{ + initUI(); + initComponent(); +} + +void CreatNetPage::initUI() +{ + connNameEdit = new LineEdit(this); + connNameEdit->setMaxLength(MAX_NAME_LENGTH); + ipv4ConfigCombox = new QComboBox(this); + ipv4addressEdit = new LineEdit(this); + netMaskEdit = new LineEdit(this); + gateWayEdit = new LineEdit(this); + firstDnsEdit = new LineEdit(this); + secondDnsEdit = new LineEdit(this); + + m_connNameLabel = new QLabel(this); + m_configLabel = new QLabel(this); + m_addressLabel = new QLabel(this); + m_maskLabel = new QLabel(this); + m_gateWayLabel = new QLabel(this); + m_dnsLabel = new QLabel(this); + m_secDnsLabel = new QLabel(this); + + m_connNameLabel->setText(tr("Connection Name")); + m_configLabel->setText(tr("IPv4Config")); + m_addressLabel->setText(tr("Address")); + m_maskLabel->setText(tr("Netmask")); + m_gateWayLabel->setText(tr("Default Gateway")); + m_dnsLabel->setText(tr("Prefs DNS")); + m_secDnsLabel->setText(tr("Alternative DNS")); + + m_detailLayout = new QFormLayout(this); + m_detailLayout->addRow(m_connNameLabel,connNameEdit); + m_detailLayout->addRow(m_configLabel,ipv4ConfigCombox); + m_detailLayout->addRow(m_addressLabel,ipv4addressEdit); + m_detailLayout->addRow(m_maskLabel,netMaskEdit); + m_detailLayout->addRow(m_gateWayLabel,gateWayEdit); + m_detailLayout->addRow(m_dnsLabel,firstDnsEdit); + m_detailLayout->addRow(m_secDnsLabel,secondDnsEdit); + + ipv4ConfigCombox->addItem(tr("Auto(DHCP)"), AUTO_CONFIG); //"自动(DHCP)" + ipv4ConfigCombox->addItem(tr("Manual"), MANUAL_CONFIG); //"手动" + + + // IP的正则格式限制 + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + ipv4addressEdit->setValidator(new QRegExpValidator(rx, this)); + gateWayEdit->setValidator(new QRegExpValidator(rx, this)); + netMaskEdit->setValidator(new QRegExpValidator(rx, this)); + firstDnsEdit->setValidator(new QRegExpValidator(rx, this)); + secondDnsEdit->setValidator(new QRegExpValidator(rx, this)); +} + +void CreatNetPage::initComponent() { + if (ipv4ConfigCombox->currentIndex() == AUTO_CONFIG) { + setLineEnabled(false); + } else if (ipv4ConfigCombox->currentIndex() == MANUAL_CONFIG) { + setLineEnabled(true); + } + connect(ipv4ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(configChanged(int))); + + connect(connNameEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(ipv4ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEnableOfSaveBtn())); + connect(netMaskEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(gateWayEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(firstDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(secondDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); +} + +bool CreatNetPage::checkConnectBtnIsEnabled() +{ + if (connNameEdit->text().isEmpty()) { + qDebug() << "create connName empty or invalid"; + return false; + } + qDebug() << "checkConnectBtnIsEnabled currentIndex" << ipv4ConfigCombox->currentIndex(); + if (ipv4ConfigCombox->currentIndex() == AUTO_CONFIG) { + return true; + } else { + if (ipv4addressEdit->text().isEmpty() || !getTextEditState(ipv4addressEdit->text())) { + qDebug() << "create ipv4address empty or invalid"; + return false; + } + + if (netMaskEdit->text().isEmpty() || !netMaskIsValide(netMaskEdit->text())) { + qDebug() << "create ipv4 netMask empty or invalid"; + return false; + } + + if (gateWayEdit->text().isEmpty() || !getTextEditState(gateWayEdit->text())) { + qDebug() << "create ipv4 gateway empty or invalid"; + return false; + } + + if (firstDnsEdit->text().isEmpty() && !secondDnsEdit->text().isEmpty()) { + qDebug() << "create ipv4 dns sort invalid"; + return false; + } + + if (!getTextEditState(firstDnsEdit->text())) { + qDebug() << "create ipv4 first dns invalid"; + return false; + } + + if (!getTextEditState(secondDnsEdit->text())) { + qDebug() << "create ipv4 second dns invalid"; + return false; + } + } + return true; +} + +void CreatNetPage::configChanged(int index) { + if (index == AUTO_CONFIG) { + setLineEnabled(false); + } + if (index == MANUAL_CONFIG) { + setLineEnabled(true); + } +} + +void CreatNetPage::setLineEnabled(bool check) { + + ipv4addressEdit->setEnabled(check); + netMaskEdit->setEnabled(check); + gateWayEdit->setEnabled(check); + firstDnsEdit->setEnabled(check); + secondDnsEdit->setEnabled(check); + + if (!check) { + ipv4addressEdit->clear(); + netMaskEdit->clear(); + gateWayEdit->clear(); + firstDnsEdit->clear(); + secondDnsEdit->clear(); + } +} + +void CreatNetPage::setEnableOfSaveBtn() { + Q_EMIT setCreatePageState(checkConnectBtnIsEnabled()); +} + +bool CreatNetPage::getTextEditState(QString text) +{ + if (text.isEmpty()) { + return true; + } + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + bool match = false; + match = rx.exactMatch(text); + + return match; +} + +void CreatNetPage::constructIpv4Info(KyConnectSetting &setting) +{ + setting.m_connectName = connNameEdit->text(); + QString ipv4address =ipv4addressEdit->text(); + QString netMask = getNetMaskText(netMaskEdit->text()); + QString gateWay = gateWayEdit->text(); + qDebug() << "constructIpv4Info: " << "ipv4address " << ipv4address + << " netMask " << netMask + << " gateWay " << gateWay; + + QStringList dnsList; + dnsList.empty(); + if (!firstDnsEdit->text().isEmpty()) { + dnsList << firstDnsEdit->text(); + if (!secondDnsEdit->text().isEmpty()) { + dnsList << secondDnsEdit->text(); + } + } + if (ipv4ConfigCombox->currentData() == AUTO_CONFIG) { + setting.setIpConfigType(IPADDRESS_V4, CONFIG_IP_DHCP); + } else { + setting.setIpConfigType(IPADDRESS_V4, CONFIG_IP_MANUAL); + setting.ipv4AddressConstruct(ipv4address, netMask, gateWay, dnsList); + } + +} + +bool CreatNetPage::netMaskIsValide(QString text) +{ + if (getTextEditState(text)) { + return true; + } else { + if (text.length() > 0 && text.length() < 3) { + int num = text.toInt(); + if (num > 0 && num < 33) { + return true; + } + } + } + return false; +} + +QString CreatNetPage::getNetMaskText(QString text) +{ + if (text.length() > 2) { + return text; + } + + int num = text.toInt(); + QStringList list; + list << "0" << "0" << "0" << "0"; + int count = 0; + while (num - 8 >= 0) { + list[count] = "255"; + num = num - 8; + count ++; + } + if (num > 0) { + int size = pow(2, 8) - pow(2,(8-num)); + list[count] = QString::number(size); + } + return QString("%1.%2.%3.%4").arg(list[0],list[1],list[2],list[3]); +} + diff --git a/src/frontend/netdetails/creatnetpage.h b/src/frontend/netdetails/creatnetpage.h new file mode 100644 index 00000000..b716084e --- /dev/null +++ b/src/frontend/netdetails/creatnetpage.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CREATNETPAGE_H +#define CREATNETPAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "coninfo.h" + +class CreatNetPage : public QFrame +{ + Q_OBJECT +public: + CreatNetPage(QWidget *parent = nullptr); + + void constructIpv4Info(KyConnectSetting &setting); +private: + LineEdit *connNameEdit; + QComboBox *ipv4ConfigCombox; + LineEdit *ipv4addressEdit; + LineEdit *netMaskEdit; + LineEdit *gateWayEdit; + LineEdit *firstDnsEdit; + LineEdit *secondDnsEdit; + +private: + QFormLayout *m_detailLayout; + QVBoxLayout *mvBoxLayout; + QLabel *m_connNameLabel; + QLabel *m_configLabel; + QLabel *m_addressLabel; + QLabel *m_maskLabel; + QLabel *m_gateWayLabel; + QLabel *m_dnsLabel; + QLabel *m_secDnsLabel; +private: + void initUI(); + void initComponent(); + void setLineEnabled(bool check); + void configSave(); + bool getTextEditState(QString text); + bool checkConnectBtnIsEnabled(); + + bool netMaskIsValide(QString text); + QString getNetMaskText(QString text); + +private Q_SLOTS: + void setEnableOfSaveBtn(); + void configChanged(int index); +Q_SIGNALS: + void setCreatePageState(bool); + +}; + +#endif // CREATNETPAGE_H diff --git a/src/frontend/netdetails/customtabstyle.cpp b/src/frontend/netdetails/customtabstyle.cpp new file mode 100644 index 00000000..23e0745d --- /dev/null +++ b/src/frontend/netdetails/customtabstyle.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "customtabstyle.h" + + +CustomTabStyle::CustomTabStyle() +{ + +} + +QSize CustomTabStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const +{ + QSize s = QProxyStyle::sizeFromContents(type, option, size, widget); + if (type == QStyle::CT_TabBarTab) { + s.transpose(); + s.rwidth() = 60; // 设置每个tabBar中item的大小 + s.rheight() = 36; + } + return s; +} + +void CustomTabStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + if (element == CE_TabBarTab) { + if (const QStyleOptionTab *tab = qstyleoption_cast(option)) { + QRect allRect = tab->rect; + if (tab->state & QStyle::State_Selected) { //选中状态:tab的Qlabel为矩形,底色为白色,边框淡灰色,文字为淡蓝色且加粗居中(具体颜色值由拾色器提取) + painter->save(); + painter->setPen(0x3790FA); //设置画笔颜色为淡灰色 + painter->setBrush(QBrush(0x3790FA)); //设置画刷为白色 + painter->drawRoundedRect(allRect.adjusted(0,0,0,0),6,6); //重绘tab的矩形边框 + painter->restore(); //还原为默认 + + painter->save(); + painter->setPen(0xffffff); //重新设置画笔颜色为淡蓝色 + QTextOption option; + option.setAlignment(Qt::AlignCenter); //设置文字居中 + painter->drawText(allRect, tab->text, option); //重绘文字 + painter->restore(); + } + else if(tab->state & QStyle::State_MouseOver) { //hover状态:tab的Qlabel为矩形,底色为灰色,边框仍未淡灰色,文字加粗居中 + painter->save(); + painter->setPen(tab->palette.color(QPalette::Window)); //设置画笔颜色为淡灰色 + painter->setBrush(tab->palette.color(QPalette::Window)); //设置画刷为灰色 + painter->drawRoundedRect(allRect.adjusted(0,0,0,0),6,6); //重绘tab的矩形边框 + painter->restore(); //还原 + + painter->save(); + QTextOption option; + option.setAlignment(Qt::AlignCenter); //设置文字居中 + painter->drawText(allRect, tab->text, option); //重绘文字 + painter->restore(); + } + else //其它的:tab的Qlabel为矩形,底色为灰色,边框为淡灰色不变,文字不加粗但居中 + { + painter->save(); + painter->setPen(tab->palette.color(QPalette::Button)); + painter->setBrush(tab->palette.color(QPalette::Button)); + painter->drawRoundedRect(allRect.adjusted(0,0,0,0),6,6); //重绘tab的矩形边框 + painter->restore(); + painter->save(); + QTextOption option; + option.setAlignment(Qt::AlignCenter); + painter->drawText(allRect, tab->text, option); + painter->restore(); + } + return; + } + } + + if (element == CE_TabBarTab) { + QProxyStyle::drawControl(element, option, painter, widget); + } +} + diff --git a/src/frontend/netdetails/customtabstyle.h b/src/frontend/netdetails/customtabstyle.h new file mode 100644 index 00000000..005ddef0 --- /dev/null +++ b/src/frontend/netdetails/customtabstyle.h @@ -0,0 +1,38 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef CUSTOMTABSTYLE_H +#define CUSTOMTABSTYLE_H + +#include +#include +#include +#include +#include +class CustomTabStyle : public QProxyStyle +{ +public: + CustomTabStyle(); + QSize sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const; + + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; +}; + +#endif // CUSTOMTABSTYLE_H diff --git a/src/frontend/netdetails/detailpage.cpp b/src/frontend/netdetails/detailpage.cpp new file mode 100644 index 00000000..9356f1c1 --- /dev/null +++ b/src/frontend/netdetails/detailpage.cpp @@ -0,0 +1,376 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "detailpage.h" +#include +#include + +#define MAX_NAME_LENGTH 32 +#define MAX_LABEL_WIDTH 250 +#define MAX_SSID_WIDTH 133 + +extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); + +DetailPage::DetailPage(bool isWlan, bool isCreate, QWidget *parent) + : m_IsWlan(isWlan), m_IsCreate(isCreate), QFrame(parent) +{ +// this->setFrameShape(QFrame::Shape::StyledPanel); + this->setMaximumWidth(960); + initUI(); + if (isCreate) { + connect(m_SSIDEdit, &LineEdit::textEdited, this, &DetailPage::setEnableOfSaveBtn); + } +} + +DetailPage::~DetailPage() +{ + if (m_copiedTip != nullptr) { + delete m_copiedTip; + m_copiedTip = nullptr; + } +} + +void DetailPage::setSSID(const QString &ssid) { + if (m_IsCreate) { + return; + } + m_formerSSID = ssid; + QFontMetrics fontMetrics(m_SSIDLabel->font()); + int fontSize = fontMetrics.width(ssid); + if (fontSize > MAX_SSID_WIDTH) { + this->m_SSIDLabel->setText(fontMetrics.elidedText(ssid, Qt::ElideRight, MAX_SSID_WIDTH)); + this->setToolTip(ssid); + } else { + this->m_SSIDLabel->setText(ssid); + this->setToolTip(""); + } +} + +void DetailPage::setProtocol(const QString &protocol) { + this->m_Protocol->setText(protocol); +} + +void DetailPage::setSecType(const QString &secType) { + this->m_SecType->setText(secType); +} + +void DetailPage::setHz(const QString &hz) { + this->m_Hz->setText(hz); +} + +void DetailPage::setChan(const QString &chan) { + this->m_Chan->setText(chan); +} + +void DetailPage::setBandWidth(const QString &brandWidth) { + this->m_BandWidth->setText(brandWidth); +} + +void DetailPage::setIpv4(const QString &ipv4) { + this->m_IPV4->setText(ipv4); +} + +void DetailPage::setIpv4Dns(const QString &ipv4Dns) { + this->m_IPV4Dns->setText(ipv4Dns); +} + +void DetailPage::setIpv6(const QString &ipv6) { + m_formerIPV6 = ipv6; + this->m_IPV6->setLabelText(ipv6); +} + +void DetailPage::setMac(const QString &mac) { + this->m_Mac->setText(mac); +} + +void DetailPage::setAutoConnect(bool flag) +{ + if (!m_IsWlan) { + return; + } + this->m_forgetNetBox->setChecked(flag); +} + +void DetailPage::getSsid(QString &ssid) +{ + if (m_IsCreate) { + ssid = m_SSIDEdit->text(); + } else { + ssid = m_SSIDLabel->text(); + } +} + +bool DetailPage::checkIsChanged(const ConInfo info) +{ + if (!m_IsWlan) { + return false; + } + if (info.isAutoConnect != m_forgetNetBox->isChecked()) { + return true; + } else { + return false; + } +} + +void DetailPage::addDetailItem(QListWidget *listWidget, QWidget *detailWidget) +{ + QListWidgetItem *listWidgetItem = new QListWidgetItem(listWidget); + listWidgetItem->setSizeHint(QSize(listWidget->width(),36)); + listWidgetItem->setFlags(Qt::NoItemFlags); + listWidget->addItem(listWidgetItem); + listWidget->setItemWidget(listWidgetItem, detailWidget); +} + +void DetailPage::newCopiedTip() +{ + //设置“复制成功”消息弹窗格式 + m_copiedTip = new KBallonTip(); + m_copiedTip->setTipType(Normal); + m_copiedTip->setContentsMargins(16, 14, 16, 14); + m_copiedTip->setFixedHeight(48); + m_copiedTip->setWindowFlags(Qt::FramelessWindowHint); + m_copiedTip->setAttribute(Qt::WA_TranslucentBackground, true); + m_copiedTip->setText(tr("Copied successfully!")); +} + +QPalette DetailPage::getTheme() +{ + //获取当前主题的颜色 + QPalette pal = qApp->palette(); +// QGSettings * styleGsettings = nullptr; +// const QByteArray style_id(THEME_SCHAME); +// if (QGSettings::isSchemaInstalled(style_id)) { +// styleGsettings = new QGSettings(style_id); +// QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); +// if(currentTheme == "ukui-default"){ +// pal = lightPalette(this); +// } +// } +// if (styleGsettings != nullptr) { +// delete styleGsettings; +// styleGsettings = nullptr; +// } + return pal; +} + +void DetailPage::initUI() { + m_layout = new QVBoxLayout(this); + m_layout->setContentsMargins(0,0,0,0); + m_layout->setSpacing(0); + + QWidget *mDetailFrame = new QFrame(this); + mDetailFrame->setFixedHeight(362); + m_DetailLayout = new QVBoxLayout(mDetailFrame); + m_DetailLayout->setContentsMargins(0,0,0,0); + + m_listWidget = new QListWidget(mDetailFrame); + m_listWidget->setFrameShape(QFrame::Shape::NoFrame); + m_listWidget->setBackgroundRole(QPalette::Base); + m_listWidget->setFocusPolicy(Qt::FocusPolicy::NoFocus); + m_DetailLayout->addWidget(m_listWidget); + + m_listWidget->setFrameShape(QFrame::Shape::StyledPanel); + + if (!m_IsCreate) { + m_SSIDLabel = new QLabel(this); + m_SSIDLabel->adjustSize(); + m_SSIDLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + + m_netCopyButton = new QPushButton(this); + m_netCopyButton->setIcon(QIcon::fromTheme("edit-copy-symbolic")); + m_netCopyButton->setToolTip(tr("Copy all")); + //设置按钮背景颜色-透明 + QPalette btnPal = m_netCopyButton->palette(); + QColor color = qApp->palette().color(QPalette::Background); + color.setAlphaF(0); + btnPal.setColor(QPalette::Button, color); + m_netCopyButton->setPalette(btnPal); + + m_ssidWidget = new DetailWidget(qobject_cast(m_SSIDLabel), m_listWidget, m_netCopyButton); + connect(m_netCopyButton, &QPushButton::clicked, this, &DetailPage::on_btnCopyNetDetail_clicked); + newCopiedTip(); + +// mSSID->setStyleSheet("background:transparent;border-width:0px;border-style:none"); +// mSSID->setFocusPolicy(Qt::NoFocus); + } else { +// mSSID->setStyleSheet("border-width:1px;;border-style:solid;border-color:black;border-radius:2px"); + m_SSIDEdit = new LineEdit(this); + m_SSIDEdit->setMaximumWidth(MAX_LABEL_WIDTH); + m_SSIDEdit->setAlignment(Qt::AlignRight); + m_SSIDEdit->setStyleSheet("border-top:0px solid;border-bottom:1px solid;border-left:0px solid;border-right: 0px solid;background:transparent"); + m_SSIDEdit->setPlaceholderText(tr("Please input SSID:")); + m_SSIDEdit->setMaxLength(MAX_NAME_LENGTH); + m_ssidWidget = new DetailWidget(qobject_cast(m_SSIDEdit), m_listWidget); + } + + + m_ssidWidget->setKey(tr("SSID:")); + + m_Protocol = new QLabel(this); + m_protocolWidget = new DetailWidget(qobject_cast(m_Protocol), m_listWidget); + m_protocolWidget->setKey(tr("Protocol:")); + + m_SecType = new QLabel(this); + m_secTypeWidget = new DetailWidget(qobject_cast(m_SecType)); + m_secTypeWidget->setKey(tr("Security Type:")); + + m_Hz = new QLabel(this); + m_hzWidget = new DetailWidget(qobject_cast(m_Hz)); + m_hzWidget->setKey(tr("Hz:")); + + m_Chan = new QLabel(this); + m_chanelWidget = new DetailWidget(qobject_cast(m_Chan)); + m_chanelWidget->setKey(tr("Chan:")); + + m_BandWidth = new QLabel(this); + m_bandwidthWidget = new DetailWidget(qobject_cast(m_BandWidth), m_listWidget); + m_bandwidthWidget->setKey(tr("BandWidth:")); + + m_IPV4 = new QLabel(this); + m_ipv4Widget = new DetailWidget(qobject_cast(m_IPV4), m_listWidget); + m_ipv4Widget->setKey(tr("IPv4:")); + + m_IPV4Dns = new QLabel(this); + m_ipv4DnsWidget = new DetailWidget(qobject_cast(m_IPV4Dns), m_listWidget); + m_ipv4DnsWidget->setKey(tr("IPv4 Dns:")); + + m_IPV6 = new FixLabel(this); + m_IPV6->setFixedWidth(MAX_LABEL_WIDTH); + m_IPV6->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + m_ipv6Widget = new DetailWidget(qobject_cast(m_IPV6), m_listWidget); + m_ipv6Widget->setKey(tr("IPv6:")); + + m_Mac = new QLabel(this); + m_macWidget = new DetailWidget(qobject_cast(m_Mac), m_listWidget); + m_macWidget->setKey(tr("Mac:")); + + if (m_IsWlan) { + m_autoConnect = new QLabel(this); + m_forgetNetBox = new QCheckBox(this); + + m_autoConnect->setText(tr("Auto Connection")); + + m_autoConWidget = new QWidget(this); + m_AutoLayout = new QHBoxLayout(m_autoConWidget); + QSpacerItem *horizontalSpacer; + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + m_AutoLayout->addSpacing(20); + m_AutoLayout->addWidget(m_forgetNetBox); + m_AutoLayout->addWidget(m_autoConnect); + m_AutoLayout->addSpacerItem(horizontalSpacer); + } + + this->addDetailItem(m_listWidget, m_ssidWidget); + this->addDetailItem(m_listWidget, m_protocolWidget); + if (m_IsWlan) { + this->addDetailItem(m_listWidget, m_secTypeWidget); + this->addDetailItem(m_listWidget, m_hzWidget); + this->addDetailItem(m_listWidget, m_chanelWidget); + } + this->addDetailItem(m_listWidget, m_bandwidthWidget); + this->addDetailItem(m_listWidget, m_ipv6Widget); + this->addDetailItem(m_listWidget, m_ipv4Widget); + this->addDetailItem(m_listWidget, m_ipv4DnsWidget); + this->addDetailItem(m_listWidget, m_macWidget); + + QPalette mpal(m_listWidget->palette()); + mpal.setColor(QPalette::Base, qApp->palette().base().color()); + mpal.setColor(QPalette::AlternateBase, qApp->palette().alternateBase().color()); + m_listWidget->setAlternatingRowColors(true); +// m_listWidget->setAutoFillBackground(true); + m_listWidget->setPalette(mpal); + + m_layout->addWidget(mDetailFrame); + if (m_IsWlan) { +// m_layout->addLayout(m_AutoLayout); + m_layout->addWidget(m_autoConWidget); + } + m_layout->addStretch(); +} + +void DetailPage::setEnableOfSaveBtn() { + bool saveEnable = true; + if (m_IsCreate) { + saveEnable = !m_SSIDEdit->text().isEmpty(); + } + Q_EMIT setDetailPageState(saveEnable); +} + +//获取列表信息 +void DetailPage::on_btnCopyNetDetail_clicked() +{ + QStringList netDetailList; + QString ssidCopy = tr("SSID:"); + QString protocolCopy = tr("Protocol:"); + QString securityCopy = tr("Security Type:"); + QString hzCopy= tr ("Hz:"); + QString chanCopy= tr ("Chan:"); + QString bandwithCopy = tr("BandWidth:"); + QString ipv4Copy = tr("IPv4:"); + QString ipv4dnsCopy = tr("IPv4 Dns:"); + QString ipv6Copy = tr("IPv6:"); + QString macCopy = tr("Mac:"); + QString netDetailCopyText; + + ssidCopy.append(m_formerSSID); + protocolCopy.append(this->m_Protocol->text()); + netDetailList.append(ssidCopy); + netDetailList.append(protocolCopy); + + if(m_IsWlan) + { + securityCopy.append(this->m_SecType->text()); + hzCopy.append(this->m_Hz->text()); + chanCopy.append(this->m_Chan->text()); + netDetailList.append(securityCopy); + netDetailList.append(hzCopy); + netDetailList.append(chanCopy); + } + + bandwithCopy += this->m_BandWidth->text(); + ipv6Copy += m_formerIPV6; + ipv4Copy += this->m_IPV4->text(); + ipv4dnsCopy += this->m_IPV4Dns->text(); + macCopy += this->m_Mac->text(); + netDetailList.append(bandwithCopy); + netDetailList.append(ipv4Copy); + netDetailList.append(ipv4dnsCopy); + netDetailList.append(ipv6Copy); + netDetailList.append(macCopy); +// qDebug() << netDetailList; + + //设置剪贴板内容 + netDetailCopyText = netDetailList.join("\n"); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(netDetailCopyText); + + //设置“复制成功”弹窗位置并显示 + if (m_copiedTip != nullptr) { + delete m_copiedTip; + newCopiedTip(); + } + QPoint position = m_ssidWidget->mapToGlobal(this->pos()); + double x = (this->width() - 0.5 * m_copiedTip->width()); + m_copiedTip->move(position.x() + x, position.y() + this->height() * 0.3); + QPalette pal = getTheme(); + m_copiedTip->setPalette(pal); + m_copiedTip->showInfo(); +} + diff --git a/src/frontend/netdetails/detailpage.h b/src/frontend/netdetails/detailpage.h new file mode 100644 index 00000000..75aaa61e --- /dev/null +++ b/src/frontend/netdetails/detailpage.h @@ -0,0 +1,123 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DETAILPAGE_H +#define DETAILPAGE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "detailwidget.h" +#include "coninfo.h" +#include "kwidget.h" +#include "ktabbar.h" +#include "kballontip.h" +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" + +using namespace kdk; + +class DetailPage : public QFrame +{ + Q_OBJECT +public: + DetailPage(bool isWlan, bool isCreate = false, QWidget *parent = nullptr); + ~DetailPage(); + void setSSID(const QString &ssid); + void setProtocol(const QString &protocol); + void setSecType(const QString &secType); + void setHz(const QString &hz); + void setChan(const QString &chan); + void setBandWidth(const QString &brandWidth); + void setIpv4(const QString &ipv4); + void setIpv4Dns(const QString &ipv4Dns); + void setIpv6(const QString &ipv6); + void setMac(const QString &mac); + void setAutoConnect(bool flag); + + bool checkIsChanged(const ConInfo info); + + void getSsid(QString &ssid); + +private: + void initUI(); + void addDetailItem(QListWidget *listWidget, QWidget *detailWidget); + void newCopiedTip(); + QPalette getTheme(); + +public: + QListWidget *m_listWidget = nullptr; + DetailWidget *m_ssidWidget = nullptr; + DetailWidget *m_protocolWidget = nullptr; + DetailWidget *m_secTypeWidget = nullptr; + DetailWidget *m_hzWidget = nullptr; + DetailWidget *m_chanelWidget = nullptr; + DetailWidget *m_bandwidthWidget = nullptr; + DetailWidget *m_ipv4Widget = nullptr; + DetailWidget *m_ipv4DnsWidget = nullptr; + DetailWidget *m_ipv6Widget = nullptr; + DetailWidget *m_macWidget = nullptr; + + QPushButton *m_netCopyButton; + LineEdit *m_SSIDEdit; + QLabel *m_SSIDLabel; + QLabel *m_Protocol; + QLabel *m_SecType; + QLabel *m_Hz; + QLabel *m_Chan; + QLabel *m_BandWidth; + QLabel *m_IPV4; + QLabel *m_IPV4Dns; + FixLabel *m_IPV6; + QLabel *m_Mac; + QLabel *m_autoConnect; + KBallonTip *m_copiedTip = nullptr; + +// QWidget *autoFrame; +private: + QVBoxLayout *m_layout; + QVBoxLayout *m_DetailLayout; + QHBoxLayout *m_AutoLayout; + QCheckBox *m_forgetNetBox; + bool m_IsWlan; + bool m_IsCreate; + + QWidget *m_autoConWidget; + + QString m_formerSSID; + QString m_formerIPV6; + +private Q_SLOTS: + void setEnableOfSaveBtn(); + void on_btnCopyNetDetail_clicked(); + +Q_SIGNALS: + void setDetailPageState(bool); + +}; + +#endif // DETAILPAGE_H diff --git a/src/frontend/netdetails/detailwidget.cpp b/src/frontend/netdetails/detailwidget.cpp new file mode 100644 index 00000000..2c0d1864 --- /dev/null +++ b/src/frontend/netdetails/detailwidget.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "detailwidget.h" +#include +#include +#include + +#define ITEM_HEIGHT 36 +#define ITEM_MARGINS 18,0,16,0 +#define MIN_LABEL_WIDTH 146 +#define MAX_LABEL_WIDTH 154 +#define MAX_WIDGET_WIDTH 270 + +FixLabel::FixLabel(QWidget *parent) : + QLabel(parent) +{ + const QByteArray id("org.ukui.style"); + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + if(QGSettings::isSchemaInstalled(id)){ + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("systemFont" == key || "systemFontSize" ==key) { + changedLabelSlot(); + } + }); + } +} + + +void FixLabel::setLabelText(QString text) { + + mStr = text; + changedLabelSlot(); +} + +QString FixLabel::getText(){ + return mStr; +} + +void FixLabel::changedLabelSlot() { + QFontMetrics fontMetrics(this->font()); + int fontSize = fontMetrics.width(mStr); + if (fontSize > this->width()) { + setText(fontMetrics.elidedText(mStr, Qt::ElideRight, this->width())); + setToolTip(mStr); + } else { + setText(mStr); + setToolTip(""); + } +} + + + +DetailWidget::DetailWidget(QWidget *valueWidget, QWidget *parent, QWidget *buttonWidget) + : m_valueWidget(valueWidget) , QWidget(parent) , m_copyButton(buttonWidget) +{ +// m_valueWidget = valueWidget; + initUI(); +} + +DetailWidget::~DetailWidget() +{ + +} + +void DetailWidget::initUI() +{ + this->setFixedHeight(ITEM_HEIGHT); + m_mainLayout = new QHBoxLayout(this); + m_mainLayout->setContentsMargins(ITEM_MARGINS); + + m_keyLabel = new FixLabel(this); + m_keyLabel->setMinimumWidth(MIN_LABEL_WIDTH); + m_keyLabel->setMaximumWidth(MAX_LABEL_WIDTH); + m_keyLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + + m_mainLayout->addWidget(m_keyLabel); + m_mainLayout->addStretch(); + if (m_copyButton != nullptr) { + m_copyButton->setMaximumWidth(ITEM_HEIGHT-8); + m_copyButton->setMaximumHeight(ITEM_HEIGHT-8); + m_mainLayout->addWidget(m_copyButton); + } + m_mainLayout->addWidget(m_valueWidget); + m_valueWidget->setMaximumWidth(MAX_WIDGET_WIDTH); +} + +void DetailWidget::setKey(const QString &keyLabel) +{ + m_keyLabel->setLabelText(keyLabel); +} diff --git a/src/frontend/netdetails/detailwidget.h b/src/frontend/netdetails/detailwidget.h new file mode 100644 index 00000000..c82a5eb5 --- /dev/null +++ b/src/frontend/netdetails/detailwidget.h @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DetailWidget_H +#define DetailWidget_H + +#include +#include +#include + +class FixLabel : public QLabel +{ + Q_OBJECT +public: + explicit FixLabel(QWidget *parent = 0); + +public: + void setLabelText(QString text); + QString getText(); + +private Q_SLOTS: + void changedLabelSlot(); +private: + QString mStr; + +}; + +class DetailWidget : public QWidget +{ + Q_OBJECT +public: + explicit DetailWidget(QWidget *valueWidget = nullptr, QWidget *parent = nullptr, QWidget *buttonWidget = nullptr); + ~DetailWidget(); + + void setKey(const QString &keyLabel); + +private: + QHBoxLayout *m_mainLayout = nullptr; + FixLabel *m_keyLabel = nullptr; + QWidget *m_valueWidget = nullptr; + QWidget *m_copyButton; + + void initUI(); + +}; + +#endif // DetailWidget_H diff --git a/src/frontend/netdetails/ipv4page.cpp b/src/frontend/netdetails/ipv4page.cpp new file mode 100644 index 00000000..6e2ca81c --- /dev/null +++ b/src/frontend/netdetails/ipv4page.cpp @@ -0,0 +1,460 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "ipv4page.h" +#include "netdetail.h" +#include "math.h" + +#define LAYOUT_MARGINS 0,0,0,0 +#define LAYOUT_SPACING 0 +#define HINT_TEXT_MARGINS 8, 1, 0, 3 +#define LABEL_HEIGHT 24 +#define FRAME_SPEED 150 +#define ICON_SIZE 16,16 + +Ipv4Page::Ipv4Page(QWidget *parent):QFrame(parent) +{ + initUI(); + initComponent(); +} + +void Ipv4Page::initUI() { + ipv4ConfigCombox = new QComboBox(this); + ipv4addressEdit = new LineEdit(this); + netMaskEdit = new LineEdit(this); + gateWayEdit = new LineEdit(this); + firstDnsEdit = new LineEdit(this); + secondDnsEdit = new LineEdit(this); + + m_configLabel = new QLabel(this); + m_addressLabel = new QLabel(this); + m_maskLabel = new QLabel(this); + m_gateWayLabel = new QLabel(this); + m_dnsLabel = new QLabel(this); + m_secDnsLabel = new QLabel(this); + + m_configEmptyLabel = new QLabel(this); + m_configEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + m_addressHintLabel = new QLabel(this); + m_addressHintLabel->setFixedHeight(LABEL_HEIGHT); + m_addressHintLabel->setContentsMargins(HINT_TEXT_MARGINS); + initConflictHintLable(); + + m_maskHintLabel = new QLabel(this); + m_maskHintLabel->setFixedHeight(LABEL_HEIGHT); + m_maskHintLabel->setContentsMargins(HINT_TEXT_MARGINS); + + m_gateWayEmptyLabel = new QLabel(this); + m_gateWayEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + m_firstDnsEmptyLabel = new QLabel(this); + m_firstDnsEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + + m_configLabel->setText(tr("IPv4Config")); + m_addressLabel->setText(tr("Address")); + m_maskLabel->setText(tr("Netmask")); + m_gateWayLabel->setText(tr("Default Gateway")); + m_dnsLabel->setText(tr("Prefs DNS")); + m_secDnsLabel->setText(tr("Alternative DNS")); + + m_statusLabel = new QLabel(this); + m_statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + QHBoxLayout *pPwdLayout = new QHBoxLayout(ipv4addressEdit); + pPwdLayout->addStretch(); + pPwdLayout->addWidget(m_statusLabel); + + QPalette hintTextColor; + hintTextColor.setColor(QPalette::WindowText, Qt::red); + m_addressHintLabel->setPalette(hintTextColor); + m_maskHintLabel->setPalette(hintTextColor); + + QWidget *addressWidget = new QWidget(this); + QVBoxLayout *addressLayout = new QVBoxLayout(addressWidget); + addressLayout->setContentsMargins(LAYOUT_MARGINS); + addressLayout->setSpacing(LAYOUT_SPACING); + addressLayout->addWidget(ipv4addressEdit); + addressLayout->addWidget(m_addressHintLabel); + + QWidget *maskWidget = new QWidget(this); + QVBoxLayout *maskLayout = new QVBoxLayout(maskWidget); + maskLayout->setContentsMargins(LAYOUT_MARGINS); + maskLayout->setSpacing(LAYOUT_SPACING); + maskLayout->addWidget(netMaskEdit); + maskLayout->addWidget(m_maskHintLabel); + + m_detailLayout = new QFormLayout(this); + m_detailLayout->setVerticalSpacing(0); + m_detailLayout->setContentsMargins(LAYOUT_MARGINS); + m_detailLayout->addRow(m_configLabel,ipv4ConfigCombox); + m_detailLayout->addRow(m_configEmptyLabel); + m_detailLayout->addRow(m_addressLabel,addressWidget); + m_detailLayout->addRow(m_maskLabel,maskWidget); + m_detailLayout->addRow(m_gateWayLabel,gateWayEdit); + m_detailLayout->addRow(m_gateWayEmptyLabel); + m_detailLayout->addRow(m_dnsLabel,firstDnsEdit); + m_detailLayout->addRow(m_firstDnsEmptyLabel); + m_detailLayout->addRow(m_secDnsLabel,secondDnsEdit); + + ipv4ConfigCombox->addItem(tr("Auto(DHCP)")); //"自动(DHCP)" + ipv4ConfigCombox->addItem(tr("Manual")); //"手动" + +// netMaskCombox->addItem(""); +// netMaskCombox->addItem("255.255.255.0"); //24 +// netMaskCombox->addItem("255.255.254.0"); //23 +// netMaskCombox->addItem("255.255.252.0"); //22 +// netMaskCombox->addItem("255.255.0.0"); //16 +// netMaskCombox->addItem("255.0.0.0"); //8 + + + // IP的正则格式限制 + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + ipv4addressEdit->setValidator(new QRegExpValidator(rx, this)); + gateWayEdit->setValidator(new QRegExpValidator(rx, this)); + netMaskEdit->setValidator(new QRegExpValidator(rx, this)); + firstDnsEdit->setValidator(new QRegExpValidator(rx, this)); + secondDnsEdit->setValidator(new QRegExpValidator(rx, this)); + + initLoadingIcon(); +} + +void Ipv4Page::initComponent() { + if (ipv4ConfigCombox->currentIndex() == AUTO_CONFIG) { + setLineEnabled(false); + } else if (ipv4ConfigCombox->currentIndex() == MANUAL_CONFIG) { + setLineEnabled(true); + } + connect(ipv4ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(configChanged(int))); + + connect(ipv4addressEdit, SIGNAL(textChanged(QString)), this, SLOT(onAddressTextChanged())); + connect(ipv4addressEdit, SIGNAL(editingFinished()), this, SLOT(onAddressEidtFinished())); + connect(netMaskEdit, SIGNAL(textChanged(QString)), this, SLOT(onNetMaskTextChanged())); + + connect(ipv4ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEnableOfSaveBtn())); + connect(ipv4addressEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(netMaskEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(gateWayEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(firstDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(secondDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); +} + +void Ipv4Page::setIpv4Config(KyIpConfigType ipv4Config) +{ + if (ipv4Config == CONFIG_IP_MANUAL) { + ipv4ConfigCombox->setCurrentIndex(MANUAL_CONFIG); + } else { + ipv4ConfigCombox->setCurrentIndex(AUTO_CONFIG); + } +} + +void Ipv4Page::setIpv4(const QString &ipv4) +{ + ipv4addressEdit->setText(ipv4); +} + +void Ipv4Page::setNetMask(const QString &netMask) +{ + netMaskEdit->setText(netMask); +} + +void Ipv4Page::setIpv4FirDns(const QString &ipv4FirDns) +{ + firstDnsEdit->setText(ipv4FirDns); +} + +void Ipv4Page::setIpv4SecDns(const QString &ipv4SecDns) +{ + secondDnsEdit->setText(ipv4SecDns); +} + +void Ipv4Page::setGateWay(const QString &gateWay) +{ + gateWayEdit->setText(gateWay); +} + +bool Ipv4Page::checkIsChanged(const ConInfo info, KyConnectSetting &setting) +{ + bool isChanged = false; + if (ipv4ConfigCombox->currentIndex() == AUTO_CONFIG) { + if (info.ipv4ConfigType != CONFIG_IP_DHCP) { + qDebug() << "ipv4ConfigType change to Auto"; + setting.setIpConfigType(IPADDRESS_V4, CONFIG_IP_DHCP); + QString ipv4address(""); + QString netMask(""); + QString gateWay(""); + QStringList dnsList; + dnsList.empty(); + qDebug() << ipv4address << netMask << gateWay; + setting.ipv4AddressConstruct(ipv4address, netMask, gateWay, dnsList); + isChanged = true; + } + } else { + if (info.ipv4ConfigType != CONFIG_IP_MANUAL) { + qDebug() << "ipv4ConfigType change to Manual"; + setting.setIpConfigType(IPADDRESS_V4, CONFIG_IP_MANUAL); + isChanged = true; + } + qDebug() << "ipv4 netmask " << getNetMaskText(netMaskEdit->text()); + if(info.strIPV4Address != ipv4addressEdit->text() + || info.strIPV4NetMask != /*netMaskEdit->text()*/getNetMaskText(netMaskEdit->text()) + || info.strIPV4GateWay != gateWayEdit->text() + || info.strIPV4FirDns != firstDnsEdit->text() + || info.strIPV4SecDns != secondDnsEdit->text()) { + + qDebug() << "ipv4 info changed"; + QStringList dnsList; + dnsList.empty(); + if (!firstDnsEdit->text().isEmpty()) { + dnsList << firstDnsEdit->text(); + if (!secondDnsEdit->text().isEmpty()) { + dnsList << secondDnsEdit->text(); + } + } + + QString ipv4address =ipv4addressEdit->text(); + QString netMask = getNetMaskText(netMaskEdit->text()); + QString gateWay = gateWayEdit->text(); + qDebug() << ipv4address << netMask << gateWay; + setting.ipv4AddressConstruct(ipv4address, netMask, gateWay, dnsList); + setting.dumpInfo(); + isChanged = true; + } + } + return isChanged; +} + +bool Ipv4Page::checkConnectBtnIsEnabled() +{ + qDebug() << "checkConnectBtnIsEnabled currentIndex" << ipv4ConfigCombox->currentIndex(); + if (ipv4ConfigCombox->currentIndex() == AUTO_CONFIG) { + return true; + } else { + if (ipv4addressEdit->text().isEmpty() || !getTextEditState(ipv4addressEdit->text())) { + qDebug() << "ipv4address empty or invalid"; + return false; + } + + if (netMaskEdit->text().isEmpty() || !netMaskIsValide(netMaskEdit->text())) { + qDebug() << "ipv4 netMask empty or invalid"; + return false; + } + +// if (gateWayEdit->text().isEmpty() || !getTextEditState(gateWayEdit->text())) { +// qDebug() << "ipv4 gateway empty or invalid"; +// return false; +// } + + if (firstDnsEdit->text().isEmpty() && !secondDnsEdit->text().isEmpty()) { + qDebug() << "ipv4 dns sort invalid"; + return false; + } + + if (!getTextEditState(firstDnsEdit->text())) { + qDebug() << "ipv4 first dns invalid"; + return false; + } + + if (!getTextEditState(secondDnsEdit->text())) { + qDebug() << "ipv4 second dns invalid"; + return false; + } + } + return true; +} + +void Ipv4Page::configChanged(int index) { + if (index == AUTO_CONFIG) { + setLineEnabled(false); + } + if (index == MANUAL_CONFIG) { + setLineEnabled(true); + } +} + +void Ipv4Page::onAddressTextChanged() +{ + m_iconLabel->hide(); + m_textLabel->hide(); + + if (!getTextEditState(ipv4addressEdit->text())) { + m_addressHintLabel->setText(tr("Invalid address")); + } else { + m_addressHintLabel->clear(); + } +} + +void Ipv4Page::onNetMaskTextChanged() +{ + if (!netMaskIsValide(netMaskEdit->text())) { + m_maskHintLabel->setText(tr("Invalid subnet mask")); + } else { + m_maskHintLabel->clear(); + } +} + +void Ipv4Page::onAddressEidtFinished() +{ + if (ipv4addressEdit->isModified()) { + if (!ipv4addressEdit->text().isEmpty() && getTextEditState(ipv4addressEdit->text())) { + Q_EMIT ipv4EditFinished(ipv4addressEdit->text()); + } + } +} + +void Ipv4Page::setLineEnabled(bool check) { + + if (!check) { + ipv4addressEdit->clear(); + netMaskEdit->clear(); + gateWayEdit->clear(); + firstDnsEdit->clear(); + secondDnsEdit->clear(); + + ipv4addressEdit->setPlaceholderText(" "); + netMaskEdit->setPlaceholderText(" "); + + } else { + ipv4addressEdit->setPlaceholderText(tr("Required")); //必填 + netMaskEdit->setPlaceholderText(tr("Required")); //必填 + } + + ipv4addressEdit->setEnabled(check); + netMaskEdit->setEnabled(check); + gateWayEdit->setEnabled(check); + firstDnsEdit->setEnabled(check); + secondDnsEdit->setEnabled(check); +} + +void Ipv4Page::setEnableOfSaveBtn() { + Q_EMIT setIpv4PageState(checkConnectBtnIsEnabled()); +} + +bool Ipv4Page::getTextEditState(QString text) +{ + if (text.isEmpty()) { + return true; + } + QRegExp rx("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b"); + + bool match = false; + match = rx.exactMatch(text); + + return match; +} + +bool Ipv4Page::netMaskIsValide(QString text) +{ + if (getTextEditState(text)) { + return true; + } else { + if (text.length() > 0 && text.length() < 3) { + int num = text.toInt(); + if (num > 0 && num < 33) { + return true; + } + } + } + return false; +} + +QString Ipv4Page::getNetMaskText(QString text) +{ + if (text.length() > 2) { + return text; + } + + int num = text.toInt(); + QStringList list; + list << "0" << "0" << "0" << "0"; + int count = 0; + while (num - 8 >= 0) { + list[count] = "255"; + num = num - 8; + count ++; + } + if (num > 0) { + int size = pow(2, 8) - pow(2,(8-num)); + list[count] = QString::number(size); + } + return QString("%1.%2.%3.%4").arg(list[0],list[1],list[2],list[3]); +} + + +void Ipv4Page::initConflictHintLable() +{ + QIcon icon = QIcon::fromTheme("dialog-warning"); + m_iconLabel = new QLabel(m_addressHintLabel); + m_iconLabel->setPixmap(icon.pixmap(ICON_SIZE)); + m_textLabel = new QLabel(m_addressHintLabel); + m_textLabel->setText(tr("Address conflict")); + QHBoxLayout *conflictHintLayout = new QHBoxLayout(m_addressHintLabel); + conflictHintLayout->setContentsMargins(0, 0, 0, 0); + conflictHintLayout->addWidget(m_iconLabel); + conflictHintLayout->addWidget(m_textLabel); + conflictHintLayout->addStretch(); + m_addressHintLabel->setLayout(conflictHintLayout); + m_iconLabel->hide(); + m_textLabel->hide(); +} + +void Ipv4Page::initLoadingIcon() +{ + m_loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic")); + m_iconTimer = new QTimer(this); + connect(m_iconTimer, &QTimer::timeout, this, &Ipv4Page::updateIcon); +} + +void Ipv4Page::updateIcon() +{ + if (m_currentIconIndex > 6) { + m_currentIconIndex = 0; + } + m_statusLabel->setPixmap(m_loadIcons.at(m_currentIconIndex).pixmap(ICON_SIZE)); + m_currentIconIndex ++; +} + +void Ipv4Page::startLoading() +{ + m_iconTimer->start(FRAME_SPEED); +} + +void Ipv4Page::stopLoading() +{ + m_iconTimer->stop(); + m_statusLabel->clear(); +} + +void Ipv4Page::showIpv4AddressConflict(bool isConflict) +{ + if (isConflict) { + m_iconLabel->show(); + m_textLabel->show(); + } else { + m_iconLabel->hide(); + m_textLabel->hide(); + } +} diff --git a/src/frontend/netdetails/ipv4page.h b/src/frontend/netdetails/ipv4page.h new file mode 100644 index 00000000..f5e9a779 --- /dev/null +++ b/src/frontend/netdetails/ipv4page.h @@ -0,0 +1,111 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef IPV4PAGE_H +#define IPV4PAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "kylinconnectsetting.h" +#include "coninfo.h" + +class Ipv4Page : public QFrame +{ + Q_OBJECT +public: + Ipv4Page(QWidget *parent = nullptr); + void setIpv4Config(KyIpConfigType ipv4Config); + void setIpv4(const QString &ipv4); + void setNetMask(const QString &netMask); + void setIpv4FirDns(const QString &ipv4FirDns); + void setIpv4SecDns(const QString &ipv4SecDns); + void setGateWay(const QString &gateWay); + + bool checkIsChanged(const ConInfo info, KyConnectSetting &setting); + + void startLoading(); + void stopLoading(); + void showIpv4AddressConflict(bool isConflict); + +private: + QComboBox *ipv4ConfigCombox; + LineEdit *ipv4addressEdit; + LineEdit *netMaskEdit; + LineEdit *gateWayEdit; + LineEdit *firstDnsEdit; + LineEdit *secondDnsEdit; + + QFormLayout *m_detailLayout; + QVBoxLayout *mvBoxLayout; + QLabel *m_configLabel; + QLabel *m_addressLabel; + QLabel *m_maskLabel; + QLabel *m_gateWayLabel; + QLabel *m_dnsLabel; + QLabel *m_secDnsLabel; + + QLabel *m_configEmptyLabel; + QLabel *m_addressHintLabel; + QLabel *m_maskHintLabel; + QLabel *m_gateWayEmptyLabel; + QLabel *m_firstDnsEmptyLabel; + + QLabel *m_statusLabel = nullptr; + QList m_loadIcons; + QTimer *m_iconTimer = nullptr; + int m_currentIconIndex =0; + + QLabel *m_iconLabel; + QLabel *m_textLabel; + +private: + void initUI(); + void initComponent(); + void setLineEnabled(bool check); + void configSave(); + bool getTextEditState(QString text); + bool netMaskIsValide(QString text); + QString getNetMaskText(QString text); + bool checkConnectBtnIsEnabled(); + void initConflictHintLable(); + void initLoadingIcon(); + +private Q_SLOTS: + void setEnableOfSaveBtn(); + void configChanged(int index); + void onAddressTextChanged(); + void onNetMaskTextChanged(); + void onAddressEidtFinished(); + void updateIcon(); + +Q_SIGNALS: + void setIpv4PageState(bool); + void ipv4EditFinished(const QString &address); +}; + +#endif // IPV4PAGE_H diff --git a/src/frontend/netdetails/ipv6page.cpp b/src/frontend/netdetails/ipv6page.cpp new file mode 100644 index 00000000..cfa568ac --- /dev/null +++ b/src/frontend/netdetails/ipv6page.cpp @@ -0,0 +1,435 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "ipv6page.h" +#include "netdetail.h" + +#define LAYOUT_MARGINS 0,0,0,0 +#define LAYOUT_SPACING 0 +#define HINT_TEXT_MARGINS 8, 1, 0, 3 +#define LABEL_HEIGHT 24 +#define FRAME_SPEED 150 +#define ICON_SIZE 16,16 + +Ipv6Page::Ipv6Page(QWidget *parent):QFrame(parent) +{ + initUI(); + initComponent(); +} + +void Ipv6Page::setIpv6Config(KyIpConfigType ipv6Config) +{ + if (ipv6Config == CONFIG_IP_MANUAL) { + ipv6ConfigCombox->setCurrentIndex(MANUAL_CONFIG); + } else { + ipv6ConfigCombox->setCurrentIndex(AUTO_CONFIG); + } +} + +void Ipv6Page::setIpv6(const QString &ipv6) +{ + ipv6AddressEdit->setText(ipv6); +} + +void Ipv6Page::setIpv6Perfix(const int &ipv6Perfix) +{ + lengthEdit->setText(QString::number(ipv6Perfix)); +} + +void Ipv6Page::setIpv6FirDns(const QString &ipv6FirDns) +{ + firstDnsEdit->setText(ipv6FirDns); +} + +void Ipv6Page::setIpv6SecDns(const QString &ipv6SecDns) +{ + secondDnsEdit->setText(ipv6SecDns); +} + +void Ipv6Page::setGateWay(const QString &gateWay) +{ + gateWayEdit->setText(gateWay); +} + +bool Ipv6Page::checkIsChanged(const ConInfo info, KyConnectSetting &setting) +{ + bool isChanged = false; + if (ipv6ConfigCombox->currentIndex() == AUTO_CONFIG) { + if (info.ipv6ConfigType != CONFIG_IP_DHCP) { + qDebug() << "ipv6ConfigType change to Auto"; + setting.setIpConfigType(IPADDRESS_V6, CONFIG_IP_DHCP); + QString ipv6address(""); + QString prefix(""); + QString gateWay(""); + QStringList dnsList; + dnsList.empty(); + setting.ipv6AddressConstruct(ipv6address, prefix, gateWay, dnsList); + isChanged = true; + } + } else { + if (info.ipv6ConfigType != CONFIG_IP_MANUAL) { + qDebug() << "ipv6ConfigType change to Manual"; + setting.setIpConfigType(IPADDRESS_V6, CONFIG_IP_MANUAL); + isChanged = true; + } + if(info.strIPV6Address != ipv6AddressEdit->text() + || info.iIPV6Prefix != lengthEdit->text().toInt() + || info.strIPV6GateWay != gateWayEdit->text() + || info.strIPV6FirDns != firstDnsEdit->text() + || info.strIPV6SecDns != secondDnsEdit->text()) { + + qDebug() << "ipv6 info changed"; + QStringList dnsList; + dnsList.empty(); + if (!firstDnsEdit->text().isEmpty()) { + dnsList << firstDnsEdit->text(); + if (!secondDnsEdit->text().isEmpty()) { + dnsList << secondDnsEdit->text(); + } + } + + QString ipv6address =ipv6AddressEdit->text(); + QString prefix = lengthEdit->text(); + QString gateWay = gateWayEdit->text(); + setting.ipv6AddressConstruct(ipv6address, prefix, gateWay, dnsList); + setting.dumpInfo(); + isChanged = true; + } + } + return isChanged; +} + +void Ipv6Page::initUI() { + ipv6ConfigCombox = new QComboBox(this); + ipv6AddressEdit = new LineEdit(this); + lengthEdit = new LineEdit(this); + gateWayEdit = new LineEdit(this); + firstDnsEdit = new LineEdit(this); + secondDnsEdit = new LineEdit(this); + + m_configLabel = new QLabel(this); + m_addressLabel = new QLabel(this); + m_subnetLabel = new QLabel(this); + m_gateWayLabel = new QLabel(this); + m_dnsLabel = new QLabel(this); + m_secDnsLabel = new QLabel(this); + + m_configEmptyLabel = new QLabel(this); + m_configEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + m_addressHintLabel = new QLabel(this); + m_addressHintLabel->setFixedHeight(LABEL_HEIGHT); + m_addressHintLabel->setContentsMargins(HINT_TEXT_MARGINS); + initConflictHintLable(); + + m_gateWayHintLabel = new QLabel(this); + m_gateWayHintLabel->setFixedHeight(LABEL_HEIGHT); + m_gateWayHintLabel->setContentsMargins(HINT_TEXT_MARGINS); + + m_subnetEmptyLabel = new QLabel(this); + m_subnetEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + m_firstDnsEmptyLabel = new QLabel(this); + m_firstDnsEmptyLabel->setFixedHeight(LABEL_HEIGHT); + + + m_configLabel->setText(tr("IPv6Config")); + m_addressLabel->setText(tr("Address")); + m_subnetLabel->setText(tr("Subnet prefix Length")); + m_gateWayLabel->setText(tr("Default Gateway")); + m_dnsLabel->setText(tr("Prefs DNS")); + m_secDnsLabel->setText(tr("Alternative DNS")); + + m_statusLabel = new QLabel(this); + m_statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + QHBoxLayout *pPwdLayout = new QHBoxLayout(ipv6AddressEdit); + pPwdLayout->addStretch(); + pPwdLayout->addWidget(m_statusLabel); + + QPalette hintTextColor; + hintTextColor.setColor(QPalette::WindowText, Qt::red); + m_addressHintLabel->setPalette(hintTextColor); + m_gateWayHintLabel->setPalette(hintTextColor); + + QWidget *addressWidget = new QWidget(this); + QVBoxLayout *addressLayout = new QVBoxLayout(addressWidget); + addressLayout->setContentsMargins(LAYOUT_MARGINS); + addressLayout->setSpacing(LAYOUT_SPACING); + addressLayout->addWidget(ipv6AddressEdit); + addressLayout->addWidget(m_addressHintLabel); + + QWidget *gateWayWidget = new QWidget(this); + QVBoxLayout *gateWayLayout = new QVBoxLayout(gateWayWidget); + gateWayLayout->setContentsMargins(LAYOUT_MARGINS); + gateWayLayout->setSpacing(LAYOUT_SPACING); + gateWayLayout->addWidget(gateWayEdit); + gateWayLayout->addWidget(m_gateWayHintLabel); + + m_detailLayout = new QFormLayout(this); + m_detailLayout->setContentsMargins(0, 0, 0, 0); + m_detailLayout->setVerticalSpacing(0); + m_detailLayout->addRow(m_configLabel,ipv6ConfigCombox); + m_detailLayout->addRow(m_configEmptyLabel); + m_detailLayout->addRow(m_addressLabel,addressWidget); + m_detailLayout->addRow(m_subnetLabel,lengthEdit); + m_detailLayout->addRow(m_subnetEmptyLabel); + m_detailLayout->addRow(m_gateWayLabel,gateWayWidget); + m_detailLayout->addRow(m_dnsLabel,firstDnsEdit); + m_detailLayout->addRow(m_firstDnsEmptyLabel); + m_detailLayout->addRow(m_secDnsLabel,secondDnsEdit); + + ipv6ConfigCombox->addItem(tr("Auto(DHCP)")); //"自动(DHCP)" + ipv6ConfigCombox->addItem(tr("Manual")); //"手动" + + QRegExp ipv6_rx("^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$"); + ipv6AddressEdit->setValidator(new QRegExpValidator(ipv6_rx, this)); + gateWayEdit->setValidator(new QRegExpValidator(ipv6_rx, this)); + firstDnsEdit->setValidator(new QRegExpValidator(ipv6_rx, this)); + secondDnsEdit->setValidator(new QRegExpValidator(ipv6_rx, this)); + + QRegExp prefix_rx("\\b(?:(?:12[0-8]|1[0-1][0-9]|^[1-9][0-9]?$)\\.){3}(?:12[0-8]|1[0-1][0-9]|^[1-9][0-9]?$)\\b"); + lengthEdit->setValidator(new QRegExpValidator(prefix_rx,this)); + + initLoadingIcon(); +} + +void Ipv6Page::initComponent() { + if (ipv6ConfigCombox->currentIndex() == AUTO_CONFIG) { + setControlEnabled(false); + } else if (ipv6ConfigCombox->currentIndex() == MANUAL_CONFIG) { + setControlEnabled(true); + } + connect(ipv6ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(configChanged(int))); + + connect(ipv6AddressEdit, SIGNAL(textChanged(QString)), this, SLOT(onAddressTextChanged())); + connect(ipv6AddressEdit, SIGNAL(editingFinished()), this, SLOT(onAddressEidtFinished())); + connect(gateWayEdit, SIGNAL(textChanged(QString)), this, SLOT(onGatewayTextChanged())); + + connect(ipv6ConfigCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEnableOfSaveBtn())); + connect(ipv6AddressEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(lengthEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(gateWayEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(firstDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(secondDnsEdit, SIGNAL(textChanged(QString)), this, SLOT(setEnableOfSaveBtn())); +} + +void Ipv6Page::configChanged(int index) { + if (index == AUTO_CONFIG) { + setControlEnabled(false); + } + if (index == MANUAL_CONFIG) { + setControlEnabled(true); + } +} + +void Ipv6Page::setControlEnabled(bool check) +{ + if (!check) { + ipv6AddressEdit->clear(); + lengthEdit->clear(); + gateWayEdit->clear(); + firstDnsEdit->clear(); + secondDnsEdit->clear(); + + ipv6AddressEdit->setPlaceholderText(" "); + lengthEdit->setPlaceholderText(" "); + gateWayEdit->setPlaceholderText(" "); + } else { + ipv6AddressEdit->setPlaceholderText(tr("Required")); //必填 + lengthEdit->setPlaceholderText(tr("Required")); //必填 + gateWayEdit->setPlaceholderText(tr("Required")); //必填 + } + + ipv6AddressEdit->setEnabled(check); + lengthEdit->setEnabled(check); + gateWayEdit->setEnabled(check); + firstDnsEdit->setEnabled(check); + secondDnsEdit->setEnabled(check); +} + +void Ipv6Page::setEnableOfSaveBtn() +{ + Q_EMIT setIpv6PageState(checkConnectBtnIsEnabled()); +} + +void Ipv6Page::onAddressTextChanged() +{ + m_iconLabel->hide(); + m_textLabel->hide(); + + if (!getIpv6EditState(ipv6AddressEdit->text())) { + m_addressHintLabel->setText(tr("Invalid address")); + } else { + m_addressHintLabel->clear(); + } +} + +void Ipv6Page::onGatewayTextChanged() +{ + if (!getIpv6EditState(gateWayEdit->text())) { + m_gateWayHintLabel->setText(tr("Invalid gateway")); + } else { + m_gateWayHintLabel->clear(); + } +} + +void Ipv6Page::onAddressEidtFinished() +{ + if (ipv6AddressEdit->isModified()) { + if (!ipv6AddressEdit->text().isEmpty() && getIpv6EditState(ipv6AddressEdit->text())) { + Q_EMIT ipv6EditFinished(ipv6AddressEdit->text()); + } + } +} + +bool Ipv6Page::checkConnectBtnIsEnabled() +{ + if (ipv6ConfigCombox->currentIndex() == AUTO_CONFIG) { + return true; + } else { + if (ipv6AddressEdit->text().isEmpty() || !getIpv6EditState(ipv6AddressEdit->text())) { + qDebug() << "ipv6address empty or invalid"; + return false; + } + + if (lengthEdit->text().isEmpty()) { + qDebug() << "ipv6 prefix length empty"; + return false; + } + + if (gateWayEdit->text().isEmpty() || !getIpv6EditState(gateWayEdit->text())) { + qDebug() << "ipv6 gateway empty or invalid"; + return false; + } + + if (firstDnsEdit->text().isEmpty() && !secondDnsEdit->text().isEmpty()) { + qDebug() << "ipv6 dns sort invalid"; + return false; + } + + if (!getIpv6EditState(firstDnsEdit->text())) { + qDebug() << "ipv6 first dns invalid"; + return false; + } + + if (!getIpv6EditState(secondDnsEdit->text())) { + qDebug() << "ipv6 second dns invalid"; + return false; + } + } + return true; +} + +void Ipv6Page::initConflictHintLable() +{ + QIcon icon = QIcon::fromTheme("dialog-warning"); + m_iconLabel = new QLabel(m_addressHintLabel); + m_iconLabel->setPixmap(icon.pixmap(ICON_SIZE)); + m_textLabel = new QLabel(m_addressHintLabel); + m_textLabel->setText(tr("Address conflict")); + QHBoxLayout *conflictHintLayout = new QHBoxLayout(m_addressHintLabel); + conflictHintLayout->setContentsMargins(0, 0, 0, 0); + conflictHintLayout->addWidget(m_iconLabel); + conflictHintLayout->addWidget(m_textLabel); + conflictHintLayout->addStretch(); + m_addressHintLabel->setLayout(conflictHintLayout); + m_iconLabel->hide(); + m_textLabel->hide(); +} + +bool Ipv6Page::getIpv6EditState(QString text) +{ + if (text.isEmpty()) { + return true; + } + QRegExp rx("^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$"); + + bool match = false; + match = rx.exactMatch(text); + + return match; +} + +int Ipv6Page::getPerfixLength(QString text) +{ + qDebug() << "getPerfixLength" << text; + int length = 0; + QStringList list= text.split(":"); + for (int i = 0; i < list.size(); ++i) { + QString temp = list.at(i); + if (temp.isEmpty()) { + continue; + } + bool ok; + unsigned int val = temp.toUInt(&ok, 16); + temp = temp.setNum(val,2); + for(int j = 0; j < temp.length(); ++j) { + if (temp.at(j) == "1") { + length++; + } + } + } + qDebug() << "getPerfixLength" << length; + return length; +} + +void Ipv6Page::initLoadingIcon() +{ + m_loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic")); + m_loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic")); + m_iconTimer = new QTimer(this); + connect(m_iconTimer, &QTimer::timeout, this, &Ipv6Page::updateIcon); +} + +void Ipv6Page::updateIcon() +{ + if (m_currentIconIndex > 6) { + m_currentIconIndex = 0; + } + m_statusLabel->setPixmap(m_loadIcons.at(m_currentIconIndex).pixmap(ICON_SIZE)); + m_currentIconIndex ++; +} + +void Ipv6Page::startLoading() +{ + m_iconTimer->start(FRAME_SPEED); +} + +void Ipv6Page::stopLoading() +{ + m_iconTimer->stop(); + m_statusLabel->clear(); +} + +void Ipv6Page::showIpv6AddressConflict(bool isConflict) +{ + if (isConflict) { + m_iconLabel->show(); + m_textLabel->show(); + } else { + m_iconLabel->hide(); + m_textLabel->hide(); + } +} + diff --git a/src/frontend/netdetails/ipv6page.h b/src/frontend/netdetails/ipv6page.h new file mode 100644 index 00000000..a36265df --- /dev/null +++ b/src/frontend/netdetails/ipv6page.h @@ -0,0 +1,111 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef IPV6PAGE_H +#define IPV6PAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "kylinconnectsetting.h" +#include "coninfo.h" + +class Ipv6Page : public QFrame +{ + Q_OBJECT +public: + Ipv6Page(QWidget *parent = nullptr); + void setIpv6Config(KyIpConfigType ipv6Config); + void setIpv6(const QString &ipv4); + void setIpv6Perfix(const int &ipv6Perfix); + void setIpv6FirDns(const QString &ipv6FirDns); + void setIpv6SecDns(const QString &ipv6SecDns); + void setGateWay(const QString &gateWay); + + bool checkIsChanged(const ConInfo info, KyConnectSetting &setting); + + int getPerfixLength(QString text); + + void startLoading(); + void stopLoading(); + void showIpv6AddressConflict(bool isConflict); + +public: + QComboBox *ipv6ConfigCombox; + LineEdit *ipv6AddressEdit; + LineEdit *lengthEdit; + LineEdit *gateWayEdit; + LineEdit *firstDnsEdit; + LineEdit *secondDnsEdit; +private: + QFormLayout *m_detailLayout; + QLabel *m_configLabel; + QLabel *m_addressLabel; + QLabel *m_subnetLabel; + QLabel *m_gateWayLabel; + QLabel *m_dnsLabel; + QLabel *m_secDnsLabel; + + QLabel *m_configEmptyLabel; + QLabel *m_addressHintLabel; + QLabel *m_subnetEmptyLabel; + QLabel *m_gateWayHintLabel; + QLabel *m_firstDnsEmptyLabel; + + QLabel *m_statusLabel = nullptr; + QList m_loadIcons; + QTimer *m_iconTimer = nullptr; + int m_currentIconIndex =0; + + QLabel *m_iconLabel; + QLabel *m_textLabel; +private: + void initUI(); + void initComponent(); + void setControlEnabled(bool check); + + bool getIpv6EditState(QString text); + + bool checkConnectBtnIsEnabled(); + + void initConflictHintLable(); + void initLoadingIcon(); + +private Q_SLOTS: + void configChanged(int index); + void setEnableOfSaveBtn(); + void onAddressTextChanged(); + void onGatewayTextChanged(); + void onAddressEidtFinished(); + void updateIcon(); + +Q_SIGNALS: + void setIpv6PageState(bool); + void ipv6EditFinished(const QString &address); +}; + +#endif // IPV6PAGE_H diff --git a/src/frontend/netdetails/joinhiddenwifipage.cpp b/src/frontend/netdetails/joinhiddenwifipage.cpp new file mode 100644 index 00000000..c9d3b174 --- /dev/null +++ b/src/frontend/netdetails/joinhiddenwifipage.cpp @@ -0,0 +1,274 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "joinhiddenwifipage.h" + +#include + +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" +#define WINDOW_WIDTH 480 +#define MIN_WINDOW_HEIGHT 368 +#define PEAP_WINDOW_HEIGHT 524 +#define TLS_WINDOW_HEIGHT 580 +#define LAYOUT_MARGINS 0, 0, 0, 0 +#define TOP_LAYOUT_MARGINS 24, 12, 24, 16 +#define CENTER_LAYOUT_MARGINS 24, 0, 24, 8 +#define BOTTOM_LAYOUT_MARGINS 24, 24, 24, 24 +#define LAYOUT_SPACING 16 +#define LABEL_MIN_WIDTH 146 +#define MAX_NAME_LENGTH 32 +#define PSK_SCRO_HEIGHT 182 +#define PEAP_SCRO_HEIGHT 340 +#define TLS_SCRO_HEIGHT 560 +#define MEDIUM_WEIGHT_VALUE 57 + +JoinHiddenWiFiPage::JoinHiddenWiFiPage(QString devName, KDialog *parent) + :m_devName(devName), + KDialog(parent) +{ + m_wirelessConnOpration = new KyWirelessConnectOperation(this); + + initUI(); + initComponent(); + + setFixedWidth(WINDOW_WIDTH); + setAttribute(Qt::WA_DeleteOnClose); + + setJoinBtnEnable(); +} + +JoinHiddenWiFiPage::~JoinHiddenWiFiPage() +{ + +} + +void JoinHiddenWiFiPage::closeEvent(QCloseEvent *event) +{ + Q_EMIT this->hiddenWiFiPageClose(m_devName); + return QWidget::closeEvent(event); +} + +void JoinHiddenWiFiPage::initUI() +{ + m_topWidget = new QWidget(this); + m_centerWidget = new QWidget(this); + m_bottomWidget = new QWidget(this); + m_secuWidget = new SecurityPage(false, this); + m_secuWidget->setSecurity(KySecuType::WPA_AND_WPA2_PERSONAL); + + m_descriptionLabel = new QLabel(this); + m_nameLabel = new FixLabel(this); + m_nameLabel->setFixedWidth(LABEL_MIN_WIDTH); + m_nameEdit =new LineEdit(this); + + m_bottomDivider = new Divider(this); + m_showListBtn = new KBorderlessButton(this); + m_cancelBtn =new QPushButton(this); + m_joinBtn =new QPushButton(this); + + m_hiddenWifiScrollArea = new QScrollArea(this); + m_hiddenWifiScrollArea->setFrameShape(QFrame::NoFrame); + m_hiddenWifiScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + QPalette pa = m_hiddenWifiScrollArea->palette(); + pa.setBrush(QPalette::Window, Qt::transparent); + m_hiddenWifiScrollArea->setPalette(pa); + + m_pageLayout = new QVBoxLayout(this); + m_pageLayout->setContentsMargins(LAYOUT_MARGINS); + m_pageLayout->setSpacing(0); + m_pageLayout->addWidget(m_topWidget); + m_pageLayout->addWidget(m_hiddenWifiScrollArea); + m_pageLayout->addWidget(m_bottomDivider); + m_pageLayout->addWidget(m_bottomWidget); + this->mainWidget()->setLayout(m_pageLayout); + + m_topLayout = new QHBoxLayout(m_topWidget); + m_topLayout->setContentsMargins(TOP_LAYOUT_MARGINS); + m_topLayout->setSpacing(0); + m_topLayout->addWidget(m_descriptionLabel); + m_topLayout->addStretch(); + + QWidget *ssidWidget = new QWidget(this); + QHBoxLayout *ssidLayout = new QHBoxLayout(ssidWidget); + ssidLayout->setContentsMargins(LAYOUT_MARGINS); + ssidLayout->setSpacing(0); + m_nameLabel->setMinimumWidth(LABEL_MIN_WIDTH); + ssidLayout->addWidget(m_nameLabel); + ssidLayout->addWidget(m_nameEdit); + + m_centerVBoxLayout = new QVBoxLayout(m_centerWidget); + m_centerVBoxLayout->setContentsMargins(CENTER_LAYOUT_MARGINS); + m_centerVBoxLayout->setSpacing(0); + m_centerVBoxLayout->addWidget(ssidWidget); + m_centerVBoxLayout->addSpacing(LAYOUT_SPACING); + m_centerVBoxLayout->addWidget(m_secuWidget); + m_centerVBoxLayout->addStretch(); + m_hiddenWifiScrollArea->setWidget(m_centerWidget); + + //底部按钮 + m_bottomLayout = new QHBoxLayout(m_bottomWidget); + m_bottomLayout->setContentsMargins(BOTTOM_LAYOUT_MARGINS); + m_bottomLayout->setSpacing(LAYOUT_SPACING); + m_bottomLayout->addWidget(m_showListBtn); + m_bottomLayout->addStretch(); + m_bottomLayout->addWidget(m_cancelBtn); + m_bottomLayout->addWidget(m_joinBtn); + + //请输入您想要加入网络的名称和安全类型 + m_descriptionLabel->setText(tr("Please enter the network name and security type")); + QFont font = m_descriptionLabel->font(); + font.setWeight(MEDIUM_WEIGHT_VALUE); + m_descriptionLabel->setFont(font); + + m_nameLabel->setLabelText(tr("Network name(SSID)")); //网络名(SSID) + m_showListBtn->setText(tr("Show Network List")); //显示网络列表 + m_cancelBtn->setText(tr("Cancel")); + m_joinBtn->setText(tr("Join")); + + m_nameEdit->setMaxLength(MAX_NAME_LENGTH); + m_nameEdit->setPlaceholderText(tr("Required")); //必填 + + this->setWindowTitle(tr("Find and Join Wi-Fi")); + this->setWindowIcon(QIcon::fromTheme("kylin-network")); + + this->setFixedHeight(MIN_WINDOW_HEIGHT); + onPaletteChanged(); +} + +void JoinHiddenWiFiPage::initComponent() +{ + connect(m_cancelBtn, &QPushButton::clicked, this, [=] { + close(); + }); + + connect(m_joinBtn, SIGNAL(clicked()), this, SLOT(onBtnJoinClicked())); + connect(m_showListBtn, SIGNAL(clicked()), this, SLOT(onBtnShowListClicked())); + + connect(m_secuWidget, &SecurityPage::secuTypeChanged, this, &JoinHiddenWiFiPage::onSecuTypeChanged); + connect(m_secuWidget, &SecurityPage::eapTypeChanged, this, &JoinHiddenWiFiPage::onEapTypeChanged); + connect(m_secuWidget, &SecurityPage::setSecuPageState, this, [ = ](bool status) { + m_isSecuOk = status; + setJoinBtnEnable(); + }); + connect(m_nameEdit, &LineEdit::textChanged, this, &JoinHiddenWiFiPage::setJoinBtnEnable); + + connect(qApp, &QApplication::paletteChanged, this, &JoinHiddenWiFiPage::onPaletteChanged); + + const QByteArray id(THEME_SCHAME); + if(QGSettings::isSchemaInstalled(id)){ + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("themeColor" == key) { + onPaletteChanged(); + } + }); + } +} + +void JoinHiddenWiFiPage::setJoinBtnEnable() +{ + if (!m_nameEdit->text().isEmpty() && m_isSecuOk) { + m_isJoinBtnEnable = true; + } else { + m_isJoinBtnEnable = false; + } + m_joinBtn->setEnabled(m_isJoinBtnEnable); +} + +void JoinHiddenWiFiPage::onBtnJoinClicked() +{ + KyWirelessConnectSetting connSettingInfo; + //基本信息 + connSettingInfo.m_ssid = m_nameEdit->text(); + connSettingInfo.setConnectName(connSettingInfo.m_ssid); + connSettingInfo.setIfaceName(m_devName); + connSettingInfo.m_secretFlag = 0; + + KySecuType secuType; + KyEapMethodType eapType; + m_secuWidget->getSecuType(secuType, eapType); + + if (secuType == WPA_AND_WPA2_ENTERPRISE) { + if (eapType == TLS) { + m_info.tlsInfo.devIfaceName = m_devName; + m_secuWidget->updateTlsChange(m_info.tlsInfo); + m_wirelessConnOpration->addAndActiveWirelessEnterPriseTlsConnect(m_info.tlsInfo, connSettingInfo, m_devName, true); + } else if (eapType == PEAP) { + m_secuWidget->updatePeapChange(m_info.peapInfo); + m_wirelessConnOpration->addAndActiveWirelessEnterPrisePeapConnect(m_info.peapInfo, connSettingInfo, m_devName, true); + } else if (eapType = TTLS) { + m_secuWidget->updateTtlsChange(m_info.ttlsInfo); + m_wirelessConnOpration->addAndActiveWirelessEnterPriseTtlsConnect(m_info.ttlsInfo, connSettingInfo, m_devName, true); + } + } else { + m_secuWidget->updateSecurityChange(connSettingInfo); + m_wirelessConnOpration->addAndActiveWirelessConnect(m_devName, connSettingInfo, true); + } + + close(); +} + +void JoinHiddenWiFiPage::onBtnShowListClicked() +{ + Q_EMIT showWlanList(1); //WLAN_PAGE_INDEX +} + +void JoinHiddenWiFiPage::onSecuTypeChanged(const KySecuType &type) +{ + if (type != KySecuType::WPA_AND_WPA2_ENTERPRISE) { + this->setFixedHeight(MIN_WINDOW_HEIGHT); + m_centerWidget->setFixedSize(WINDOW_WIDTH, PSK_SCRO_HEIGHT); + } +} + +void JoinHiddenWiFiPage::onEapTypeChanged(const KyEapMethodType &type) +{ + if (type == KyEapMethodType::TLS) { + this->setFixedHeight(TLS_WINDOW_HEIGHT); + m_centerWidget->setFixedSize(WINDOW_WIDTH, TLS_SCRO_HEIGHT); + } else if (type == KyEapMethodType::PEAP || type == KyEapMethodType::TTLS) { + this->setFixedHeight(PEAP_WINDOW_HEIGHT); + m_centerWidget->setFixedSize(WINDOW_WIDTH, PEAP_SCRO_HEIGHT); + } +} + +void JoinHiddenWiFiPage::onPaletteChanged() +{ + QPalette pal = qApp->palette(); + + QGSettings * styleGsettings = nullptr; + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + styleGsettings = new QGSettings(style_id); + QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); + if(currentTheme == "ukui-default"){ + pal = lightPalette(this); + } + } + this->setPalette(pal); + setFramePalette(m_secuWidget, pal); + setFramePalette(m_hiddenWifiScrollArea, pal); + + if (styleGsettings != nullptr) { + delete styleGsettings; + styleGsettings = nullptr; + } +} + diff --git a/src/frontend/netdetails/joinhiddenwifipage.h b/src/frontend/netdetails/joinhiddenwifipage.h new file mode 100644 index 00000000..662905a4 --- /dev/null +++ b/src/frontend/netdetails/joinhiddenwifipage.h @@ -0,0 +1,95 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef JOINHIDDENWIFIPAGE_H +#define JOINHIDDENWIFIPAGE_H + +#include +#include +#include +#include + +#include "coninfo.h" +#include "kywirelessconnectoperation.h" +#include "securitypage.h" +#include "divider.h" +#include "kwidget.h" +#include "kdialog.h" +#include "kborderlessbutton.h" + +using namespace kdk; + +class JoinHiddenWiFiPage : public KDialog +{ + Q_OBJECT + +public: + JoinHiddenWiFiPage(QString devName, KDialog *parent = nullptr); + ~JoinHiddenWiFiPage(); + +protected: + void closeEvent(QCloseEvent *event); + +private: + void initUI(); + void initComponent(); + + void setJoinBtnEnable(); + +private: + KyWirelessConnectOperation *m_wirelessConnOpration = nullptr; + QString m_devName; + + QWidget *m_topWidget; + QWidget *m_centerWidget; + QWidget *m_bottomWidget; + SecurityPage *m_secuWidget; + + QLabel *m_descriptionLabel; + FixLabel *m_nameLabel; + LineEdit *m_nameEdit; + + Divider *m_bottomDivider = nullptr; + KBorderlessButton *m_showListBtn; + QPushButton *m_cancelBtn; + QPushButton *m_joinBtn; + + QScrollArea *m_hiddenWifiScrollArea; + QVBoxLayout *m_pageLayout; + QHBoxLayout *m_topLayout; + QVBoxLayout *m_centerVBoxLayout; + QHBoxLayout *m_bottomLayout; + + bool m_isJoinBtnEnable = false; + bool m_isSecuOk = false; + ConInfo m_info; + +private Q_SLOTS: + void onBtnJoinClicked(); + void onBtnShowListClicked(); + void onSecuTypeChanged(const KySecuType &type); + void onEapTypeChanged(const KyEapMethodType &type); + void onPaletteChanged(); + +Q_SIGNALS: + void hiddenWiFiPageClose(QString); + void showWlanList(int type); +}; + +#endif // JOINHIDDENWIFIPAGE_H diff --git a/src/frontend/netdetails/netdetail.cpp b/src/frontend/netdetails/netdetail.cpp new file mode 100644 index 00000000..30e47900 --- /dev/null +++ b/src/frontend/netdetails/netdetail.cpp @@ -0,0 +1,1210 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "netdetail.h" +#include "backend/kylinipv4arping.h" +#include "backend/kylinipv6arping.h" +//#include "xatom/xatom-helper.h" +#include "networkmodeconfig.h" + + +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" + +#include +#include +#include +#include + +#include "windowmanager/windowmanager.h" + +#define WINDOW_WIDTH 520 +#define WINDOW_HEIGHT 602 +#define ICON_SIZE 22,22 +#define TITLE_LAYOUT_MARGINS 9,9,0,0 +#define CENTER_LAYOUT_MARGINS 24,0,0,0 +#define BOTTOM_LAYOUT_MARGINS 24,0,24,0 +#define BOTTOM_LAYOUT_SPACING 16 +#define PAGE_LAYOUT_SPACING 1 +#define DETAIL_PAGE_NUM 0 +#define IPV4_PAGE_NUM 1 +#define IPV6_PAGE_NUM 2 +#define SECURITY_PAGE_NUM 3 +#define CONFIG_PAGE_NUM 4 +#define CREATE_NET_PAGE_NUM 5 +#define PAGE_MIN_HEIGHT 40 +#define LAN_TAB_WIDTH 180 +#define WLAN_TAB_WIDTH 240 +#define SCRO_WIDTH 472 +#define PEAP_SCRO_HEIGHT 300 +#define TLS_SCRO_HEIGHT 480 +#define MAX_TAB_TEXT_LENGTH 44 + +//extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); + +void NetDetail::showDesktopNotify(const QString &message, QString soundName) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QStringList actions; //跳转动作 + actions.append("kylin-nm"); + actions.append("default"); //默认动作:点击消息体时打开麒麟录音 + QMap hints; + if (!soundName.isEmpty()) { + hints.insert("sound-name", soundName); //添加声音 + } + QList args; + args<<(tr("Kylin NM")) + <<((unsigned int) 0) + <setEnabled(on); + ipv4Page->setEnabled(on); + ipv6Page->setEnabled(on); + securityPage->setEnabled(on); + createNetPage->setEnabled(on); + cancelBtn->setEnabled(on); + forgetBtn->setEnabled(on); + confimBtn->setEnabled(on); +} + +void NetDetail::startObjectThread() +{ + m_objectThread = new QThread(); + m_object = new ThreadObject(m_deviceName); + m_object->moveToThread(m_objectThread); + connect(m_objectThread, &QThread::finished, m_objectThread, &QObject::deleteLater); + connect(m_objectThread, &QThread::finished, m_object, &QObject::deleteLater); + connect(ipv4Page, &Ipv4Page::ipv4EditFinished, this, [=](){ + ipv4Page->startLoading(); + }); + connect(ipv6Page, &Ipv6Page::ipv6EditFinished, this, [=](){ + ipv6Page->startLoading(); + }); + + connect(ipv4Page, SIGNAL(ipv4EditFinished(const QString &)), m_object, SLOT(checkIpv4ConflictThread(const QString &))); + connect(ipv6Page, SIGNAL(ipv6EditFinished(const QString &)), m_object, SLOT(checkIpv6ConflictThread(const QString &))); + connect(this, SIGNAL(checkCurrentIpv4Conflict(const QString &)), m_object, SLOT(checkIpv4ConflictThread(const QString &))); + connect(this, SIGNAL(checkCurrentIpv6Conflict(const QString &)), m_object, SLOT(checkIpv6ConflictThread(const QString &))); + + connect(m_object, &ThreadObject::ipv4IsConflict, this, [=](bool ipv4IsConf) { + ipv4Page->stopLoading(); + ipv4Page->showIpv4AddressConflict(ipv4IsConf); + }); + connect(m_object, &ThreadObject::ipv6IsConflict, this, [=](bool ipv6IsConf) { + ipv6Page->stopLoading(); + ipv6Page->showIpv6AddressConflict(ipv6IsConf); + }); + + m_objectThread->start(); +} + +NetDetail::NetDetail(QString interface, QString name, QString uuid, bool isActive, bool isWlan, bool isCreateNet, QWidget *parent) + :m_deviceName(interface), + m_name(name), + m_uuid(uuid), + isActive(isActive), + isWlan(isWlan), + m_isCreateNet(isCreateNet), + QWidget(parent) +{ + //设置窗口无边框,阴影 +//#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +// MotifWmHints window_hints; +// window_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; +// window_hints.functions = MWM_FUNC_ALL; +// window_hints.decorations = MWM_DECOR_BORDER; +// XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), window_hints); +//#else +// this->setWindowFlags(Qt::Dialog /*| Qt::FramelessWindowHint*/); + this->setWindowFlag(Qt::Window); +//#endif +// this->setProperty("useStyleWindowManager", false); //禁用拖动 +// setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint ); +// setAttribute(Qt::WA_TranslucentBackground); + setAttribute(Qt::WA_DeleteOnClose); + setFixedSize(WINDOW_WIDTH,WINDOW_HEIGHT); + centerToScreen(); + + qDebug() << m_isCreateNet << name; + if (!m_isCreateNet && name.isEmpty()) { + m_isCreateNet = true; + } + qDebug() << m_isCreateNet; + m_netDeviceResource = new KyNetworkDeviceResourse(this); + m_wirelessConnOpration = new KyWirelessConnectOperation(this); + m_resource = new KyWirelessNetResource(this); + m_connectOperation = new KyConnectOperation(this); + m_wiredConnOperation = new KyWiredConnectOperation(this); + initUI(); + loadPage(); + initComponent(); + getConInfo(m_info); + startObjectThread(); + pagePadding(name,isWlan); + setSecuPageHeight(); + connect(qApp, &QApplication::paletteChanged, this, &NetDetail::onPaletteChanged); + + isCreateOk = !(m_isCreateNet && !isWlan); + isDetailOk = !(m_name.isEmpty()); + isIpv4Ok = true; + isIpv6Ok = true; + isSecuOk = false; + if (!m_uuid.isEmpty() || (m_uuid.isEmpty() && m_info.secType == NONE)) { + isSecuOk = true; + } + + qDebug() << interface << name << uuid << "isWlan" << isWlan << "isCreateNet" <isRunning()) { + m_objectThread->quit(); + m_objectThread->wait(); + } +} + +void NetDetail::onPaletteChanged() +{ + QPalette pal = qApp->palette(); + + QGSettings * styleGsettings = nullptr; + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + styleGsettings = new QGSettings(style_id); + QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); + if(currentTheme == "ukui-default"){ + pal = lightPalette(this); + } + } + pal.setColor(QPalette::Background, pal.base().color()); + this->setPalette(pal); + + setFramePalette(detailPage, pal); + setFramePalette(ipv4Page, pal); + setFramePalette(ipv6Page, pal); + setFramePalette(securityPage, pal); + setFramePalette(createNetPage, pal); + QToolTip::setPalette(pal); + + QPalette listwidget_pal(detailPage->m_listWidget->palette()); + listwidget_pal.setColor(QPalette::Base, pal.base().color()); + listwidget_pal.setColor(QPalette::AlternateBase, pal.alternateBase().color()); + detailPage->m_listWidget->setAlternatingRowColors(true); + detailPage->m_listWidget->setPalette(listwidget_pal); + + if (styleGsettings != nullptr) { + delete styleGsettings; + styleGsettings = nullptr; + } +} + +void NetDetail::currentRowChangeSlot(int row) +{ + if (isActive) { + if (row < 3) { + stackWidget->setCurrentIndex(row); + } else { + if(isWlan) { + stackWidget->setCurrentIndex(row); + } else { + stackWidget->setCurrentIndex(CONFIG_PAGE_NUM); + } + } + } else { + stackWidget->setCurrentIndex(row); + } +} + +void NetDetail::paintEvent(QPaintEvent *event) +{ +// QPalette pal = qApp->palette(); +// QPainter painter(this); +// painter.setBrush(pal.color(QPalette::Base)); +// painter.drawRect(this->rect()); +// painter.fillRect(rect(), QBrush(pal.color(QPalette::Base))); + + return QWidget::paintEvent(event); +} + +void NetDetail::closeEvent(QCloseEvent *event) +{ + Q_EMIT this->detailPageClose(false); + Q_EMIT this->createPageClose(m_deviceName); + return QWidget::closeEvent(event); +} + +void NetDetail::centerToScreen() +{ + QDesktopWidget* m = QApplication::desktop(); + QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos())); + int desk_x = desk_rect.width(); + int desk_y = desk_rect.height(); + int x = this->width(); + int y = this->height(); + this->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top()); +// kdk::WindowManager::setGeometry(this->windowHandle(), QRect(desk_x / 2 - x / 2 + desk_rect.left(), +// desk_y / 2 - y / 2 + desk_rect.top(), +// this->width(), +// this->height())); +} + +void NetDetail::initUI() +{ + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0,9,0,24); + mainLayout->setSpacing(24); + + detailPage = new DetailPage(isWlan, m_name.isEmpty(), this); + + ipv4Page = new Ipv4Page(this); + ipv6Page = new Ipv6Page(this); + securityPage = new SecurityPage(this); + createNetPage = new CreatNetPage(this); + configPage = new ConfigPage(this); + + this->installEventFilter(this); + + centerWidget = new QWidget(this); + bottomWidget = new QWidget(this); + + m_secuPageScrollArea = new QScrollArea(this); + m_secuPageScrollArea->setFrameShape(QFrame::NoFrame); + m_secuPageScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_secuPageScrollArea->setWidget(securityPage); + QPalette pal = m_secuPageScrollArea->palette(); + pal.setBrush(QPalette::Base, QColor(0,0,0,0)); + m_secuPageScrollArea->setPalette(pal); + + detailPage->setFixedWidth(SCRO_WIDTH); + ipv4Page->setFixedWidth(SCRO_WIDTH); + ipv6Page->setFixedWidth(SCRO_WIDTH); + createNetPage->setFixedWidth(SCRO_WIDTH); + configPage->setFixedWidth(SCRO_WIDTH); + + stackWidget = new QStackedWidget(centerWidget); + stackWidget->addWidget(detailPage); + stackWidget->addWidget(ipv4Page); + stackWidget->addWidget(ipv6Page); + stackWidget->addWidget(m_secuPageScrollArea); + stackWidget->addWidget(configPage); + stackWidget->addWidget(createNetPage); + + mainLayout->addWidget(centerWidget); + mainLayout->addWidget(bottomWidget); + + bottomWidget->setMinimumHeight(PAGE_MIN_HEIGHT); + + pageFrame = new QFrame(this); + QHBoxLayout *pageLayout = new QHBoxLayout(pageFrame); +// pageLayout->setSpacing(PAGE_LAYOUT_SPACING); + + // TabBar + onPaletteChanged(); + m_netTabBar = new NetTabBar(this); + m_netTabBar->addTab(tr("Detail")); //详情 + m_netTabBar->addTab(tr("IPv4"));//Ipv4 + m_netTabBar->addTab(tr("IPv6"));//Ipv6 + if (isWlan) { + m_netTabBar->addTab(tr("Security"));//安全 + if (isActive) { + m_netTabBar->addTab(tr("Config")); //配置 + m_netTabBar->setFixedWidth(WLAN_TAB_WIDTH + TAB_WIDTH); + } else { + m_netTabBar->setFixedWidth(WLAN_TAB_WIDTH); + } + } else { + if (isActive) { + m_netTabBar->addTab(tr("Config")); //配置 + m_netTabBar->setFixedWidth(LAN_TAB_WIDTH + TAB_WIDTH); + } else { + m_netTabBar->setFixedWidth(LAN_TAB_WIDTH); + } + } + + pageLayout->addWidget(m_netTabBar, Qt::AlignCenter); + pageLayout->addSpacing(24); + + // TabBar关联选项卡页面 + connect(m_netTabBar, SIGNAL(currentChanged(int)), this, SLOT(currentRowChangeSlot(int))); + setNetTabToolTip(); + + confimBtn = new QPushButton(this); + confimBtn->setText(tr("Confirm")); + + cancelBtn = new QPushButton(this); + cancelBtn->setText(tr("Cancel")); + + forgetBtn = new QPushButton(this); + + QVBoxLayout *centerlayout = new QVBoxLayout(centerWidget); + centerlayout->setContentsMargins(CENTER_LAYOUT_MARGINS); // 右边距为0,为安全页滚动区域留出空间 + centerlayout->addWidget(pageFrame); + centerlayout->addSpacing(4); + centerlayout->addWidget(stackWidget); + + QHBoxLayout *bottomLayout = new QHBoxLayout(bottomWidget); + bottomLayout->setContentsMargins(BOTTOM_LAYOUT_MARGINS); + bottomLayout->setSpacing(BOTTOM_LAYOUT_SPACING); + bottomLayout->addWidget(forgetBtn); + bottomLayout->addStretch(); + bottomLayout->addWidget(cancelBtn); + bottomLayout->addWidget(confimBtn); + +// QPalette pal(this->palette()); +// pal.setColor(QPalette::Background, qApp->palette().base().color()); + this->setAutoFillBackground(true); +// this->setPalette(pal); +} + +void NetDetail::loadPage() +{ + //判断是否创建网络页面 + if (m_isCreateNet && !isWlan) { + pageFrame->hide(); + stackWidget->setCurrentIndex(CREATE_NET_PAGE_NUM); + this->setWindowTitle(tr("Add Lan Connect")); + } else { + stackWidget->setCurrentIndex(DETAIL_PAGE_NUM); + this->setWindowTitle(m_name); + if (isWlan && m_name.isEmpty()) { + this->setWindowTitle(tr("connect hiddin wlan")); + } + } +} + +void NetDetail::initComponent() +{ + connect(cancelBtn, &QPushButton::clicked, this, [=] { + close(); + }); + + connect(confimBtn, SIGNAL(clicked()), this, SLOT(on_btnConfirm_clicked())); + if (!m_uuid.isEmpty()) { + if (isWlan) { + forgetBtn->setText(tr("Forget this network")); + } else { + forgetBtn->setText(tr("Delete this network")); + } + forgetBtn->show(); + connect(forgetBtn, SIGNAL(clicked()), this, SLOT(on_btnForget_clicked())); + } else { + forgetBtn->hide(); + } + + connect(createNetPage, &CreatNetPage::setCreatePageState, this, [=](bool status) { + isCreateOk = status; + setConfirmEnable(); + }); + + connect(detailPage, &DetailPage::setDetailPageState, this, [=](bool status) { + isDetailOk = status; + setConfirmEnable(); + }); + + connect(ipv4Page, &Ipv4Page::setIpv4PageState, this, [=](bool status) { + isIpv4Ok = status; + setConfirmEnable(); + }); + + connect(ipv6Page, &Ipv6Page::setIpv6PageState, this, [=](bool status) { + isIpv6Ok = status; + setConfirmEnable(); + }); + + connect(securityPage, &SecurityPage::setSecuPageState, this, [=](bool status) { + isSecuOk = status; + setConfirmEnable(); + }); + + connect(securityPage, &SecurityPage::secuTypeChanged, this, [=]() { + setSecuPageHeight(); + }); + connect(securityPage, &SecurityPage::eapTypeChanged, this, [=]() { + setSecuPageHeight(); + }); + + const QByteArray id(THEME_SCHAME); + if(QGSettings::isSchemaInstalled(id)){ + QGSettings * fontSetting = new QGSettings(id, QByteArray(), this); + connect(fontSetting, &QGSettings::changed,[=](QString key) { + if ("systemFont" == key || "systemFontSize" ==key) { + setNetTabToolTip(); + } else if ("themeColor" == key) { + onPaletteChanged(); + } + }); + } +} + +void NetDetail::pagePadding(QString netName, bool isWlan) +{ + //网络详情页填充 + if(m_isCreateNet && !isWlan) { + return; + } + + detailPage->setSSID(netName); + detailPage->setProtocol(m_info.strConType); + detailPage->setSecType(m_info.strSecType); + detailPage->setHz(m_info.strHz); + detailPage->setChan(m_info.strChan); + detailPage->setIpv4(m_info.strDynamicIpv4); + detailPage->setIpv4Dns(m_info.strDynamicIpv4Dns); + detailPage->setIpv6(m_info.strDynamicIpv6); + detailPage->setMac(m_info.strMac); + detailPage->setBandWidth(m_info.strBandWidth); + detailPage->setAutoConnect(m_info.isAutoConnect); + + //ipv4页面填充 + if (m_info.ipv4ConfigType == CONFIG_IP_MANUAL) { + Q_EMIT checkCurrentIpv4Conflict(m_info.strIPV4Address); + ipv4Page->setIpv4Config(m_info.ipv4ConfigType); + ipv4Page->setIpv4(m_info.strIPV4Address); + ipv4Page->setNetMask(m_info.strIPV4NetMask); + ipv4Page->setIpv4FirDns(m_info.strIPV4FirDns); + ipv4Page->setIpv4SecDns(m_info.strIPV4SecDns); + ipv4Page->setGateWay(m_info.strIPV4GateWay); + } else { + ipv4Page->setIpv4Config(m_info.ipv4ConfigType); + } + //ipv6页面填充 + if (m_info.ipv6ConfigType == CONFIG_IP_MANUAL) { + Q_EMIT checkCurrentIpv6Conflict(m_info.strIPV6Address); + ipv6Page->setIpv6Config(m_info.ipv6ConfigType); + ipv6Page->setIpv6(m_info.strIPV6Address); + ipv6Page->setIpv6Perfix(m_info.iIPV6Prefix); + ipv6Page->setIpv6FirDns(m_info.strIPV6FirDns); + ipv6Page->setIpv6SecDns(m_info.strIPV6SecDns); + ipv6Page->setGateWay(m_info.strIPV6GateWay); + } else { + ipv6Page->setIpv6Config(m_info.ipv6ConfigType); + } + + //安全页面 + if (isWlan) { + securityPage->setSecurity(m_info.secType); + qDebug() << "setSecurity" << m_info.secType; + if (m_info.secType == WPA_AND_WPA2_ENTERPRISE) { + if (m_info.enterpriseType == TLS) { + securityPage->setTlsInfo(m_info.tlsInfo); + } else if (m_info.enterpriseType == PEAP) { + securityPage->setPeapInfo(m_info.peapInfo); + } else if (m_info.enterpriseType == TTLS) { + securityPage->setTtlsInfo(m_info.ttlsInfo); + } + } + } + + //配置页面 + if (isActive) { + configPage->setConfigState(NetworkModeConfig::getInstance()->getNetworkModeConfig(m_uuid)); + } + +} + +//获取网路详情信息 +void NetDetail::getConInfo(ConInfo &conInfo) +{ + if (m_isCreateNet && !isWlan) { + return; + } + getBaseInfo(conInfo); + getDynamicIpInfo(conInfo, isActive); + getStaticIpInfo(conInfo,isActive); +} + + +//详情ssid 带宽 物理地址 无线额外(安全性 频带 通道) +void NetDetail::getBaseInfo(ConInfo &conInfo) +{ + //有线无线公有 + conInfo.strConName = m_name; + + QString hardAddress; + int bandWith; + m_netDeviceResource->getHardwareInfo(m_deviceName, hardAddress, bandWith); + + if (!hardAddress.isEmpty()) { + conInfo.strBandWidth = QString("%1").arg(bandWith/1000) + "Mbps"; + conInfo.strMac = hardAddress; + } + + if (!isWlan) { + conInfo.strConType = "802-3-ethernet"; + } else { + conInfo.strConType = "802-11-wireless"; + if (!isActive) { + KyWirelessNetItem item; + if (!m_resource->getWifiNetwork(m_deviceName, m_name, item)) { + qDebug() << "getWifiNetWork failed device:" << m_deviceName << " name:" << m_name; + return; + } else { + conInfo.strHz = QString::number(item.m_frequency); + conInfo.strChan = QString::number(item.m_channel); + //无线特有 + conInfo.strSecType = item.m_secuType; + if (conInfo.strSecType.isEmpty()) { + conInfo.strSecType = tr("None"); + } + + if (!item.m_isConfigured) { + conInfo.secType = item.m_kySecuType; + } + } + } else { + uint iHz,iChan; + QString strMac; + m_netDeviceResource->getDeviceActiveAPInfo(m_deviceName, strMac, iHz, iChan, conInfo.strSecType); + if (conInfo.strSecType.isEmpty()) { + conInfo.strSecType = tr("None"); + } + conInfo.strHz = QString::number(iHz); + conInfo.strChan = QString::number(iChan); + + } + + + + KyKeyMgmt type = m_wirelessConnOpration->getConnectKeyMgmt(m_uuid); + if (!m_uuid.isEmpty()) { + KyKeyMgmt type = m_wirelessConnOpration->getConnectKeyMgmt(m_uuid); + if (type == WpaNone || type == Unknown) { + conInfo.secType = NONE; + } else if (type == WpaPsk) { + conInfo.secType = WPA_AND_WPA2_PERSONAL; + } else if (type == SAE) { + conInfo.secType = WPA3_PERSONAL; + } else if (type == WpaEap) { + conInfo.secType = WPA_AND_WPA2_ENTERPRISE; + } else { + qDebug() << "KeyMgmt not support now " << type; + } + } + + initSecuData(); + } +} + +//详情ipv4 ipv6 ipv4Dns +void NetDetail::getDynamicIpInfo(ConInfo &conInfo, bool bActived) +{ + if (!bActived) { + return; + } + //已激活的网络 详情页显示动态ipv4 ipv6 dns + QString ipv4,ipv6; + QList ipv4Dns,ipv6Dns; + KyActiveConnectResourse *activeResourse = new KyActiveConnectResourse(this); + activeResourse->getActiveConnectIpInfo(m_uuid,ipv4,ipv6); + activeResourse->getActiveConnectDnsInfo(m_uuid,ipv4Dns,ipv6Dns); + + //Ipv6 + if (!ipv6.isEmpty()) { + conInfo.strDynamicIpv6 = ipv6; + } + + //IPv4 + if (!ipv4.isEmpty()) { + conInfo.strDynamicIpv4 = ipv4; + } + + if (!ipv4Dns.isEmpty()) { + conInfo.strDynamicIpv4Dns = ipv4Dns.at(0).toString(); + } +} + +//ipv4+ipv6页面 +void NetDetail::getStaticIpInfo(ConInfo &conInfo, bool bActived) +{ + KyConnectResourse *kyConnectResourse = new KyConnectResourse(this); + KyConnectSetting connetSetting; + kyConnectResourse->getConnectionSetting(m_uuid,connetSetting); + connetSetting.dumpInfo(); + + conInfo.ipv4ConfigType = connetSetting.m_ipv4ConfigIpType; + conInfo.ipv6ConfigType = connetSetting.m_ipv6ConfigIpType; + conInfo.isAutoConnect = connetSetting.m_isAutoConnect; + + if (connetSetting.m_ipv4ConfigIpType == CONFIG_IP_MANUAL) { + if (connetSetting.m_ipv4Address.size() > 0) { + conInfo.strIPV4Address = connetSetting.m_ipv4Address.at(0).ip().toString(); + conInfo.strIPV4NetMask = connetSetting.m_ipv4Address.at(0).netmask().toString(); + conInfo.strIPV4GateWay = connetSetting.m_ipv4Address.at(0).gateway().toString(); + } + if (connetSetting.m_ipv4Dns.size() == 1) { + conInfo.strIPV4FirDns = connetSetting.m_ipv4Dns.at(0).toString(); + } else if (connetSetting.m_ipv4Dns.size() > 1) { + conInfo.strIPV4FirDns = connetSetting.m_ipv4Dns.at(0).toString(); + conInfo.strIPV4SecDns = connetSetting.m_ipv4Dns.at(1).toString(); + } + } + + if (connetSetting.m_ipv6ConfigIpType == CONFIG_IP_MANUAL) { + if (connetSetting.m_ipv6Address.size() > 0) { + conInfo.strIPV6Address = connetSetting.m_ipv6Address.at(0).ip().toString(); + conInfo.iIPV6Prefix = ipv6Page->getPerfixLength(connetSetting.m_ipv6Address.at(0).netmask().toString()); + conInfo.strIPV6GateWay = connetSetting.m_ipv6Address.at(0).gateway().toString(); + } + + if (connetSetting.m_ipv6Dns.size() == 1) { + conInfo.strIPV6FirDns = connetSetting.m_ipv6Dns.at(0).toString(); + } else if (connetSetting.m_ipv4Dns.size() > 1) { + conInfo.strIPV6FirDns = connetSetting.m_ipv6Dns.at(0).toString(); + conInfo.strIPV6SecDns = connetSetting.m_ipv6Dns.at(1).toString(); + } + } + + if (!bActived) { + conInfo.strDynamicIpv4 = conInfo.strIPV4Address.isEmpty() ? tr("Auto") : conInfo.strIPV4Address; + conInfo.strDynamicIpv6 = conInfo.strIPV6Address.isEmpty() ? tr("Auto") : conInfo.strIPV6Address; + conInfo.strDynamicIpv4Dns = conInfo.strIPV4FirDns.isEmpty() ? tr("Auto") : conInfo.strIPV4FirDns; + } +} + +void NetDetail::initSecuData() +{ + QString password(""); + int type = m_info.secType; + switch (type) { + case NONE: + break; + case WPA_AND_WPA2_PERSONAL: + case WPA3_PERSONAL: + if (!m_uuid.isEmpty()) { + NetworkManager::Setting::SecretFlags flag; + if (m_wirelessConnOpration->getConnSecretFlags(m_uuid, flag)) { + if (!flag) { + password = m_wirelessConnOpration->getPsk(m_uuid); + } + } + } + m_info.strPassword = password; + securityPage->setPsk(password); + break; + case WPA_AND_WPA2_ENTERPRISE: + if (!m_wirelessConnOpration->getEnterpiseEapMethod(m_uuid, m_info.enterpriseType)) { + qDebug() << m_name << "not enterprise wifi"; + } else if (m_info.enterpriseType == TLS){ + initTlsInfo(m_info); + } else if (m_info.enterpriseType == PEAP){ + initPeapInfo(m_info); + } else { + initTtlsInfo(m_info); + } + break; + default: + break; + } +} + +void NetDetail::setSecuPageHeight() +{ + KySecuType secuType; + KyEapMethodType eapType; + securityPage->getSecuType(secuType, eapType); + if (secuType == WPA_AND_WPA2_ENTERPRISE) { + if (eapType == TLS) { + securityPage->setFixedSize(SCRO_WIDTH, TLS_SCRO_HEIGHT); + } else { + securityPage->setFixedSize(SCRO_WIDTH, PEAP_SCRO_HEIGHT); + } + } else { + securityPage->setFixedSize(SCRO_WIDTH, PEAP_SCRO_HEIGHT); + } +} + +void NetDetail::initTlsInfo(ConInfo &conInfo) +{ + m_resource->getEnterPriseInfoTls(m_uuid, conInfo.tlsInfo); +} + +void NetDetail::initPeapInfo(ConInfo &conInfo) +{ + m_resource->getEnterPriseInfoPeap(m_uuid, conInfo.peapInfo); +} + +void NetDetail::initTtlsInfo(ConInfo &conInfo) +{ + m_resource->getEnterPriseInfoTtls(m_uuid, conInfo.ttlsInfo); +} + +//点击了保存更改网络设置的按钮 +void NetDetail::on_btnConfirm_clicked() +{ + qDebug() << "on_btnConfirm_clicked"; + setNetdetailSomeEnable(false); + if (m_isCreateNet) { + if (!isWlan) { + //新建有线连接 + qDebug() << "Confirm create wired connect"; + if (!createWiredConnect()) { + setNetdetailSomeEnable(true); + return; + } + } else { + //新建无线连接 + qDebug() << "Confirm create wireless connect"; + if (!createWirelessConnect()) { + setNetdetailSomeEnable(true); + return; + } + } + } else { + //更新连接 + qDebug() << "Confirm update connect"; + if (!updateConnect()) { + setNetdetailSomeEnable(true); + return; + } + } + close(); +} + +//点击忘记网络 +void NetDetail::on_btnForget_clicked() +{ + qDebug() << "user choose forget connection uuid = " << m_uuid; + m_connectOperation->deleteConnect(m_uuid); + close(); +} + +void NetDetail::setConfirmEnable() +{ + if (m_isCreateNet && !isWlan) { + isConfirmBtnEnable = isCreateOk; + } else { + if (isDetailOk && isIpv4Ok && isIpv6Ok) { + if (isWlan && !isSecuOk) { + isConfirmBtnEnable = false; + } else { + isConfirmBtnEnable = true; + } + } else { + isConfirmBtnEnable = false; + } + } + qDebug() << "setConfirmEnable "<< isConfirmBtnEnable; + confimBtn->setEnabled(isConfirmBtnEnable); +} + +#if 0 +bool NetDetail::checkIpv4Conflict(QString ipv4Address) +{ + showDesktopNotify(tr("start check ipv4 address conflict"), "networkwrong"); + bool isConflict = false; + KyIpv4Arping* ipv4Arping = new KyIpv4Arping(m_deviceName, ipv4Address); + + if (ipv4Arping->ipv4ConflictCheck() >= 0) { + isConflict = ipv4Arping->ipv4IsConflict(); + } else { + qWarning() << "checkIpv4Conflict internal error"; + } + + delete ipv4Arping; + ipv4Arping = nullptr; + return isConflict; +} + +bool NetDetail::checkIpv6Conflict(QString ipv6address) +{ + showDesktopNotify(tr("start check ipv6 address conflict"), "networkwrong"); + bool isConflict = false; + KyIpv6Arping* ipv46rping = new KyIpv6Arping(m_deviceName, ipv6address); + + if (ipv46rping->ipv6ConflictCheck() >= 0) { + isConflict = ipv46rping->ipv6IsConflict(); + } else { + qWarning() << "checkIpv6Conflict internal error"; + } + + delete ipv46rping; + ipv46rping = nullptr; + return isConflict; +} +#endif + +void NetDetail::updateWirelessPersonalConnect() +{ + KyWirelessConnectSetting setting; + securityPage->updateSecurityChange(setting); + bool isPwdChanged = !(m_info.strPassword == setting.m_psk); + m_wirelessConnOpration->updateWirelessPersonalConnect(m_uuid, setting, isPwdChanged); +} + +void NetDetail::updateWirelessEnterPriseConnect(KyEapMethodType enterpriseType) +{ + if (enterpriseType == TLS) { + m_info.tlsInfo.devIfaceName = m_deviceName; + securityPage->updateTlsChange(m_info.tlsInfo); + m_wirelessConnOpration->updateWirelessEnterPriseTlsConnect(m_uuid, m_info.tlsInfo); + } else if (enterpriseType == PEAP) { + securityPage->updatePeapChange(m_info.peapInfo); + m_wirelessConnOpration->updateWirelessEnterPrisePeapConnect(m_uuid, m_info.peapInfo); + } else if (enterpriseType == TTLS) { + securityPage->updateTtlsChange(m_info.ttlsInfo); + m_wirelessConnOpration->updateWirelessEnterPriseTtlsConnect(m_uuid, m_info.ttlsInfo); + } +} + +bool NetDetail::createWiredConnect() +{ + KyWirelessConnectSetting connetSetting; + connetSetting.setIfaceName(m_deviceName); + createNetPage->constructIpv4Info(connetSetting); +// if (connetSetting.m_ipv4ConfigIpType != CONFIG_IP_DHCP) { +// if (checkIpv4Conflict(connetSetting.m_ipv4Address.at(0).ip().toString())) { +// qDebug() << "ipv4 conflict"; +// showDesktopNotify(tr("ipv4 address conflict!"), "networkwrong"); +// return false; +// } +// } + m_wiredConnOperation->createWiredConnect(connetSetting); + return true; +} + +bool NetDetail::createWirelessConnect() +{ + KyWirelessConnectSetting connetSetting; + KySecuType secuType; + KyEapMethodType enterpriseType; + securityPage->getSecuType(secuType, enterpriseType); + //类型判断 + if (!m_name.isEmpty()) { + if (!checkWirelessSecurity(secuType)) { + return false; + } + } + + //基本信息 + QString ssid; + if (m_name.isEmpty()) { + detailPage->getSsid(ssid); + } else { + ssid = m_name; + } + connetSetting.setConnectName(ssid); + connetSetting.setIfaceName(m_deviceName); + if (detailPage->checkIsChanged(m_info)) { + connetSetting.isAutoConnect = !m_info.isAutoConnect; + } else { + connetSetting.isAutoConnect = m_info.isAutoConnect; + } + qDebug() << "isAutoConnect" << connetSetting.isAutoConnect; + connetSetting.m_ssid = ssid; +// connetSetting.m_secretFlag = NetworkManager::Setting::None; + //由于X.h的None与此处的None有歧义,此处直接使用值 + connetSetting.m_secretFlag = 0; + + //ipv4 & ipv6 + bool ipv4Change = ipv4Page->checkIsChanged(m_info, connetSetting); + bool ipv6Change = ipv6Page->checkIsChanged(m_info, connetSetting); + + connetSetting.dumpInfo(); + + qDebug() << "ipv4Changed" << ipv4Change << "ipv6Change" << ipv6Change; +// if (ipv4Change && connetSetting.m_ipv4ConfigIpType == CONFIG_IP_MANUAL) { +// if (checkIpv4Conflict(connetSetting.m_ipv4Address.at(0).ip().toString())) { +// qDebug() << "ipv4 conflict"; +// showDesktopNotify(tr("ipv4 address conflict!"), "networkwrong"); +// return false; +// } +// } + +// if (ipv6Change && connetSetting.m_ipv6ConfigIpType == CONFIG_IP_MANUAL) { +// if (checkIpv6Conflict(connetSetting.m_ipv6Address.at(0).ip().toString())) { +// qDebug() << "ipv6 conflict"; +// showDesktopNotify(tr("ipv6 address conflict!"), "networkwrong"); +// return false; +// } +// } + //wifi安全性 + if (secuType == WPA_AND_WPA2_ENTERPRISE) { + connetSetting.m_type = WpaEap; + if (enterpriseType == TLS) { + m_info.tlsInfo.devIfaceName = m_deviceName; + securityPage->updateTlsChange(m_info.tlsInfo); + if (!m_name.isEmpty()) { + qDebug() << "add new TLS connect"; + m_wirelessConnOpration->addTlsConnect(connetSetting, m_info.tlsInfo); + } else { + qDebug() << "addAndConnect TLS connect"; + m_wirelessConnOpration->addAndActiveWirelessEnterPriseTlsConnect(m_info.tlsInfo, connetSetting, m_deviceName, true); + } + } else if (enterpriseType == PEAP) { + securityPage->updatePeapChange(m_info.peapInfo); + if (!m_name.isEmpty()) { + qDebug() << "add new PEAP connect"; + m_wirelessConnOpration->addPeapConnect(connetSetting, m_info.peapInfo); + } else { + qDebug() << "addAndConnect PEAP connect"; + m_wirelessConnOpration->addAndActiveWirelessEnterPrisePeapConnect(m_info.peapInfo, connetSetting, m_deviceName, true); + } + } else if (enterpriseType == TTLS) { + securityPage->updateTtlsChange(m_info.ttlsInfo); + if (!m_name.isEmpty()) { + qDebug() << "add new TTLS connect"; + m_wirelessConnOpration->addTtlsConnect(connetSetting, m_info.ttlsInfo); + } else { + qDebug() << "addAndConnect TTLS connect"; + m_wirelessConnOpration->addAndActiveWirelessEnterPriseTtlsConnect(m_info.ttlsInfo, connetSetting, m_deviceName, true); + } + } + } else { + securityPage->updateSecurityChange(connetSetting); + if (!m_name.isEmpty()) { + qDebug() << "add new personal connect"; + m_wirelessConnOpration->addConnect(connetSetting); + } else { + qDebug() << "addAndConnect personal connect" << m_deviceName; + m_wirelessConnOpration->addAndActiveWirelessConnect(m_deviceName, connetSetting, true); + } + } + return true; +} + +bool NetDetail::updateConnect() +{ + KyConnectResourse *kyConnectResourse = new KyConnectResourse(this); + KyConnectSetting connetSetting; + KySecuType secuType; + KyEapMethodType enterpriseType; + kyConnectResourse->getConnectionSetting(m_uuid,connetSetting); + + bool securityChange = false; + if (isWlan) { + securityChange = securityPage->checkIsChanged(m_info); + if(securityChange) { + securityPage->getSecuType(secuType, enterpriseType); + if (!checkWirelessSecurity(secuType)) { + return false; + } + } + } + + if(!m_uuid.isEmpty() && detailPage->checkIsChanged(m_info)) { + m_wirelessConnOpration->setWirelessAutoConnect(m_uuid, !m_info.isAutoConnect); + } + + bool ipv4Change = ipv4Page->checkIsChanged(m_info, connetSetting); + bool ipv6Change = ipv6Page->checkIsChanged(m_info, connetSetting); + + qDebug() << "ipv4Changed" << ipv4Change << "ipv6Change" << ipv6Change; + +// if (ipv4Change && connetSetting.m_ipv4ConfigIpType == CONFIG_IP_MANUAL) { +// if (checkIpv4Conflict(connetSetting.m_ipv4Address.at(0).ip().toString())) { +// qDebug() << "ipv4 conflict"; +// showDesktopNotify(tr("ipv4 address conflict!"), "networkwrong"); +// return false; +// } +// } + +// if (ipv6Change && connetSetting.m_ipv6ConfigIpType == CONFIG_IP_MANUAL) { +// if (checkIpv6Conflict(connetSetting.m_ipv6Address.at(0).ip().toString())) { +// qDebug() << "ipv6 conflict"; +// showDesktopNotify(tr("ipv6 address conflict!"), "networkwrong"); +// return false; +// } +// } + + if (ipv4Change || ipv6Change) { + connetSetting.dumpInfo(); + m_wiredConnOperation->updateWiredConnect(m_uuid, connetSetting); + } + + qDebug() << "securityChange" << securityChange; + if (securityChange) { + if (secuType == WPA_AND_WPA2_ENTERPRISE) { + updateWirelessEnterPriseConnect(enterpriseType); + } else { + updateWirelessPersonalConnect(); + } + } + + if (ipv4Change || ipv6Change || securityChange) { + if (isActive) { + //信息变化 断开-重连 更新需要時間 不可以立即重連 +// sleep(1); + QEventLoop eventloop; + QTimer::singleShot(1000, &eventloop, SLOT(quit())); + eventloop.exec(); + m_wirelessConnOpration->activateConnection(m_uuid, m_deviceName); + } + } + + if (configPage != nullptr) { + int configType = NetworkModeConfig::getInstance()->getNetworkModeConfig(m_uuid); + bool configPageChange = configPage->checkIsChanged(configType); + int currentConfigType = configPage->getConfigState(); +// qDebug () << Q_FUNC_INFO << __LINE__<< configPageChange; + + if (configPageChange) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(m_uuid, m_deviceName, m_name, currentConfigType); +// qDebug () <type() == QEvent::KeyPress) { + QKeyEvent *mEvent = static_cast(event); + if (mEvent->key() == Qt::Key_Enter || mEvent->key() == Qt::Key_Return) { + if (confimBtn->isEnabled()) { + Q_EMIT confimBtn->clicked(); + } + return true; + } else if (mEvent->key() == Qt::Key_Escape) { + close(); + return true; + } + } + return QWidget::eventFilter(w, event); +} + +void NetDetail::setNetTabToolTip() +{ + int tabCount = m_netTabBar->count(); + for (int i = 0; i< tabCount; ++i) { + QFontMetrics fontMetrics(m_netTabBar->font()); + int fontSize = fontMetrics.width(m_netTabBar->tabText(i)); + if (fontSize > MAX_TAB_TEXT_LENGTH) { + m_netTabBar->setTabToolTip(i, m_netTabBar->tabText(i)); + } else { + m_netTabBar->setTabToolTip(i, ""); + } + } +} + +NetTabBar::NetTabBar(QWidget *parent) + :KTabBar(KTabBarStyle::SegmentDark, parent) +{ + +} + +NetTabBar::~NetTabBar() +{ + +} + +QSize NetTabBar::sizeHint() const +{ + return QSize(TAB_WIDTH, TAB_HEIGHT); +} + +QSize NetTabBar::minimumTabSizeHint(int index) const +{ + Q_UNUSED(index) + return QSize(TAB_WIDTH, TAB_HEIGHT); +} + + +ThreadObject::ThreadObject(QString deviceName, QObject *parent) + :m_devName(deviceName), QObject(parent) +{ + m_isStop = false; +} + +ThreadObject::~ThreadObject() +{ + +} + +void ThreadObject::stop() +{ + m_isStop = true; +} + +void ThreadObject::checkIpv4ConflictThread(const QString &ipv4Address) +{ + if (m_isStop) { + return; + } + bool isConflict = false; + KyIpv4Arping* ipv4Arping = new KyIpv4Arping(m_devName, ipv4Address); + if (ipv4Arping->ipv4ConflictCheck() >= 0) { + isConflict = ipv4Arping->ipv4IsConflict(); + } else { + qWarning() << "checkIpv4Conflict internal error"; + } + + delete ipv4Arping; + ipv4Arping = nullptr; + Q_EMIT ipv4IsConflict(isConflict); +} + +void ThreadObject::checkIpv6ConflictThread(const QString &ipv6Address) +{ + if (m_isStop) { + return; + } + bool isConflict = false; + KyIpv6Arping* ipv6rping = new KyIpv6Arping(m_devName, ipv6Address); + + if (ipv6rping->ipv6ConflictCheck() >= 0) { + isConflict = ipv6rping->ipv6IsConflict(); + } else { + qWarning() << "checkIpv6Conflict internal error"; + } + + delete ipv6rping; + ipv6rping = nullptr; + Q_EMIT ipv6IsConflict(isConflict); +} diff --git a/src/frontend/netdetails/netdetail.h b/src/frontend/netdetails/netdetail.h new file mode 100644 index 00000000..0d427e68 --- /dev/null +++ b/src/frontend/netdetails/netdetail.h @@ -0,0 +1,206 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef NETDETAIL_H +#define NETDETAIL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "detailpage.h" +#include "ipv4page.h" +#include "ipv6page.h" +#include "securitypage.h" +#include "creatnetpage.h" +#include "configpage.h" +#include "coninfo.h" +#include "tab-pages/tabpage.h" +#include "kwidget.h" +#include "ktabbar.h" + +using namespace kdk; + +#define TAB_WIDTH 60 +#define TAB_HEIGHT 36 + +class NetTabBar : public KTabBar +{ + Q_OBJECT +public: + explicit NetTabBar(QWidget *parent = nullptr); + ~NetTabBar(); + + QSize sizeHint() const; + QSize minimumTabSizeHint(int index) const; +}; +class ThreadObject : public QObject +{ + Q_OBJECT +public: + ThreadObject(QString deviceName, QObject *parent = nullptr); + ~ThreadObject(); + void stop(); +private: + QString m_devName; + volatile bool m_isStop; + +public Q_SLOTS: + void checkIpv4ConflictThread(const QString &ipv4Address); + void checkIpv6ConflictThread(const QString &ipv6Address); + +Q_SIGNALS: + bool ipv4IsConflict(bool isConflict); + bool ipv6IsConflict(bool isConflict); +}; + +class NetDetail : public QWidget +{ + Q_OBJECT + +public: + NetDetail(QString interface, QString name, QString uuid, bool isActive, bool isWlan, bool isCreateNet, QWidget *parent = nullptr); + ~NetDetail(); + + void paintEvent(QPaintEvent *event); + void closeEvent(QCloseEvent *event); + bool eventFilter(QObject *w, QEvent *event); + +private: + void initUI(); + void centerToScreen(); + void initComponent(); + void getConInfo(ConInfo &conInfo); + void loadPage(); + void pagePadding(QString netName, bool isWlan); + void initSecuData(); + void setSecuPageHeight(); + + void initTlsInfo(ConInfo &conInfo); + void initPeapInfo(ConInfo &conInfo); + void initTtlsInfo(ConInfo &conInfo); + + void updateWirelessPersonalConnect(); + void updateWirelessEnterPriseConnect(KyEapMethodType enterpriseType); + + //详情ssid 带宽 物理地址 无线额外(安全性 频带 通道) + void getBaseInfo(ConInfo &conInfo); + //详情ipv4 ipv6 ipv4Dns + void getDynamicIpInfo(ConInfo &conInfo, bool bActived); + //ipv4+ipv6页面 + void getStaticIpInfo(ConInfo &conInfo, bool bActived); + + void setConfirmEnable(); + +// bool checkIpv4Conflict(QString ipv4Address); +// bool checkIpv6Conflict(QString ipv6Address); + + bool createWiredConnect(); + bool createWirelessConnect(); + bool updateConnect(); + + bool checkWirelessSecurity(KySecuType secuType); + + void showDesktopNotify(const QString &message, QString soundName); + + void setNetdetailSomeEnable(bool on); + void startObjectThread(); + void setNetTabToolTip(); + +private: + KyNetworkDeviceResourse *m_netDeviceResource = nullptr; + KyConnectOperation* m_connectOperation = nullptr; + KyWirelessConnectOperation *m_wirelessConnOpration = nullptr; + KyWiredConnectOperation *m_wiredConnOperation = nullptr; + KyWirelessNetResource *m_resource = nullptr; + + QStackedWidget * stackWidget; + + DetailPage * detailPage; + Ipv4Page * ipv4Page; + Ipv6Page * ipv6Page; + SecurityPage * securityPage; + CreatNetPage * createNetPage; + ConfigPage * configPage; + + QWidget * centerWidget; + QWidget * bottomWidget; + QScrollArea * m_secuPageScrollArea; + + QPushButton * cancelBtn; + QPushButton * forgetBtn; + QPushButton * confimBtn; + + QFrame * pageFrame; + NetTabBar *m_netTabBar = nullptr; + + QString m_name; + QString m_uuid; + QString m_deviceName; + + bool isWlan; + bool m_isCreateNet; + bool isActive; + bool isHideWlan; + + bool isCreateOk; + bool isDetailOk; + bool isIpv4Ok; + bool isIpv6Ok; + bool isSecuOk; + bool isConfirmBtnEnable; + + ConInfo m_info; + + ThreadObject *m_object; + QThread *m_objectThread; + +private Q_SLOTS: + void on_btnConfirm_clicked(); + void on_btnForget_clicked(); + void onPaletteChanged(); + +protected Q_SLOTS: + void currentRowChangeSlot(int row); + +Q_SIGNALS: + void detailPageClose(bool on); + void createPageClose(QString); + void currentChanged(int); + void checkCurrentIpv4Conflict(const QString &address); + void checkCurrentIpv6Conflict(const QString &address); +}; + +#endif // NETDETAIL_H diff --git a/src/frontend/netdetails/netdetails.pri b/src/frontend/netdetails/netdetails.pri new file mode 100644 index 00000000..75657d5d --- /dev/null +++ b/src/frontend/netdetails/netdetails.pri @@ -0,0 +1,26 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/configpage.h \ + $$PWD/coninfo.h \ + $$PWD/creatnetpage.h \ + $$PWD/customtabstyle.h \ + $$PWD/detailpage.h \ + $$PWD/detailwidget.h \ + $$PWD/ipv4page.h \ + $$PWD/ipv6page.h \ + $$PWD/joinhiddenwifipage.h \ + $$PWD/netdetail.h \ + $$PWD/securitypage.h + +SOURCES += \ + $$PWD/configpage.cpp \ + $$PWD/creatnetpage.cpp \ + $$PWD/customtabstyle.cpp \ + $$PWD/detailpage.cpp \ + $$PWD/detailwidget.cpp \ + $$PWD/ipv4page.cpp \ + $$PWD/ipv6page.cpp \ + $$PWD/joinhiddenwifipage.cpp \ + $$PWD/netdetail.cpp \ + $$PWD/securitypage.cpp diff --git a/src/frontend/netdetails/securitypage.cpp b/src/frontend/netdetails/securitypage.cpp new file mode 100644 index 00000000..ee4c457d --- /dev/null +++ b/src/frontend/netdetails/securitypage.cpp @@ -0,0 +1,914 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "securitypage.h" +#include "netdetail.h" + +#include + +#define DETAIL_MIN_LABEL_WIDTH 80 +#define DETAIL_MIN_EDIT_WIDTH 390 +#define MIN_LABEL_WIDTH 146 +#define MIN_EDIT_WIDTH 278 + +SecurityPage::SecurityPage(bool isNetDetailPage, QWidget *parent) : isDetailPage(isNetDetailPage), QFrame(parent) +{ + initUI(); + initConnect(); +} + +void SecurityPage::initUI() +{ + mainLayout = new QVBoxLayout(this); + secuTypeLabel = new QLabel(this); + pwdLabel = new QLabel(this); + //企业wifi共有 + eapTypeLabel = new QLabel(this); + //TLS + identityLable = new QLabel(this); + domainLable = new QLabel(this); + caCertPathLabel = new QLabel(this); + caNeedFlagLabel = new QLabel(this); + clientCertPathLabel = new FixLabel(this); + clientCertPathLabel->setFixedWidth(MIN_LABEL_WIDTH); + clientPrivateKeyLabel = new FixLabel(this); + clientPrivateKeyLabel->setFixedWidth(MIN_LABEL_WIDTH); + clientPrivateKeyPwdLabel = new FixLabel(this); + clientPrivateKeyPwdLabel->setFixedWidth(MIN_LABEL_WIDTH); + pwdOptionLabel = new FixLabel(this); + pwdOptionLabel->setFixedWidth(MIN_LABEL_WIDTH); + + //PEAP TTLS共有 + eapMethodLabel = new FixLabel(this); + eapMethodLabel->setFixedWidth(MIN_LABEL_WIDTH); + userNameLabel = new QLabel(this); + userPwdLabel = new QLabel(this); + userPwdFlagLabel = new QLabel(this); + + secuTypeCombox = new QComboBox(this); + pwdEdit = new KPasswordEdit(this); + pwdEdit->setUseCustomPalette(true); + eapTypeCombox = new QComboBox(this); + //TLS + identityEdit = new LineEdit(this); + domainEdit = new LineEdit(this); + caCertPathCombox = new QComboBox(this); + caNeedBox = new QCheckBox(this); + clientCertPathCombox = new QComboBox(this); + clientPrivateKeyCombox = new QComboBox(this); + clientPrivateKeyPwdEdit = new KPasswordEdit(this); + clientPrivateKeyPwdEdit->setUseCustomPalette(true); + pwdOptionCombox = new QComboBox(this); + tlsWidget = new QWidget(this); + + //PEAP && TTLS + eapMethodCombox = new QComboBox(this); + userNameEdit = new LineEdit(this); + userPwdEdit = new KPasswordEdit(this); + userPwdEdit->setUseCustomPalette(true); + userPwdFlagBox = new QCheckBox(this); + + QWidget *queryWidget = new QWidget(this); + QHBoxLayout *queryLayout = new QHBoxLayout(queryWidget); + queryLayout->setContentsMargins(0, 0, 0, 0); + queryLayout->addWidget(userPwdFlagBox); + queryLayout->addWidget(userPwdFlagLabel); + queryLayout->addStretch(); + + //记住该网络复选框 + m_emptyLabel = new QLabel(this); + m_emptyLabel->setMinimumWidth(MIN_LABEL_WIDTH - 8); + m_checkLabel = new QLabel(this); + m_checkLabel->setText(tr("Remember the Network")); //记住该网络 + m_rememberCheckBox = new QCheckBox(this); + m_rememberCheckBox->setChecked(true); + QWidget *checkWidget = new QWidget(this); + QHBoxLayout *rememberLayout = new QHBoxLayout(checkWidget); + rememberLayout->setContentsMargins(0, 0, 0, 0); + rememberLayout->addWidget(m_emptyLabel); + rememberLayout->addWidget(m_rememberCheckBox); + rememberLayout->addWidget(m_checkLabel); + rememberLayout->addStretch(); + +// mSecuLayout = new QFormLayout(this); +// mSecuLayout->setContentsMargins(0, 0, 0, 0); +// mSecuLayout->addRow(secuTypeLabel, secuTypeCombox); +// mSecuLayout->addRow(pwdLabel, pwdEdit); +// mSecuLayout->addRow(eapTypeLabel, eapTypeCombox); +// mSecuLayout->addRow(identityLable, identityEdit); +// mSecuLayout->addRow(domainLable, domainEdit); +// mSecuLayout->addRow(caCertPathLabel, caCertPathCombox); +// mSecuLayout->addRow(caNeedBox, caNeedFlagLabel); +// mSecuLayout->addRow(clientCertPathLabel, clientCertPathCombox); +// mSecuLayout->addRow(clientPrivateKeyLabel, clientPrivateKeyCombox); +// mSecuLayout->addRow(clientPrivateKeyPwdLabel,clientPrivateKeyPwdEdit); +// mSecuLayout->addRow(eapMethodLabel, eapMethodCombox); +// mSecuLayout->addRow(userNameLabel, userNameEdit); +// mSecuLayout->addRow(userPwdLabel, userPwdEdit); +// mSecuLayout->addRow(userPwdFlagBox, userPwdFlagLabel); + + topLayout = new QGridLayout(); + topLayout->setContentsMargins(0, 0, 0, 0); + topLayout->setVerticalSpacing(16); + // 安全 Label和选项框 第0行,第0列,第1列 + topLayout->addWidget(secuTypeLabel, 0, 0); + topLayout->addWidget(secuTypeCombox, 0, 1); + //密码 Label和密码框 第1行,第0列,第1列 + topLayout->addWidget(pwdLabel, 1, 0); + topLayout->addWidget(pwdEdit, 1, 1); + // EAP认证 Label和选项框 第2行,第0列,第1列 + topLayout->addWidget(eapTypeLabel, 2, 0); + topLayout->addWidget(eapTypeCombox, 2, 1); + //内部认证 Label和选项框 第3行,第0列,第1列 + topLayout->addWidget(eapMethodLabel, 3, 0); + topLayout->addWidget(eapMethodCombox, 3, 1); + //用户名 Label和输入框 第4行,第0列,第1列 + topLayout->addWidget(userNameLabel, 4, 0); + topLayout->addWidget(userNameEdit, 4, 1); + //密码 Label和密码框 第5行,第0列,第1列 + topLayout->addWidget(userPwdLabel, 5, 0); + topLayout->addWidget(userPwdEdit, 5, 1); + // 匿名身份 Label和输入框 第6行,第0列,第1列 + topLayout->addWidget(identityLable, 6, 0); + topLayout->addWidget(identityEdit, 6, 1); + + + // CA证书选项框及CheckBox布局 + QWidget *caWidget = new QWidget(this); + QGridLayout *checkLayout = new QGridLayout(caWidget); + checkLayout->setContentsMargins(0, 0, 0, 0); + checkLayout->setVerticalSpacing(0); + checkLayout->setColumnMinimumWidth(0, 16); + checkLayout->addWidget(caCertPathCombox, 0, 0, 1, 2); + checkLayout->addWidget(caNeedBox, 1, 0); + checkLayout->addWidget(caNeedFlagLabel, 1, 1); + + bottomLayout = new QGridLayout(tlsWidget); + bottomLayout->setContentsMargins(0, 0, 0, 0); + bottomLayout->setVerticalSpacing(8); + bottomLayout->setHorizontalSpacing(0); + // 域 Label和输入框 第0行,第0列,第1列 + bottomLayout->addWidget(domainLable, 0, 0); + bottomLayout->addWidget(domainEdit, 0, 1); + + // CA证书 Label第1行,第0列 + bottomLayout->addWidget(caCertPathLabel, 1, 0); + // CA证书选项框 不需要CA证书复选框 从第1行,第1列开始,占2行1列 + bottomLayout->addWidget(caWidget, 1, 1, 2, 1); + // 用户证书 Label和选项框 第3行,第0列,第1列 + bottomLayout->addWidget(clientCertPathLabel, 3, 0); + bottomLayout->addWidget(clientCertPathCombox, 3, 1); + // 用户私钥 Label和选项框 第4行,第0列,第1列 + bottomLayout->addWidget(clientPrivateKeyLabel, 4, 0); + bottomLayout->addWidget(clientPrivateKeyCombox, 4, 1); + // 私钥密码 Label和密码框 第5行,第0列,第1列 + bottomLayout->addWidget(clientPrivateKeyPwdLabel, 5, 0); + bottomLayout->addWidget(clientPrivateKeyPwdEdit, 5, 1); + // 密码选项 Label和选项框 第6行,第0列,第1列 + bottomLayout->addWidget(pwdOptionLabel, 6, 0); + bottomLayout->addWidget(pwdOptionCombox, 6, 1); + + if (isDetailPage) { + checkWidget->hide(); + topLayout->addWidget(queryWidget, 7, 1); + changeColumnWidthWithSecuType(); + } else { + queryWidget->hide(); + topLayout->setColumnMinimumWidth(0, MIN_LABEL_WIDTH); + topLayout->setColumnMinimumWidth(1, MIN_EDIT_WIDTH); + bottomLayout->setColumnMinimumWidth(0, MIN_LABEL_WIDTH - 8); + } + + topLayout->addWidget(tlsWidget, 7, 0, 6, 2); + + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + mainLayout->addLayout(topLayout); + mainLayout->addWidget(checkWidget); + mainLayout->addStretch(); + + secuTypeLabel->setText(tr("Security")); + pwdLabel->setText(tr("Password")); + pwdEdit->setPlaceholderText(hintRequired); + + //企业wifi共有 + eapTypeLabel->setText(tr("EAP type")); + //TLS + identityLable->setText(tr("Identity")); + domainLable->setText(tr("Domain")); + caCertPathLabel->setText(tr("CA certficate")); + caNeedFlagLabel->setText(tr("no need for CA certificate")); + clientCertPathLabel->setLabelText(tr("User certificate")); + clientPrivateKeyLabel->setLabelText(tr("User private key")); + clientPrivateKeyPwdLabel->setLabelText(tr("User key password")); + pwdOptionLabel->setLabelText(tr("Password options")); + identityEdit->setPlaceholderText(tr("Required")); + clientPrivateKeyPwdEdit->setPlaceholderText(hintRequired); + + //PEAP TTLS共有 + eapMethodLabel->setLabelText(tr("Ineer authentication")); + userNameLabel->setText(tr("Usename")); + userPwdLabel->setText(tr("Password")); + userPwdFlagLabel->setText(tr("Ask pwd each query")); + userNameEdit->setPlaceholderText(tr("Required")); + userPwdEdit->setPlaceholderText(hintRequired); + + secuTypeCombox->addItem(tr("None"),NONE); + secuTypeCombox->addItem(tr("WPA&WPA2 Personal"),WPA_AND_WPA2_PERSONAL); + secuTypeCombox->addItem(tr("WPA&WPA2 Enterprise"), WPA_AND_WPA2_ENTERPRISE); + secuTypeCombox->addItem(tr("WPA3 Personal"), WPA3_PERSONAL); + + eapTypeCombox->addItem("TLS", TLS); + eapTypeCombox->addItem("PEAP", PEAP); + eapTypeCombox->addItem("TTLS", TTLS); + eapTypeCombox->setCurrentIndex(TLS); + //TLS + caCertPathCombox->addItem(tr("None"), QString(tr("None"))); //无 + caCertPathCombox->addItem(tr("Choose from file..."), QString(tr("Choose from file..."))); //从文件中选择... + + clientCertPathCombox->addItem(tr("None"), QString(tr("None"))); //无 + clientCertPathCombox->addItem(tr("Choose from file..."), QString(tr("Choose from file..."))); //从文件中选择... + + clientPrivateKeyCombox->addItem(tr("None"), QString(tr("None"))); //无 + clientPrivateKeyCombox->addItem(tr("Choose from file..."), QString(tr("Choose from file..."))); //从文件中选择... + + //仅为该用户存储密码 + pwdOptionCombox->addItem(tr("Store passwords only for this user"), QString(tr("Store password only for this user"))); + //存储所有用户的密码 + pwdOptionCombox->addItem(tr("Store passwords for all users"), QString(tr("Store password for all users"))); + //每次询问这个密码 + pwdOptionCombox->addItem(tr("Ask this password every time"), QString(tr("Ask password every time"))); + pwdOptionCombox->setCurrentIndex(1); + + //禁用ClearBtn按钮 + pwdEdit->setClearButtonEnabled(false); + clientPrivateKeyPwdEdit->setClearButtonEnabled(false); + userPwdEdit->setClearButtonEnabled(false); + + QRegExp rx("^[A-Za-z0-9`~!@#$%^&*()_-+=<>,.\\\/]+$"); + QRegExpValidator *latitude = new QRegExpValidator(rx, this); + pwdEdit->setValidator(latitude); + clientPrivateKeyPwdEdit->setValidator(latitude); + userPwdEdit->setValidator(latitude); + + showNone(); +} + +void SecurityPage::initConnect() +{ + //安全类型变化 +// connect(secuTypeCombox, &QComboBox::currentTextChanged, this, &SecurityPage::onSecuTypeComboxIndexChanged); + connect(secuTypeCombox, QOverload::of(&QComboBox::currentIndexChanged), this, &SecurityPage::onSecuTypeComboxIndexChanged); + + connect(secuTypeCombox, QOverload::of(&QComboBox::currentIndexChanged), this, &SecurityPage::changeColumnWidthWithSecuType); + + //EAP方式变化 +// connect(eapTypeCombox, &QComboBox::currentTextChanged, this, &SecurityPage::onEapTypeComboxIndexChanged); + connect(eapTypeCombox, QOverload::of(&QComboBox::currentIndexChanged), this, &SecurityPage::onEapTypeComboxIndexChanged); + + connect(caNeedBox, &QCheckBox::clicked, this, &SecurityPage::onCaNeedBoxClicked); + + connect(caCertPathCombox, static_cast(&QComboBox::currentIndexChanged), + this, &SecurityPage::onCaCertPathComboxIndexChanged); + + connect(clientCertPathCombox, static_cast(&QComboBox::currentIndexChanged), + this, &SecurityPage::onClientCertPathComboxIndexChanged); + + connect(clientPrivateKeyCombox, static_cast(&QComboBox::currentIndexChanged), + this, &SecurityPage::onClientPrivateKeyComboxIndexChanged); + + connect(pwdOptionCombox, static_cast(&QComboBox::currentIndexChanged), + this, &SecurityPage::onPwdOptionComboxIndexChanged); + + connect(secuTypeCombox, SIGNAL(currentIndexChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(pwdEdit, &LineEdit::textChanged, this, &SecurityPage::setEnableOfSaveBtn); + connect(eapTypeCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEnableOfSaveBtn())); + connect(identityEdit, &LineEdit::textChanged, this, &SecurityPage::setEnableOfSaveBtn); + connect(caCertPathCombox, SIGNAL(currentTextChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(caNeedBox, &QCheckBox::stateChanged, this, &SecurityPage::setEnableOfSaveBtn); + connect(clientCertPathCombox, SIGNAL(currentTextChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(clientPrivateKeyCombox, SIGNAL(currentTextChanged(QString)), this, SLOT(setEnableOfSaveBtn())); + connect(clientPrivateKeyPwdEdit, &LineEdit::textChanged, this, &SecurityPage::setEnableOfSaveBtn); + connect(eapMethodCombox, SIGNAL(currentIndexChanged(int)), this, SLOT(setEnableOfSaveBtn())); + connect(userNameEdit, &LineEdit::textChanged, this, &SecurityPage::setEnableOfSaveBtn); + connect(userPwdEdit, &LineEdit::textChanged, this, &SecurityPage::setEnableOfSaveBtn); + +} + +void SecurityPage::setSecurity(KySecuType index) +{ + secuTypeCombox->setCurrentIndex(index); + onSecuTypeComboxIndexChanged(); +} + +void SecurityPage::setPsk(const QString &psk) +{ + pwdEdit->setText(psk); +} + +void SecurityPage::setTlsInfo(KyEapMethodTlsInfo &info) +{ + showTls(); + identityEdit->setText(info.identity); + domainEdit->setText(info.domain); + if (info.caCertPath.isEmpty()) { + caCertPathCombox->setItemText(0, QString(tr("None"))); + caNeedBox->setChecked(true); + caCertPathCombox->setEnabled(false); + } else { + caCertPathCombox->setItemText(0, info.caCertPath); + caNeedBox->setChecked(false); + caCertPathCombox->setEnabled(true); + } + + if (info.clientCertPath.isEmpty()) { + clientCertPathCombox->setItemText(0, ""); + } else { + clientCertPathCombox->setItemText(0, info.clientCertPath); + } + + if (info.clientPrivateKey.isEmpty()) { + clientPrivateKeyCombox->setItemText(0, ""); + } else { + clientPrivateKeyCombox->setItemText(0, info.clientPrivateKey); + } + + clientPrivateKeyPwdEdit->setText(info.clientPrivateKeyPWD); + + if (info.m_privateKeyPWDFlag == NetworkManager::Setting::AgentOwned) { + pwdOptionCombox->setCurrentIndex(0); + } else if (info.m_privateKeyPWDFlag == NetworkManager::Setting::None) { + pwdOptionCombox->setCurrentIndex(1); + } else { + pwdOptionCombox->setCurrentIndex(2); + } +} + +void SecurityPage::setPeapInfo(KyEapMethodPeapInfo &info) +{ + showPeapOrTtls(); + eapTypeCombox->setCurrentIndex(PEAP); + onEapTypeComboxIndexChanged(); + if (info.phase2AuthMethod == KyAuthMethodMschapv2) { + eapMethodCombox->setCurrentIndex(MSCHAPV2_PEAP); + } else if (info.phase2AuthMethod == KyAuthMethodMd5){ + eapMethodCombox->setCurrentIndex(MD5_PEAP); + } else if (info.phase2AuthMethod == KyAuthMethodGtc) { + eapMethodCombox->setCurrentIndex(GTC_PEAP); + } + userNameEdit->setText(info.userName); + userPwdEdit->setText(info.userPWD); + if (info.m_passwdFlag) { + userPwdFlagBox->setChecked(true); + } else { + userPwdFlagBox->setChecked(false); + } +} + +void SecurityPage::setTtlsInfo(KyEapMethodTtlsInfo &info) +{ + showPeapOrTtls(); + eapTypeCombox->setCurrentIndex(TTLS); + onEapTypeComboxIndexChanged(); + + if (info.authType == AUTH_EAP) { + if (info.authEapMethod = KyAuthEapMethodMschapv2) { + eapMethodCombox->setCurrentIndex(MSCHAPV2_EAP); + } else if (info.authEapMethod = KyAuthEapMethodMd5) { + eapMethodCombox->setCurrentIndex(MD5_EAP); + } else if (info.authEapMethod = KyAuthEapMethodMd5) { + eapMethodCombox->setCurrentIndex(MD5_EAP); + } else { + qDebug() << "not support yet. AUTH_EAP method" << info.authEapMethod; + } + } else { + if (info.authNoEapMethod == KyAuthMethodPap) { + eapMethodCombox->setCurrentIndex(PAP); + } else if (info.authNoEapMethod == KyAuthMethodMschap) { + eapMethodCombox->setCurrentIndex(MSCHAP); + } else if (info.authNoEapMethod == KyAuthMethodMschapv2) { + eapMethodCombox->setCurrentIndex(MSCHAPV2); + } else if (info.authNoEapMethod == KyAuthMethodChap) { + eapMethodCombox->setCurrentIndex(CHAP); + } else { + qDebug() << "not support yet. AUTH_NO_EAP method" << info.authNoEapMethod; + } + } + userNameEdit->setText(info.userName); + userPwdEdit->setText(info.userPWD); + if (info.m_passwdFlag) { + userPwdFlagBox->setChecked(true); + } else { + userPwdFlagBox->setChecked(false); + } +} + +void SecurityPage::setSecurityVisible(const bool &visible) +{ + if (secuTypeLabel) { + secuTypeLabel->setVisible(visible); + } else { + qWarning() << "Set visible of secuTypeLabel failed because of null pointer" << Q_FUNC_INFO << __LINE__; + } + if (secuTypeCombox) { + secuTypeCombox->setVisible(visible); + } else { + qWarning() << "Set visible of secuTypeCombox failed because of null pointer" << Q_FUNC_INFO << __LINE__; + } +} + +void SecurityPage::updateTlsChange(KyEapMethodTlsInfo &info) +{ + KyEapMethodTlsInfo tlsInfo = assembleTlsInfo(); + if (tlsInfo.clientPrivateKeyPWD != info.clientPrivateKeyPWD) { + tlsInfo.bChanged = true; + } + tlsInfo.devIfaceName = info.devIfaceName; + info = tlsInfo; +} + +void SecurityPage::updatePeapChange(KyEapMethodPeapInfo &info) +{ + KyEapMethodPeapInfo peapInfo = assemblePeapInfo(); + if (peapInfo.userPWD != info.userPWD) { + peapInfo.bChanged = true; + } + info = peapInfo; +} + +void SecurityPage::updateTtlsChange(KyEapMethodTtlsInfo &info) +{ + KyEapMethodTtlsInfo ttlsInfo = assembleTtlsInfo(); + if (ttlsInfo.userPWD != info.userPWD) { + ttlsInfo.bChanged = true; + } + info = ttlsInfo; +} + +void SecurityPage::getSecuType(KySecuType &secuType, KyEapMethodType &enterpriseType) +{ + secuType = (KySecuType)secuTypeCombox->currentData().toInt(); + enterpriseType = (KyEapMethodType)eapTypeCombox->currentData().toInt(); +} + +bool SecurityPage::checkIsChanged(const ConInfo info) +{ + if (info.secType != secuTypeCombox->currentData().toInt()) { + return true; + } else { + if (info.secType == NONE) { + return false; + } else if (info.secType == WPA_AND_WPA2_PERSONAL || info.secType == WPA3_PERSONAL) { + return !(info.strPassword == pwdEdit->text()); + } else { + if (info.enterpriseType != eapTypeCombox->currentData().toInt()) { + return true; + } else { + if (info.enterpriseType == TLS) { + return !(info.tlsInfo == assembleTlsInfo()); + } else if (info.enterpriseType == PEAP) { + return !(info.peapInfo == assemblePeapInfo()); + } else if (info.enterpriseType == TTLS) { + return !(info.ttlsInfo == assembleTtlsInfo()); + } + } + } + } +} + +void SecurityPage::showNone() +{ + pwdLabel->hide(); + pwdEdit->hide(); + //企业wifi共有 + eapTypeLabel->hide(); + eapTypeCombox->hide(); + + //TLS + identityLable->hide(); + identityEdit->hide(); + tlsWidget->hide(); + + //PEAP TTLS共有 + eapMethodLabel->hide(); + userNameLabel->hide(); + userPwdLabel->hide(); + userPwdFlagBox->hide(); + + eapMethodCombox->hide(); + userNameEdit->hide(); + userPwdEdit->hide(); + userPwdFlagLabel->hide(); +} + +void SecurityPage::showPsk() +{ + pwdLabel->show(); + pwdEdit->show(); + //企业wifi共有 + eapTypeLabel->hide(); + eapTypeCombox->hide(); + + //TLS + identityLable->hide(); + identityEdit->hide(); + tlsWidget->hide(); + + //PEAP TTLS共有 + eapMethodLabel->hide(); + userNameLabel->hide(); + userPwdLabel->hide(); + userPwdFlagBox->hide(); + + eapMethodCombox->hide(); + userNameEdit->hide(); + userPwdEdit->hide(); + userPwdFlagLabel->hide(); +} + +void SecurityPage::showTls() +{ + pwdLabel->hide(); + pwdEdit->hide(); + eapTypeCombox->show(); + eapTypeLabel->show(); + + //TLS + identityLable->show(); + identityEdit->show(); + tlsWidget->show(); + + //PEAP TTLS共有 + eapMethodLabel->hide(); + userNameLabel->hide(); + userPwdLabel->hide(); + userPwdFlagBox->hide(); + + eapMethodCombox->hide(); + userNameEdit->hide(); + userPwdEdit->hide(); + userPwdFlagLabel->hide(); +} + +void SecurityPage::showPeapOrTtls() +{ + pwdLabel->hide(); + pwdEdit->hide(); + + //企业wifi共有 + eapTypeLabel->show(); + eapTypeCombox->show(); + + //TLS + identityLable->hide(); + identityEdit->hide(); + tlsWidget->hide(); + + //PEAP TTLS共有 + eapMethodLabel->show(); + userNameLabel->show(); + userPwdLabel->show(); + userPwdFlagBox->show(); + + eapMethodCombox->show(); + userNameEdit->show(); + userPwdEdit->show(); + userPwdFlagLabel->show(); +} + +KyEapMethodTlsInfo SecurityPage::assembleTlsInfo() +{ + KyEapMethodTlsInfo info; + info.identity = identityEdit->text(); + info.domain = domainEdit->text(); + info.caCertPath = caCertPathCombox->currentText(); + info.bNeedCa = !caNeedBox->isChecked(); + info.clientCertPath = clientCertPathCombox->currentText(); + info.clientPrivateKey = clientPrivateKeyCombox->currentText(); + info.clientPrivateKeyPWD = clientPrivateKeyPwdEdit->text(); + switch (pwdOptionCombox->currentIndex()) { + case 0: + info.m_privateKeyPWDFlag = NetworkManager::Setting::AgentOwned; + break; + case 1: + info.m_privateKeyPWDFlag = NetworkManager::Setting::None; + break; + case 2: + info.m_privateKeyPWDFlag = NetworkManager::Setting::NotSaved; + break; + default: + break; + } + return info; +} + +KyEapMethodPeapInfo SecurityPage::assemblePeapInfo() +{ + KyEapMethodPeapInfo info; +// info.phase2AuthMethod = (KyNoEapMethodAuth)eapMethodCombox->currentData().toInt(); + switch (eapMethodCombox->currentIndex()) { + case 0: + info.phase2AuthMethod = KyAuthMethodMschapv2; + break; + case 1: + info.phase2AuthMethod = KyAuthMethodMd5; + break; + case 2: + info.phase2AuthMethod = KyAuthMethodGtc; + break; + default: + break; + } + info.userName = userNameEdit->text(); + info.userPWD = userPwdEdit->text(); + info.m_passwdFlag = (userPwdFlagBox->isChecked() ? NetworkManager::Setting::NotSaved : NetworkManager::Setting::None); + + return info; +} +KyEapMethodTtlsInfo SecurityPage::assembleTtlsInfo() +{ + KyEapMethodTtlsInfo info; + switch (eapMethodCombox->currentIndex()) { + case PAP: + info.authType = AUTH_NO_EAP; + info.authNoEapMethod = KyAuthMethodPap; + break; + case MSCHAP: + info.authType = AUTH_NO_EAP; + info.authNoEapMethod = KyAuthMethodChap; + break; + case MSCHAPV2_EAP: + info.authType = AUTH_EAP; + info.authEapMethod = KyAuthEapMethodMschapv2; + break; + case MSCHAPV2: + info.authType = AUTH_NO_EAP; + info.authNoEapMethod = KyAuthMethodMschapv2; + break; + case CHAP: + info.authType = AUTH_NO_EAP; + info.authNoEapMethod = KyAuthMethodChap; + break; + case MD5_EAP: + info.authType = AUTH_EAP; + info.authEapMethod = KyAuthEapMethodMd5; + break; + case GTC_EAP: + info.authType = AUTH_EAP; + info.authEapMethod = KyAuthEapMethodGtc; + break; + default: + break; + } + info.userName = userNameEdit->text(); + info.userPWD = userPwdEdit->text(); + info.m_passwdFlag = (userPwdFlagBox->isChecked() ? NetworkManager::Setting::NotSaved : NetworkManager::Setting::None); + return info; +} + +void SecurityPage::updateSecurityChange(KyWirelessConnectSetting &setting) +{ + qDebug() << "secuTypeCombox->currentData()" << secuTypeCombox->currentData().toInt() << pwdEdit->text(); + if (secuTypeCombox->currentData().toInt() == NONE) { + setting.m_psk = ""; + } else { + setting.m_psk = pwdEdit->text(); + } + + if (secuTypeCombox->currentData().toInt() == NONE) { + setting.m_type = WpaNone; + } else if (secuTypeCombox->currentData().toInt() == WPA_AND_WPA2_PERSONAL) { + setting.m_type = WpaPsk; + } else if (secuTypeCombox->currentData().toInt() == WPA3_PERSONAL) { + setting.m_type = SAE; + } + setting.isAutoConnect = m_rememberCheckBox->isChecked(); +} + +bool SecurityPage::checkConnectBtnIsEnabled() +{ + int index = secuTypeCombox->currentData().toInt(); + if (index == NONE) { + + } else if (index == WPA_AND_WPA2_PERSONAL || index == WPA3_PERSONAL) { + if (pwdEdit->text().isEmpty() || pwdEdit->text().length() < 8 ) { + qDebug() << "password is empty or length < 8"; + return false; + } + } else if (index == WPA_AND_WPA2_ENTERPRISE) { + int type = eapTypeCombox->currentData().toInt(); + if (type == TLS) { + if (identityEdit->text().isEmpty()) { + qDebug() << "tls identity is empty"; + return false; + } + QFile cafile(caCertPathCombox->currentText()); + if(!caNeedBox->isChecked() && !cafile.exists()) { + qDebug() << "ca cert filepath " << caCertPathCombox->currentText() << " is invalid"; + return false; + } + + QFile cliCafile(clientCertPathCombox->currentText()); + if(!cliCafile.exists()) { + qDebug() << "client cert filepath " << clientCertPathCombox->currentText() << " is invalid"; + return false; + } + + QFile cliKeyfile(clientPrivateKeyCombox->currentText()); + if(!cliKeyfile.exists()) { + qDebug() << "client private key filepath " << clientPrivateKeyCombox->currentText() << " is invalid"; + return false; + } + + if(clientPrivateKeyPwdEdit->text().isEmpty()) { + qDebug() << "client Private Key password is empty"; + return false; + } + } else if (type == PEAP || type == TTLS) { + if(userNameEdit->text().isEmpty() || userPwdEdit->text().isEmpty()) { + qDebug() << "user name or user password is empty"; + return false; + } + } + } + return true; +} + +void SecurityPage::setEnableOfSaveBtn() +{ + Q_EMIT setSecuPageState(checkConnectBtnIsEnabled()); +} + +void SecurityPage::onSecuTypeComboxIndexChanged() +{ + int index = secuTypeCombox->currentData().toInt(); + if (index == WPA_AND_WPA2_PERSONAL) { + showPsk(); + Q_EMIT this->secuTypeChanged(WPA_AND_WPA2_PERSONAL); + } + else if (index == WPA3_PERSONAL) { + showPsk(); + Q_EMIT this->secuTypeChanged(WPA3_PERSONAL); + } else if (index == WPA_AND_WPA2_ENTERPRISE) { + onEapTypeComboxIndexChanged(); + Q_EMIT this->secuTypeChanged(WPA_AND_WPA2_ENTERPRISE); + } else if (index == NONE) { + showNone(); + Q_EMIT this->secuTypeChanged(NONE); + } +} + +void SecurityPage::onEapTypeComboxIndexChanged() +{ + qDebug() << "onEapTypeComboxIndexChanged"; + int index = eapTypeCombox->currentData().toInt(); + if (index == TLS) { + showTls(); + Q_EMIT this->eapTypeChanged(TLS); + } else if (index == PEAP) { + showPeapOrTtls(); + eapMethodCombox->clear(); + eapMethodCombox->addItem("MSCHAPv2", MSCHAPV2_PEAP); + eapMethodCombox->addItem("MD5", MD5_PEAP); + eapMethodCombox->addItem("GTC", GTC_PEAP); + Q_EMIT this->eapTypeChanged(PEAP); + } else if (index == TTLS) { + showPeapOrTtls(); + eapMethodCombox->clear(); + eapMethodCombox->addItem("pap", PAP); + eapMethodCombox->addItem("mschap", MSCHAP); + eapMethodCombox->addItem("mschapv2(eap)", MSCHAPV2_EAP); + eapMethodCombox->addItem("mschapv2", MSCHAPV2); + eapMethodCombox->addItem("chap", CHAP); + eapMethodCombox->addItem("md5(eap)", MD5_EAP); + eapMethodCombox->addItem("gtc(eap)", GTC_EAP); + Q_EMIT this->eapTypeChanged(TTLS); + } +} + +void SecurityPage::onCaNeedBoxClicked() +{ + if (caNeedBox->isChecked()) { + caCertPathCombox->setItemText(0, QString(tr("None"))); + caCertPathCombox->setEnabled(false); + } else { + caCertPathCombox->setEnabled(true); + } +} + +void SecurityPage::onCaCertPathComboxIndexChanged(QString str) +{ + if (str.contains("Choose from file...") || str.contains("从文件选择...")) + { + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a CA certificate"), "recent:///", + tr("CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx)")); + if (!fileName.isNull()) { + QStringList nameList = fileName.split("/"); + caCertPathCombox->blockSignals(true); + caCertPathCombox->setItemText(0, fileName); + caCertPathCombox->setCurrentIndex(0); + caCertPathCombox->blockSignals(false); + } else { + caCertPathCombox->blockSignals(true); + caCertPathCombox->setItemText(0, tr("None")); + caCertPathCombox->setCurrentIndex(0); + caCertPathCombox->blockSignals(false); + } + } else { + qWarning() << "Choose file is null or unvalible"; + } +} + +void SecurityPage::onClientCertPathComboxIndexChanged(QString str) +{ + if (str.contains("Choose from file...") || str.contains("从文件选择...")) + { + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a CA certificate"), "recent:///", + tr("CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx)")); + if (!fileName.isNull()) { + clientCertPathCombox->blockSignals(true); + clientCertPathCombox->setItemText(0, fileName); + clientCertPathCombox->setCurrentIndex(0); + clientCertPathCombox->blockSignals(false); + } else { + clientCertPathCombox->blockSignals(true); + clientCertPathCombox->setItemText(0, tr("None")); + clientCertPathCombox->setCurrentIndex(0); + clientCertPathCombox->blockSignals(false); + } + } else { + qWarning() << "Choose file is null or unvalible"; + } +} + +void SecurityPage::onClientPrivateKeyComboxIndexChanged(QString str) +{ + if (str.contains("Choose from file...") || str.contains("从文件选择...")) + { + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a CA certificate"), "recent:///", + tr("CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx)")); + if (!fileName.isNull()) { + QStringList nameList = fileName.split("/"); + clientPrivateKeyCombox->blockSignals(true); + clientPrivateKeyCombox->setItemText(0, fileName); + clientPrivateKeyCombox->setCurrentIndex(0); + clientPrivateKeyCombox->blockSignals(false); + } else { + clientPrivateKeyCombox->blockSignals(true); + clientPrivateKeyCombox->setItemText(0, tr("None")); + clientPrivateKeyCombox->setCurrentIndex(0); + clientPrivateKeyCombox->blockSignals(false); + } + } else { + qWarning() << "Choose file is null or unvalible"; + } +} + +void SecurityPage::onPwdOptionComboxIndexChanged(QString str) +{ + KyEapMethodTlsInfo info; + if (str.contains("Store passwords only for this user") || str.contains("仅为该用户存储密码")) { + info.m_privateKeyPWDFlag = NetworkManager::Setting::AgentOwned; + clientPrivateKeyPwdEdit->setPlaceholderText(emptyhint); + } else if (str.contains("Store passwords for all users") || str.contains("存储所有用户的密码")) { + info.m_privateKeyPWDFlag = NetworkManager::Setting::None; + clientPrivateKeyPwdEdit->setPlaceholderText(hintRequired); + } else { + info.m_privateKeyPWDFlag = NetworkManager::Setting::NotSaved; + clientPrivateKeyPwdEdit->setPlaceholderText(emptyhint); + } +} + +void SecurityPage::changeColumnWidthWithSecuType() +{ + if (!isDetailPage) { + return; + } + if (secuTypeCombox->currentData().toInt() == WPA_AND_WPA2_ENTERPRISE && + eapMethodCombox->currentData().toInt() == TLS) { + topLayout->setColumnMinimumWidth(0, MIN_LABEL_WIDTH); + topLayout->setColumnMinimumWidth(1, MIN_EDIT_WIDTH); + bottomLayout->setColumnMinimumWidth(0, MIN_LABEL_WIDTH - 8); + + } else { + topLayout->setColumnMinimumWidth(0, DETAIL_MIN_LABEL_WIDTH); + topLayout->setColumnMinimumWidth(1, DETAIL_MIN_EDIT_WIDTH); + } +} + diff --git a/src/frontend/netdetails/securitypage.h b/src/frontend/netdetails/securitypage.h new file mode 100644 index 00000000..294880e9 --- /dev/null +++ b/src/frontend/netdetails/securitypage.h @@ -0,0 +1,146 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef SECURITYWIDGET_H +#define SECURITYWIDGET_H + +#include +#include +#include +#include +#include +#include + +#include "coninfo.h" +#include "detailwidget.h" +#include "kwidget.h" +#include "kpasswordedit.h" + +using namespace kdk; + +class SecurityPage : public QFrame +{ + Q_OBJECT +public: + SecurityPage(bool isNetDetailPage, QWidget *parent = nullptr); + + void setSecurity(KySecuType index); + void setPsk(const QString &psk); + void setTlsInfo(KyEapMethodTlsInfo &info); + void setPeapInfo(KyEapMethodPeapInfo &info); + void setTtlsInfo(KyEapMethodTtlsInfo &info); + void setSecurityVisible(const bool &visible); + + bool checkIsChanged(const ConInfo info); + void updateSecurityChange(KyWirelessConnectSetting &setting); + void updateTlsChange(KyEapMethodTlsInfo &info); + void updatePeapChange(KyEapMethodPeapInfo &info); + void updateTtlsChange(KyEapMethodTtlsInfo &info); + + void getSecuType(KySecuType &secuType, KyEapMethodType &enterpriseType); + +private: + bool isDetailPage; +// QFormLayout *mSecuLayout; + QGridLayout *topLayout; + QGridLayout *bottomLayout; + QVBoxLayout *mainLayout; + + QLabel *secuTypeLabel; + QLabel *pwdLabel; + //企业wifi共有 + QLabel *eapTypeLabel; + //TLS + QLabel *identityLable; + QLabel *domainLable; + QLabel *caCertPathLabel; + QLabel *caNeedFlagLabel; + FixLabel *clientCertPathLabel; + FixLabel *clientPrivateKeyLabel; + FixLabel *clientPrivateKeyPwdLabel; + FixLabel *pwdOptionLabel; + + //PEAP TTLS共有 + FixLabel *eapMethodLabel; + QLabel *userNameLabel; + QLabel *userPwdLabel; + QLabel *userPwdFlagLabel; + + QComboBox *secuTypeCombox; + KPasswordEdit *pwdEdit = nullptr; + QComboBox *eapTypeCombox; + //TLS + LineEdit *identityEdit; + LineEdit *domainEdit; + QComboBox *caCertPathCombox; + QCheckBox *caNeedBox; + QComboBox *clientCertPathCombox; + QComboBox *clientPrivateKeyCombox; + KPasswordEdit *clientPrivateKeyPwdEdit = nullptr; + QComboBox *pwdOptionCombox; + QWidget *tlsWidget; + + //PEAP && TTLS + QComboBox *eapMethodCombox; + LineEdit *userNameEdit; + KPasswordEdit *userPwdEdit = nullptr; + QCheckBox *userPwdFlagBox; + + QLabel *m_emptyLabel = nullptr; + QLabel *m_checkLabel = nullptr; + QCheckBox *m_rememberCheckBox = nullptr; + + QString hintRequired = tr("Required"); //必填 + QString emptyhint = tr(" "); + +private: + void showNone(); + void showPsk(); + void showTls(); + void showPeapOrTtls(); + void initUI(); + void initConnect(); + + KyEapMethodTlsInfo assembleTlsInfo(); + KyEapMethodPeapInfo assemblePeapInfo(); + KyEapMethodTtlsInfo assembleTtlsInfo(); + + bool checkConnectBtnIsEnabled(); + + +private Q_SLOTS: + void onSecuTypeComboxIndexChanged(); + void onEapTypeComboxIndexChanged(); + void setEnableOfSaveBtn(); + + void onCaNeedBoxClicked(); + + void onCaCertPathComboxIndexChanged(QString str); + void onClientCertPathComboxIndexChanged(QString str); + void onClientPrivateKeyComboxIndexChanged(QString str); + void onPwdOptionComboxIndexChanged(QString str); + void changeColumnWidthWithSecuType(); + +Q_SIGNALS: + void setSecuPageState(bool); + void secuTypeChanged(const KySecuType &type); + void eapTypeChanged(const KyEapMethodType &type); +}; + +#endif // SECURITYWIDGET_H diff --git a/src/frontend/networkmode/firewalldialog.cpp b/src/frontend/networkmode/firewalldialog.cpp new file mode 100644 index 00000000..ed9e1304 --- /dev/null +++ b/src/frontend/networkmode/firewalldialog.cpp @@ -0,0 +1,128 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "firewalldialog.h" + +#include + +#define THEME_SCHAME "org.ukui.style" +#define COLOR_THEME "styleName" +#define ICON_SIZE 16,16 + +FirewallDialog::FirewallDialog(QWidget *parent): KDialog(parent) +{ + initUI(); + this->setWindowIcon(QIcon::fromTheme("kylin-network")); + this->setFixedSize(480, 204); + setAttribute(Qt::WA_DeleteOnClose); +// centerToScreen(); + connect(qApp, &QApplication::paletteChanged, this, &FirewallDialog::onPaletteChanged); +} + +FirewallDialog::~FirewallDialog() +{ + +} + +void FirewallDialog::initUI() +{ + m_iconLabel = new QLabel(this); + m_contentLabel = new QLabel(this); + m_suggestLabel = new QLabel(this); + m_YesBtn = new QPushButton(this); + m_NoBtn = new QPushButton(this); + m_dialogLayout = new QVBoxLayout(this); + + QWidget *contentWidget = new QWidget(this); + QGridLayout *contentLayout = new QGridLayout(contentWidget); + contentLayout->setContentsMargins(0, 0, 0, 0); + contentLayout->addWidget(m_iconLabel, 0, 0, Qt::AlignVCenter); + contentLayout->addWidget(m_contentLabel, 0, 1); + contentLayout->addWidget(m_suggestLabel, 1, 1); + m_iconLabel->setFixedWidth(16); + + QWidget *btnWidget = new QWidget(this); + QHBoxLayout *btnLayout = new QHBoxLayout(btnWidget); + btnLayout->setContentsMargins(0, 0, 0, 0); + btnLayout->setSpacing(16); + btnLayout->addStretch(); + btnLayout->addWidget(m_YesBtn); + btnLayout->addWidget(m_NoBtn); + + m_dialogLayout->setContentsMargins(24, 16, 24, 24); + m_dialogLayout->setSpacing(0); + m_dialogLayout->addWidget(contentWidget); + m_dialogLayout->addStretch(); + m_dialogLayout->addWidget(btnWidget); + + QIcon icon = QIcon::fromTheme("dialog-info"); + m_iconLabel->setPixmap(icon.pixmap(ICON_SIZE)); + + QFont font = m_contentLabel->font(); + font.setWeight(57); + m_contentLabel->setFont(font); + //是否允许此网络上的其他设备发现这台电脑? + m_contentLabel->setText(tr("Allow other devices on this network to discover this computer?")); + m_contentLabel->setWordWrap(true); + //不建议在公共网络上开启此功能 + m_suggestLabel->setText(tr("It is not recommended to enable this feature on public networks")); + m_suggestLabel->setWordWrap(true); + + m_YesBtn->setText(tr("Not allowed (recommended)")); + m_NoBtn->setText(tr("Allowed")); + + this->closeButton(); + this->mainWidget()->setLayout(m_dialogLayout); + onPaletteChanged(); + + connect(m_YesBtn, &QPushButton::clicked, this, &FirewallDialog::setPublicNetMode); + connect(m_NoBtn, &QPushButton::clicked, this, &FirewallDialog::setPrivateNetMode); +} + +void FirewallDialog::centerToScreen() +{ + QDesktopWidget* m = QApplication::desktop(); + QRect desk_rect = m->screenGeometry(m->screenNumber(QCursor::pos())); + int desk_x = desk_rect.width(); + int desk_y = desk_rect.height(); + int x = this->width(); + int y = this->height(); + this->move(desk_x / 2 - x / 2 + desk_rect.left(), desk_y / 2 - y / 2 + desk_rect.top()); +} + +void FirewallDialog::onPaletteChanged() +{ + QPalette pal = qApp->palette(); + + QGSettings * styleGsettings = nullptr; + const QByteArray style_id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(style_id)) { + styleGsettings = new QGSettings(style_id); + QString currentTheme = styleGsettings->get(COLOR_THEME).toString(); + if(currentTheme == "ukui-default"){ + pal = lightPalette(this); + } + } + this->setPalette(pal); + + if (styleGsettings != nullptr) { + delete styleGsettings; + styleGsettings = nullptr; + } +} diff --git a/src/frontend/networkmode/firewalldialog.h b/src/frontend/networkmode/firewalldialog.h new file mode 100644 index 00000000..2d92bbd1 --- /dev/null +++ b/src/frontend/networkmode/firewalldialog.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef FIREWALLDIALOG_H +#define FIREWALLDIALOG_H + +#include +#include +#include +#include +#include +#include + +#include "coninfo.h" +#include "kwidget.h" +#include "kdialog.h" + +using namespace kdk; + +class FirewallDialog : public KDialog +{ + Q_OBJECT +public: + FirewallDialog(QWidget *parent = nullptr); + ~FirewallDialog(); + void setUuid(QString uuid) { + m_uuid = uuid; + } + + void centerToScreen(); + +private: + void initUI(); + + QString m_uuid; + QLabel * m_iconLabel = nullptr; + QLabel * m_contentLabel = nullptr; + QLabel * m_suggestLabel = nullptr; + QVBoxLayout *m_dialogLayout = nullptr; + QPushButton *m_YesBtn = nullptr; + QPushButton *m_NoBtn = nullptr; + +Q_SIGNALS: + void setPublicNetMode(); + void setPrivateNetMode(); + +private Q_SLOTS: + void onPaletteChanged(); + + +public Q_SLOTS: + void closeMyself(QString uuid, int status) { + if (uuid == m_uuid && status == 4) { + this->close(); + } + } +}; +#endif // FIREWALLDIALOG_H diff --git a/src/frontend/networkmode/networkmode.pri b/src/frontend/networkmode/networkmode.pri new file mode 100644 index 00000000..6459b81c --- /dev/null +++ b/src/frontend/networkmode/networkmode.pri @@ -0,0 +1,10 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/firewalldialog.h \ + $$PWD/networkmodeconfig.h + +SOURCES += \ + $$PWD/firewalldialog.cpp \ + $$PWD/networkmodeconfig.cpp + diff --git a/src/frontend/networkmode/networkmodeconfig.cpp b/src/frontend/networkmode/networkmodeconfig.cpp new file mode 100644 index 00000000..fa19cc6c --- /dev/null +++ b/src/frontend/networkmode/networkmodeconfig.cpp @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "networkmodeconfig.h" +#include + +NetworkModeConfig *NetworkModeConfig::m_netModeInstance = nullptr; + +NetworkModeConfig *NetworkModeConfig::getInstance() +{ + if (m_netModeInstance == NULL) { + m_netModeInstance = new NetworkModeConfig(); + } + return m_netModeInstance; +} + + +NetworkModeConfig::NetworkModeConfig(QObject *parent) : QObject(parent) +{ + m_dbusInterface = new QDBusInterface("com.ksc.defender", + "/firewall", + "com.ksc.defender.firewall", + QDBusConnection::systemBus()); +} + +int NetworkModeConfig::getNetworkModeConfig(QString uuid) +{ + if (uuid.isEmpty()) { + qWarning()<< /*LOG_FLAG <<*/ "uuid is empty, so can not get network mode config"; + return -1; + } + + if(!m_dbusInterface->isValid()) { + qWarning ()<< "init com.ksc.defender dbus error"; + } + + QDBusReply reply = m_dbusInterface->call("get_networkModeConfig", uuid); + if (reply.isValid()) { + return reply.value(); + } else { + qWarning() << "call get_networkModeConfig failed" << reply.error().message(); + } + return -1; +} + +void NetworkModeConfig::setNetworkModeConfig(QString uuid, QString cardName, QString ssid, int mode) +{ + if(!m_dbusInterface->isValid()) { + qWarning ()<< "init com.ksc.defender dbus error"; + } + + QDBusReply reply = m_dbusInterface->call("set_networkModeConfig", uuid, cardName, ssid, mode); + if (reply.isValid()) { + qDebug() << "set_networkModeConfig" << ssid << uuid << cardName << mode << ",result" << reply.value(); + } else { + qWarning() << "call set_networkModeConfig" << reply.error().message(); + } +} + +int NetworkModeConfig::breakNetworkConnect(QString uuid, QString cardName, QString ssid) +{ + if(!m_dbusInterface->isValid()) { + qWarning ()<< "init com.ksc.defender dbus error"; + } + + QDBusReply reply = m_dbusInterface->call("break_networkConnect", uuid, cardName, ssid); + if (reply.isValid()) { + qDebug() << "break_networkConnect" << ssid << uuid << cardName << ",result" << reply.value(); + return reply.value(); + } else { + qWarning() << "call break_networkConnect failed" << reply.error().message(); + return -1; + } +} diff --git a/src/frontend/networkmode/networkmodeconfig.h b/src/frontend/networkmode/networkmodeconfig.h new file mode 100644 index 00000000..e3ed69f2 --- /dev/null +++ b/src/frontend/networkmode/networkmodeconfig.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef NETWORKMODECONFIG_H +#define NETWORKMODECONFIG_H + +#include +#include +#include + +class NetworkModeConfig : public QObject +{ + Q_OBJECT +public: + static NetworkModeConfig *getInstance(); + //安全中心-获取网络模式配置 + int getNetworkModeConfig(QString uuid); + //安全中心-设置网络模式配置 + void setNetworkModeConfig(QString uuid, QString cardName, QString ssid, int mode); + //安全中心-解除连接(用于防火墙处从正在使用的网络中删除) + int breakNetworkConnect(QString uuid, QString cardName, QString ssid); + + static NetworkModeConfig *m_netModeInstance; + +private: + explicit NetworkModeConfig(QObject *parent = nullptr); + QDBusInterface *m_dbusInterface = nullptr; +}; + +#endif // NETWORKMODECONFIG_H diff --git a/src/frontend/tab-pages/lanpage.cpp b/src/frontend/tab-pages/lanpage.cpp new file mode 100644 index 00000000..8ce1e7b3 --- /dev/null +++ b/src/frontend/tab-pages/lanpage.cpp @@ -0,0 +1,1294 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "lanpage.h" +#include "networkmodeconfig.h" +#include +#include + +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_SPACING 0 +#define TITLE_FRAME_HEIGHT 52 +#define TITLE_LAYOUT_MARGINS 24,0,24,0 +#define LAN_LIST_SPACING 0 +#define TEXT_MARGINS 16,0,0,0 +#define SETTINGS_LAYOUT_MARGINS 24,16,24,16 +#define TRANSPARENT_COLOR QColor(0,0,0,0) +#define ITEM_HEIGHT 48 + +#define LOG_FLAG "[LanPage]" + +const QString EMPTY_CONNECT_UUID = "emptyconnect"; + +const QString WIRED_SWITCH = "wiredswitch"; + +LanPage::LanPage(QWidget *parent) : TabPage(parent) +{ + m_activeResourse = new KyActiveConnectResourse(this); + m_connectResourse = new KyConnectResourse(this); + m_deviceResource = new KyNetworkDeviceResourse(this); + m_wiredConnectOperation = new KyWiredConnectOperation(this); + + initUI(); + initLanDevice(); + initNetSwitch(); + initLanDeviceState(); + + initDeviceCombox(); + initLanArea(); + + connect(m_activeResourse, &KyActiveConnectResourse::stateChangeReason, this, &LanPage::onConnectionStateChange); + connect(m_activeResourse, &KyActiveConnectResourse::activeConnectRemove, this, [=] (QString activeConnectUuid) { + sendLanStateChangeSignal(activeConnectUuid,Deactivated); + } ); + + connect(m_connectResourse, &KyConnectResourse::connectionAdd, this, &LanPage::onAddConnection); + connect(m_connectResourse, &KyConnectResourse::connectionRemove, this, &LanPage::onRemoveConnection); + connect(m_connectResourse, &KyConnectResourse::connectionUpdate, this, &LanPage::onUpdateConnection); + + connect(m_deviceResource, &KyNetworkDeviceResourse::deviceAdd, this, &LanPage::onDeviceAdd); + connect(m_deviceResource, &KyNetworkDeviceResourse::deviceRemove, this, &LanPage::onDeviceRemove); + connect(m_deviceResource, &KyNetworkDeviceResourse::deviceNameUpdate, this, &LanPage::onDeviceNameUpdate); + + connect(m_deviceResource, &KyNetworkDeviceResourse::carrierChanage, this, &LanPage::onDeviceCarriered); + connect(m_deviceResource, &KyNetworkDeviceResourse::deviceActiveChanage, this, &LanPage::onDeviceActiveChanage); + connect(m_deviceResource, &KyNetworkDeviceResourse::deviceManagedChange, this, &LanPage::onDeviceManagedChange); + + connect(m_wiredConnectOperation, &KyWiredConnectOperation::activateConnectionError, this, &LanPage::activateFailed); + connect(m_wiredConnectOperation, &KyWiredConnectOperation::deactivateConnectionError, this, &LanPage::deactivateFailed); + connect(m_wiredConnectOperation, &KyWiredConnectOperation::wiredEnabledChanged, this, &LanPage::onWiredEnabledChanged); + connect(m_netSwitch, &KSwitchButton::clicked, this, [=](bool checked) { + m_netSwitch->setChecked(!checked); + m_wiredConnectOperation->setWiredEnabled(checked); + }); +} + +LanPage::~LanPage() +{ + +} + +void LanPage::initLanDevice() +{ + m_devList.clear(); + m_deviceResource->getNetworkDeviceList(NetworkManager::Device::Type::Ethernet, m_devList); + + m_currentDeviceName = getDefaultDeviceName(WIRED); + bool getDefault = !m_currentDeviceName.isEmpty(); + if (getDefault) { + if (m_deviceResource->wiredDeviceIsCarriered(m_currentDeviceName)) { + return; + } + } + + QList activedList; + for (int index = 0; index < m_devList.size(); ++index) { + m_activeResourse->getActiveConnectionList(m_devList.at(index), + NetworkManager::ConnectionSettings::Wired, activedList); + if (!activedList.isEmpty()) { + m_currentDeviceName = m_devList.at(index); + if (!getDefault) { + setDefaultDevice(WIRED, m_currentDeviceName); + } + return; + } + } + + for (int index = 0; index < m_devList.size(); ++index) { + if (m_deviceResource->wiredDeviceIsCarriered(m_devList.at(index))) { + m_currentDeviceName = m_devList.at(index); + if (!getDefault) { + setDefaultDevice(WIRED, m_currentDeviceName); + } + return; + } + } + return; +} + +void LanPage::initLanDeviceState() +{ + m_disableDeviceList.clear(); + m_enableDeviceList.clear(); + for (int index = 0; index < m_devList.count(); ++index) { + QString deviceName = m_devList.at(index); + if (m_deviceResource->getDeviceManaged(deviceName)) { + m_enableDeviceList<getWiredEnabled(); + + if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA)) { + m_switchGsettings = new QGSettings(GSETTINGS_SCHEMA); + if (m_switchGsettings->keys().contains(WIRED_SWITCH)) { + wiredSwitch = m_switchGsettings->get(WIRED_SWITCH).toBool(); + connect(m_switchGsettings, &QGSettings::changed, this, &LanPage::onSwithGsettingsChanged); + } + } else { + qDebug()<<"[LanPage] org.ukui.kylin-nm.switch is not installed!"; + } + + if (nullptr != m_switchGsettings + && wiredSwitch != wiredEnable) { + m_switchGsettings->set(WIRED_SWITCH, wiredEnable); + } + + //从3.0升级上来 先读取老的配置文件来保证和升级前状态一致 + bool oldVersionState; + if (getOldVersionWiredSwitchState(oldVersionState)) { + if (wiredEnable != oldVersionState) { + m_wiredConnectOperation->setWiredEnabled(oldVersionState); + } + } + + if (m_devList.count() == 0) { + qDebug() << "[wiredSwitch]:init not enable when no device"; + m_netSwitch->setChecked(false); + m_netSwitch->setCheckable(false); + } + + qDebug() << "[wiredSwitch]:init state:" << wiredEnable; + + m_netSwitch->setChecked(wiredEnable); +} + +void LanPage::onSwithGsettingsChanged(const QString &key) +{ + if (key == WIRED_SWITCH) { + + bool wiredSwitch = m_switchGsettings->get(WIRED_SWITCH).toBool(); + qDebug()<<"[LanPage] SwitchButton statue changed to:" << wiredSwitch << m_netSwitch->isChecked(); + + if (wiredSwitch != m_wiredConnectOperation->getWiredEnabled()) { + m_wiredConnectOperation->setWiredEnabled(wiredSwitch); + return; + } + + m_netSwitch->setChecked(wiredSwitch); + + initLanDeviceState(); + initDeviceCombox(); + initLanArea(); + } +} + +void LanPage::getEnabledDevice(QStringList &enableDeviceList) +{ + if (m_devList.isEmpty()) { + qDebug()<<"[LanPage] there is not wired device."; + return; + } + + for (int index = 0; index < m_devList.size(); ++index) { + if (m_deviceResource->getDeviceManaged(m_devList.at(index))) { + enableDeviceList << m_devList.at(index); + } + } +} + +void LanPage::getDisabledDevices(QStringList &disableDeviceList) +{ + if (m_devList.isEmpty()) { + qDebug()<<"[LanPage] there is not wired device."; + return; + } + + for (int index = 0; index < m_devList.size(); ++index) { + if (!m_deviceResource->getDeviceManaged(m_devList.at(index))) { + disableDeviceList << m_devList.at(index); + } + } +} + +void LanPage::initDeviceCombox() +{ + //TODO 获取设备列表,单设备时隐藏下拉框,多设备时添加到下拉框;m_devList记录插入的所有设备,deviceMap记录设备状态 + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); + + m_deviceComboBox->clear(); + + if (m_netSwitch->isChecked()) { + int enableDeviceCount = m_enableDeviceList.count(); + if (enableDeviceCount > 1) { + for (int index = 0; index < enableDeviceCount; ++index) { + m_deviceComboBox->addItem(m_enableDeviceList.at(index)); + } + + m_deviceFrame->show(); + m_tipsLabel->hide(); + m_deviceComboBox->show(); + + if (m_currentDeviceName != m_deviceComboBox->currentText()) { + if (m_enableDeviceList.contains(m_currentDeviceName)) { + m_deviceComboBox->setCurrentText(m_currentDeviceName); + } else { + m_currentDeviceName = m_deviceComboBox->currentText(); + } + } + + } else if (enableDeviceCount == 1) { + m_deviceFrame->hide(); + + if (m_currentDeviceName != m_enableDeviceList.at(0)) { + m_currentDeviceName = m_enableDeviceList.at(0); + } + } else { + m_deviceFrame->show(); + m_deviceComboBox->hide(); + m_tipsLabel->show(); + m_currentDeviceName = ""; + } + } else { + m_deviceFrame->hide(); + m_currentDeviceName = ""; + } + + setDefaultDevice(WIRED, m_currentDeviceName); + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); +} + +void LanPage::addEmptyConnectItem(QMap &connectMap, + QListWidget *lanListWidget) +{ + QListWidgetItem *p_listWidgetItem = addNewItem(nullptr, lanListWidget); + connectMap.insert(EMPTY_CONNECT_UUID, p_listWidgetItem); +} + + +void LanPage::deleteConnectionMapItem(QMap &connectMap, + QListWidget *lanListWidget, QString uuid) +{ + QListWidgetItem *p_listWidgetItem = connectMap.value(uuid); + if (p_listWidgetItem) { + connectMap.remove(uuid); + LanListItem *p_lanItem = (LanListItem *)lanListWidget->itemWidget(p_listWidgetItem); + lanListWidget->removeItemWidget(p_listWidgetItem); + + delete p_lanItem; + p_lanItem = nullptr; + + delete p_listWidgetItem; + p_listWidgetItem = nullptr; + } + + return; +} + +void LanPage::clearConnectionMap(QMap &connectMap, + QListWidget *lanListWidget) +{ + QMap::iterator iter; + + iter = connectMap.begin(); + while (iter != connectMap.end()) { + qDebug()<<"[LanPage] clear connection map item"<< iter.key(); + + QListWidgetItem *p_widgetItem = iter.value(); + LanListItem *p_lanItem = (LanListItem *)lanListWidget->itemWidget(p_widgetItem); + lanListWidget->removeItemWidget(p_widgetItem); + + delete p_lanItem; + p_lanItem = nullptr; + + delete p_widgetItem; + p_widgetItem = nullptr; + + iter = connectMap.erase(iter); + } + + return; +} + +void LanPage::constructActiveConnectionArea() +{ + QList activedList; + + activedList.clear(); + clearConnectionMap(m_activeConnectionMap, m_activatedLanListWidget); + + m_activeResourse->getActiveConnectionList(m_currentDeviceName, + NetworkManager::ConnectionSettings::Wired, activedList); //激活列表的显示 + qDebug() << "[LanPage] construct active connection area get Active list size:" << activedList.size(); + if (!activedList.isEmpty()) { + for (int index = 0; index < activedList.size(); index++) { + KyConnectItem *p_activeConnectionItem = activedList.at(index); + qDebug() << "[LanPage] construct active connection area. add active item" + << p_activeConnectionItem->m_connectName; + QListWidgetItem *p_listWidgetItem = addNewItem(p_activeConnectionItem, m_activatedLanListWidget); + m_activeConnectionMap.insert(p_activeConnectionItem->m_connectUuid, p_listWidgetItem); + + int configType = NetworkModeConfig::getInstance()->getNetworkModeConfig(p_activeConnectionItem->m_connectUuid); + if (configType == -1) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(p_activeConnectionItem->m_connectUuid, + m_currentDeviceName, + p_activeConnectionItem->m_connectName, + KSC_FIREWALL_PUBLIC); + } else { + NetworkModeConfig::getInstance()->setNetworkModeConfig(p_activeConnectionItem->m_connectUuid, + m_currentDeviceName, + p_activeConnectionItem->m_connectName, + configType); + } + + delete p_activeConnectionItem; + p_activeConnectionItem = nullptr; + } + setNetSpeed->start(REFRESH_NETWORKSPEED_TIMER); + } else { + qDebug()<<"[LanPage] there is not active"; + addEmptyConnectItem(m_activeConnectionMap, m_activatedLanListWidget); + } + + return; +} + +void LanPage::constructConnectionArea() +{ + QList deactivedList; + + deactivedList.clear(); + clearConnectionMap(m_inactiveConnectionMap, m_inactivatedLanListWidget); + + m_connectResourse->getConnectionList(m_currentDeviceName, NetworkManager::ConnectionSettings::Wired, deactivedList); //未激活列表的显示 + qDebug() << "[LanPage]construct connection area get connection list size:" << deactivedList.size(); + if (!deactivedList.isEmpty()) { + for (int index = 0; index < deactivedList.size(); index++) { + KyConnectItem *p_deactiveConnectionItem = deactivedList.at(index); + qDebug()<<"[LanPage] construct connection area add deactive item"<m_connectName; + QListWidgetItem *p_listWidgetItem = addNewItem(p_deactiveConnectionItem, m_inactivatedLanListWidget); + if (m_inactiveConnectionMap.contains(p_deactiveConnectionItem->m_connectUuid)) { + qDebug()<m_connectUuid; + } + m_inactiveConnectionMap.insert(p_deactiveConnectionItem->m_connectUuid, p_listWidgetItem); + + delete p_deactiveConnectionItem; + p_deactiveConnectionItem = nullptr; + + } + } + if (m_inactivatedLanListWidget->count() <= MAX_ITEMS) { + m_inactivatedLanListWidget->setFixedWidth(MIN_WIDTH); + } else { + m_inactivatedLanListWidget->setFixedWidth(MAX_WIDTH); + } + return; +} + +void LanPage::initLanArea() +{ + if (!m_netSwitch->isChecked() || m_currentDeviceName.isEmpty()) { + m_activatedNetDivider->hide(); + m_activatedNetFrame->hide(); + + m_inactivatedNetFrame->hide(); + } else { + m_activatedNetDivider->show(); + m_activatedNetFrame->show(); + constructActiveConnectionArea(); + + m_inactivatedNetFrame->show(); + constructConnectionArea(); + } + + return; +} + +bool LanPage::removeConnectionItem(QMap &connectMap, + QListWidget *lanListWidget, QString path) +{ + QMap::iterator iter; + for (iter = connectMap.begin(); iter != connectMap.end(); ++iter) { + QListWidgetItem *p_listWidgetItem = iter.value(); + LanListItem *p_lanItem = (LanListItem*)lanListWidget->itemWidget(p_listWidgetItem); + if (p_lanItem->getConnectionPath() == path) { + qDebug()<<"[LanPage] Remove a connection from list"; + + lanListWidget->removeItemWidget(p_listWidgetItem); + + delete p_lanItem; + p_lanItem = nullptr; + + delete p_listWidgetItem; + p_listWidgetItem = nullptr; + + iter = connectMap.erase(iter); + if (m_inactivatedLanListWidget->count() <= MAX_ITEMS) { + m_inactivatedLanListWidget->setFixedWidth(MIN_WIDTH); + } + return true; + } + } + + return false; +} + +void LanPage::onRemoveConnection(QString path) //删除时后端会自动断开激活,将其从未激活列表中删除 +{ + //for dbus + qDebug() << "[LanPage] Q_EMIT lanRemove because onRemoveConnection " << path; + Q_EMIT lanRemove(path); + + if (removeConnectionItem(m_inactiveConnectionMap, m_inactivatedLanListWidget, path)) { + return; + } else { + removeConnectionItem(m_activeConnectionMap, m_activatedLanListWidget, path); + if (m_activeConnectionMap.count() <= 0) { + addEmptyConnectItem(m_activeConnectionMap, m_activatedLanListWidget); + } + + return; + } +} + +void LanPage::onAddConnection(QString uuid) //新增一个有线连接,将其加入到激活列表 +{ + if (!m_connectResourse->isWiredConnection(uuid)) { + return; + } + + KyConnectItem *p_newItem = nullptr; + p_newItem = m_connectResourse->getConnectionItemByUuid(uuid); + if (nullptr == p_newItem) { + return; + } + + sendLanAddSignal(p_newItem); + + if (p_newItem->m_ifaceName == m_currentDeviceName || p_newItem->m_ifaceName == "") { + qDebug()<<"[LanPage] Add a new connection, name:"<m_connectName; + QListWidgetItem *p_listWidgetItem = insertNewItem(p_newItem, m_inactivatedLanListWidget); + if (m_inactiveConnectionMap.contains(p_newItem->m_connectUuid)) { + qDebug()<m_connectUuid; + } + m_inactiveConnectionMap.insert(p_newItem->m_connectUuid, p_listWidgetItem); + } + + delete p_newItem; + p_newItem = nullptr; + if (m_inactivatedLanListWidget->count() > MAX_ITEMS) { + m_inactivatedLanListWidget->setFixedWidth(MAX_WIDTH); + } +} + +void LanPage::addDeviceForCombox(QString deviceName) +{ + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); + + if (m_netSwitch->isChecked()) { + if (1 == m_enableDeviceList.count()) { + //1、从无到有添加第一块有线网卡 + //2、有多快网卡,但是没有使能 + m_deviceFrame->hide(); + m_currentDeviceName = deviceName; + setDefaultDevice(WIRED, m_currentDeviceName); + } else if (2 == m_enableDeviceList.count()) { + //3、现在有且只有一块网卡,并已使能 + //4、有多快网卡,且使能了其中一块 + m_deviceComboBox->addItem(m_currentDeviceName); + m_deviceComboBox->addItem(deviceName); + + m_deviceFrame->show(); + m_tipsLabel->hide(); + m_deviceComboBox->show(); + } else if (m_enableDeviceList.count() > 2) { + //5、有多快网卡且使能了多块网卡 + m_deviceComboBox->addItem(deviceName); + } + } + + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); +} + +void LanPage::onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType) +{ + if (!m_deviceResource->deviceIsWired(deviceName)) { + return; + } + + if (m_devList.contains(deviceName)) { + return; + } + + if (m_devList.count() == 0) {// 有线网卡从无到有,打开开关 + bool wiredSwitch = m_switchGsettings->get(WIRED_SWITCH).toBool(); + m_netSwitch->setCheckable(true); + m_netSwitch->setChecked(wiredSwitch); + } + + qDebug() << "[LanPage] Begin add device:" << deviceName; + + m_devList << deviceName; + if (m_deviceResource->getDeviceManaged(deviceName)) { + m_enableDeviceList << deviceName; + addDeviceForCombox(deviceName); + if (m_currentDeviceName == deviceName) { + initLanArea(); + } + } else { + m_disableDeviceList << deviceName; + } + + Q_EMIT deviceStatusChanged(); +} + +void LanPage::deleteDeviceFromCombox(QString deviceName) +{ + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); + + if (m_netSwitch->isChecked()) { + if (0 == m_enableDeviceList.count()) { + //1、没有使能任何网卡 + goto l_out; + } else if (1 == m_enableDeviceList.count()) { + //2、使能了一个网卡,且当前网卡是要删除的网卡 + if (m_currentDeviceName == deviceName) { + m_deviceFrame->show(); + m_deviceComboBox->hide(); + m_tipsLabel->show(); + m_currentDeviceName = ""; + setDefaultDevice(WIRED, m_currentDeviceName); + } + } else if (2 == m_enableDeviceList.count()) { + //3、使能了两个网卡,且包括要删除的网卡,有可能是要删除的网卡 + if (m_deviceComboBox->findText(deviceName) != -1) { + for (int index = m_deviceComboBox->count() - 1; index >= 0; index--) { + if (m_currentDeviceName == deviceName + && m_deviceComboBox->itemText(index) != deviceName) { + m_currentDeviceName = m_deviceComboBox->itemText(index); + setDefaultDevice(WIRED, m_currentDeviceName); + } + m_deviceComboBox->removeItem(index); + } + + m_tipsLabel->hide(); + m_deviceFrame->hide(); + m_deviceComboBox->hide(); + } + } else { + //4、使能了多个网卡,且包括要删除的网卡,有可能是正要删除的网卡 + int index = m_deviceComboBox->findText(deviceName); + if (index != -1) { + m_deviceComboBox->removeItem(index); + if (m_currentDeviceName == deviceName) { + m_currentDeviceName = m_deviceComboBox->currentText(); + setDefaultDevice(WIRED, m_currentDeviceName); + } + } + } + } + +l_out: + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &LanPage::onDeviceComboxIndexChanged); + + return; +} + +void LanPage::onDeviceRemove(QString deviceName) +{ + if (!m_devList.contains(deviceName)) { + return; + } + + qDebug() << "[LanPage] deviceRemove:" << deviceName; + + m_devList.removeOne(deviceName); + if (m_devList.count() == 0) { + m_netSwitch->setChecked(false); + m_netSwitch->setCheckable(false); + qDebug() << "[wiredSwitch]set not enable after device remove"; + } + + QString nowDevice = m_currentDeviceName; + deleteDeviceFromCombox(deviceName); + if (nowDevice == deviceName) { + setDefaultDevice(WIRED, m_currentDeviceName); + initLanArea(); + } + + if (m_enableDeviceList.contains(deviceName)) { + m_enableDeviceList.removeOne(deviceName); + } + if (m_disableDeviceList.contains(deviceName)) { + m_disableDeviceList.removeOne(deviceName); + } + + Q_EMIT deviceStatusChanged(); +} + +void LanPage::updateDeviceCombox(QString oldDeviceName, QString newDeviceName) +{ + if (m_currentDeviceName == oldDeviceName) { + m_currentDeviceName = newDeviceName; + setDefaultDevice(WIRED, m_currentDeviceName); + } + + int index = m_deviceComboBox->findText(oldDeviceName); + if (index != -1) { + m_deviceComboBox->setItemText(index, newDeviceName); + } + + return; +} + +void LanPage::onDeviceNameUpdate(QString oldName, QString newName) +{ + if (m_devList.contains(oldName)) { + m_devList.removeOne(oldName); + m_devList.append(newName); + + if (m_enableDeviceList.contains(oldName)) { + m_enableDeviceList.removeOne(oldName); + m_enableDeviceList.append(newName); + } else if (m_disableDeviceList.contains(oldName)) { + m_disableDeviceList.removeOne(oldName); + m_disableDeviceList.append(newName); + } + qDebug() << "[LanPage] Q_EMIT deviceNameUpdate " << oldName << newName; + + updateDeviceCombox(oldName, newName); + if (m_currentDeviceName == newName) { + initLanArea(); + } + + Q_EMIT deviceNameChanged(oldName, newName, WIRED); + } +} + +void LanPage::onDeviceCarriered(QString deviceName, bool pluged) +{ + if (!pluged) { + return; + } + if (m_enableDeviceList.contains(deviceName)) { + updateCurrentDevice(deviceName); + } +} + +void LanPage::onDeviceActiveChanage(QString deviceName, bool deviceActive) +{ +// if (!m_devList.contains(deviceName)) { +// return; +// } + +// if (deviceActive) { +// if (!m_netSwitch->isChecked() || !m_enableDeviceList.contains(deviceName)) { +// qDebug()<< LOG_FLAG << "close disabled device"; +// m_wiredConnectOperation->closeWiredNetworkWithDevice(deviceName); +// } +// } + +// return; +} + +void LanPage::onDeviceManagedChange(QString deviceName, bool managed) +{ + initLanDeviceState(); + initDeviceCombox(); + initLanArea(); + Q_EMIT deviceStatusChanged(); +} + + +void LanPage::onDeviceComboxIndexChanged(int currentIndex) +{ + //TODO 设备变更时更新设备和列表 + m_currentDeviceName = m_deviceComboBox->currentText(); + qDebug() << "[LanPage]Current Device Changed to:" << m_currentDeviceName; + initLanArea(); +} + +void LanPage::onShowControlCenter() +{ + QProcess process; + process.startDetached("ukui-control-center -m netconnect"); +} + +void LanPage::initUI() +{ + m_titleLabel->setText(tr("LAN")); + + m_activatedNetLabel->setText(tr("Activated LAN")); + m_activatedLanListWidget = new QListWidget(m_activatedNetFrame); + m_activatedLanListWidget->setFrameShape(QFrame::Shape::NoFrame); + m_activatedLanListWidget->setSpacing(LAN_LIST_SPACING); + m_activatedLanListWidget->setFixedHeight(ITEM_HEIGHT); //active区域固定高度,只显示一个条目 + m_activatedLanListWidget->setFixedWidth(MIN_WIDTH); + m_activatedLanListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_activatedLanListWidget->setProperty("needTranslucent", true); + m_activatedNetLayout->addWidget(m_activatedLanListWidget); + + m_inactivatedNetLabel->setText(tr("Inactivated LAN")); + m_inactivatedLanListWidget = new QListWidget(m_inactivatedNetListArea); + m_inactivatedLanListWidget->setFrameShape(QFrame::Shape::NoFrame); + m_inactivatedLanListWidget->setSpacing(LAN_LIST_SPACING); + m_inactivatedLanListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_inactivatedLanListWidget->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + m_inactivatedLanListWidget->verticalScrollBar()->setProperty("drawScrollBarGroove",false); //去除滚动条的外侧黑框 + m_inactivatedLanListWidget->verticalScrollBar()->setSingleStep(SCROLL_STEP); + m_inactivatedLanListWidget->verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu); + m_inactivatedLanListWidget->verticalScrollBar()->setProperty("needTranslucent", true); + m_inactivatedLanListWidget->setProperty("needTranslucent", true); + m_inactivatedAreaLayout->addWidget(m_inactivatedLanListWidget); + + QPalette pal = m_activatedLanListWidget->palette(); + pal.setBrush(QPalette::Base, QColor(0,0,0,0)); //背景透明 + m_activatedLanListWidget->setPalette(pal); + m_inactivatedLanListWidget->setPalette(pal); + + m_settingsLabel->installEventFilter(this); + m_netSwitch->installEventFilter(this); + + showRate(); +} + +QListWidgetItem *LanPage::insertNewItem(KyConnectItem *itemData, QListWidget *listWidget) +{ + int index = 0; + + for(index = 0; index < m_inactivatedLanListWidget->count(); index++) { + QListWidgetItem *p_listWidgetItem = m_inactivatedLanListWidget->item(index); + LanListItem *p_lanItem = (LanListItem *)m_inactivatedLanListWidget->itemWidget(p_listWidgetItem); + QString name1 = p_lanItem->getConnectionName(); + QString name2 = itemData->m_connectName; + if (QString::compare(name1, name2, Qt::CaseInsensitive) > 0) { + break; + } + } + + QListWidgetItem *p_sortListWidgetItem = new QListWidgetItem(); + p_sortListWidgetItem->setFlags(p_sortListWidgetItem->flags() & (~Qt::ItemIsSelectable)); //设置不可被选中 + p_sortListWidgetItem->setSizeHint(QSize(listWidget->width(),ITEM_HEIGHT)); + + listWidget->insertItem(index, p_sortListWidgetItem); + + LanListItem *p_sortLanItem = nullptr; + p_sortLanItem = new LanListItem(itemData, m_currentDeviceName); + listWidget->setItemWidget(p_sortListWidgetItem, p_sortLanItem); + + return p_sortListWidgetItem; +} + +QListWidgetItem *LanPage::addNewItem(KyConnectItem *itemData, QListWidget *listWidget) +{ + QListWidgetItem *p_listWidgetItem = new QListWidgetItem(); + p_listWidgetItem->setFlags(p_listWidgetItem->flags() & (~Qt::ItemIsSelectable)); + p_listWidgetItem->setSizeHint(QSize(listWidget->width(), ITEM_HEIGHT)); + listWidget->addItem(p_listWidgetItem); + LanListItem *p_lanItem = nullptr; + if (itemData != nullptr) { + p_lanItem = new LanListItem(itemData, m_currentDeviceName); + qDebug() << "[LanPage] addNewItem, connection: " + << itemData->m_connectName << "deviceName: " << m_currentDeviceName; + } else { + p_lanItem = new LanListItem(); + qDebug() << "[LanPage] Add nullItem!"; + } + + listWidget->setItemWidget(p_listWidgetItem, p_lanItem); + return p_listWidgetItem; +} + +void LanPage::updateActivatedConnectionArea(KyConnectItem *p_newItem) +{ + if (m_activeConnectionMap.contains(p_newItem->m_connectUuid)) { + return; + } + + deleteConnectionMapItem(m_inactiveConnectionMap, m_inactivatedLanListWidget, p_newItem->m_connectUuid); + if (p_newItem->m_ifaceName == m_currentDeviceName) { + qDebug()<<"[LanPage]update active connection item"<m_connectName; + deleteConnectionMapItem(m_activeConnectionMap, m_activatedLanListWidget, EMPTY_CONNECT_UUID); + QListWidgetItem *p_listWidgetItem = addNewItem(p_newItem, m_activatedLanListWidget); + m_activeConnectionMap.insert(p_newItem->m_connectUuid, p_listWidgetItem); +// this->showDesktopNotify(tr("LAN Connected Successfully"), "networkconnected"); + } + if (m_inactivatedLanListWidget->count() <= MAX_ITEMS) { + m_inactivatedLanListWidget->setFixedWidth(MIN_WIDTH); + } + + return; +} + +void LanPage::updateConnectionArea(KyConnectItem *p_newItem) +{ + if (m_inactiveConnectionMap.contains(p_newItem->m_connectUuid)) { + return; + } + + deleteConnectionMapItem(m_activeConnectionMap, m_activatedLanListWidget, p_newItem->m_connectUuid); + if (m_activeConnectionMap.count() <= 0) { + addEmptyConnectItem(m_activeConnectionMap, m_activatedLanListWidget); + } + + if (p_newItem->m_ifaceName == m_currentDeviceName || p_newItem->m_ifaceName == "") { + qDebug()<<"[LanPage] update connection item"<m_connectName; + QListWidgetItem *p_listWidgetItem = insertNewItem(p_newItem, m_inactivatedLanListWidget); + m_inactiveConnectionMap.insert(p_newItem->m_connectUuid, p_listWidgetItem); +// this->showDesktopNotify(tr("LAN Disconnected Successfully"), "networkdisconnected"); + } + if (m_inactivatedLanListWidget->count() <= MAX_ITEMS) { + m_inactivatedLanListWidget->setFixedWidth(MIN_WIDTH); + } else { + m_inactivatedLanListWidget->setFixedWidth(MAX_WIDTH); + } + + return; +} + +void LanPage::updateConnectionState(QMap &connectMap, + QListWidget *lanListWidget, QString uuid, ConnectState state) +{ + qDebug() << LOG_FLAG << "update connection state"; + + QListWidgetItem *p_listWidgetItem = connectMap.value(uuid); + if (p_listWidgetItem) { + LanListItem *p_lanItem = (LanListItem *)lanListWidget->itemWidget(p_listWidgetItem); + p_lanItem->updateConnectionState(state); + } + + return; +} + +QString LanPage::getConnectionDevice(QString uuid) +{ + QString deviceName = ""; + + deviceName = m_activeResourse->getDeviceOfActivateConnect(uuid); + if (deviceName.isEmpty()) { + m_connectResourse->getInterfaceByUuid(deviceName, uuid); + } + + return deviceName; +} + +void LanPage::updateCurrentDevice(QString deviceName) +{ + if (m_currentDeviceName != deviceName) { + int index = m_deviceComboBox->findText(deviceName); + if (index < 0) { + index = 0; + } + m_deviceComboBox->setCurrentIndex(index); + return; + } + return; +} + +void LanPage::onConnectionStateChange(QString uuid, + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason) +{ + //lanpage函数内持续监听连接状态的变化并记录供其他函数调用获取状态 + if (!m_connectResourse->isWiredConnection(uuid)) { + qDebug() << "[LanPage] connection state change signal but not wired"; + return; + } + + sendLanStateChangeSignal(uuid, (ConnectState)state); + + if (m_activeConnectionMap.keys().contains(uuid) && state == NetworkManager::ActiveConnection::State::Activated) { + return; + } + + qDebug()<<"[LanPage] connection uuid"<< uuid + << "state change slot:"<< state; + + KyConnectItem *p_newItem = nullptr; + QString deviceName = ""; + QString ssid = ""; + + if (state == NetworkManager::ActiveConnection::State::Activated) { + p_newItem = m_activeResourse->getActiveConnectionByUuid(uuid); + if (nullptr == p_newItem) { + qWarning()<<"[LanPage] get active connection failed, connection uuid" << uuid; + return; + } + + deviceName = p_newItem->m_ifaceName; + ssid = p_newItem->m_connectName; + + int configType = NetworkModeConfig::getInstance()->getNetworkModeConfig(uuid); + + if (configType == -1) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, deviceName, ssid, KSC_FIREWALL_PUBLIC); //默认公有配置 + FirewallDialog *fireWallDialog = new FirewallDialog(); + fireWallDialog->setUuid(uuid); + fireWallDialog->setWindowTitle(ssid); + + connect(fireWallDialog, &FirewallDialog::setPrivateNetMode, this, [=](){ + fireWallDialog->hide(); + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, deviceName, ssid, KSC_FIREWALL_PRIVATE); + }); + + connect(fireWallDialog, &FirewallDialog::setPublicNetMode, this, [=](){ + fireWallDialog->hide(); + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, deviceName, ssid, KSC_FIREWALL_PUBLIC); + }); + + connect(m_activeResourse, &KyActiveConnectResourse::stateChangeReason, fireWallDialog, &FirewallDialog::closeMyself); + + fireWallDialog->show(); + fireWallDialog->centerToScreen(); + + } else if (configType == KSC_FIREWALL_PUBLIC) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, deviceName, ssid, KSC_FIREWALL_PUBLIC); + } else if (configType == KSC_FIREWALL_PRIVATE) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, deviceName, ssid, KSC_FIREWALL_PRIVATE); + } + + updateActivatedConnectionArea(p_newItem); + updateConnectionState(m_activeConnectionMap, m_activatedLanListWidget, uuid, (ConnectState)state); + setNetSpeed->start(REFRESH_NETWORKSPEED_TIMER); + } else if (state == NetworkManager::ActiveConnection::State::Deactivated) { + p_newItem = m_connectResourse->getConnectionItemByUuidWithoutActivateChecking(uuid); + qDebug() << "[LanPage] deactivated reason" << reason; + if (nullptr == p_newItem) { + qWarning()<<"[LanPage] get active connection failed, connection uuid" << uuid; + return; + } + + deviceName = p_newItem->m_ifaceName; + ssid = p_newItem->m_connectName; + updateConnectionArea(p_newItem); + updateConnectionState(m_inactiveConnectionMap, m_inactivatedLanListWidget, uuid, (ConnectState)state); + NetworkModeConfig::getInstance()->breakNetworkConnect(uuid, deviceName, ssid); + setNetSpeed->stop(); + } else if (state == NetworkManager::ActiveConnection::State::Activating) { + deviceName = getConnectionDevice(uuid); + if (deviceName == m_currentDeviceName) { + updateConnectionState(m_inactiveConnectionMap, m_inactivatedLanListWidget, uuid, (ConnectState)state); + } + } else if (state == NetworkManager::ActiveConnection::State::Deactivating) { + deviceName = getConnectionDevice(uuid); + if (deviceName == m_currentDeviceName) { + updateConnectionState(m_activeConnectionMap, m_activatedLanListWidget, uuid, (ConnectState)state); + } + } + + Q_EMIT lanActiveConnectionStateChanged(deviceName, uuid, state); + + if (p_newItem) { + delete p_newItem; + p_newItem = nullptr; + } + + return; +} + + +void LanPage::getWiredList(QMap > &map) +{ + QStringList devlist; + m_deviceResource->getNetworkDeviceList(NetworkManager::Device::Type::Ethernet, devlist); + if (devlist.isEmpty()) { + return; + } + + Q_FOREACH (auto deviceName, devlist) { + QList activedList; + QList deactivedList; + QVector vector; + m_activeResourse->getActiveConnectionList(deviceName,NetworkManager::ConnectionSettings::Wired,activedList); + if (!activedList.isEmpty()) { + vector.append(QStringList() << activedList.at(0)->m_connectName << activedList.at(0)->m_connectUuid << activedList.at(0)->m_connectPath); + } else { + vector.append(QStringList()<<("--")); + } + + m_connectResourse->getConnectionList(deviceName, NetworkManager::ConnectionSettings::Wired, deactivedList); //未激活列表的显示 + if (!deactivedList.isEmpty()) { + for (int i = 0; i < deactivedList.size(); i++) { + vector.append(QStringList()<m_connectName<m_connectUuid << deactivedList.at(i)->m_connectPath); + } + } + map.insert(deviceName, vector); + } + return; +} + +void LanPage::sendLanUpdateSignal(KyConnectItem *p_connectItem) +{ + QStringList info; + info << p_connectItem->m_connectName << p_connectItem->m_connectUuid << p_connectItem->m_connectPath; + Q_EMIT lanUpdate(p_connectItem->m_ifaceName, info); + + return; +} + +void LanPage::sendLanAddSignal(KyConnectItem *p_connectItem) +{ + QStringList info; + info << p_connectItem->m_connectName << p_connectItem->m_connectUuid << p_connectItem->m_connectPath; + qDebug() << "[LanPage] Q_EMIT lanAdd because addConnection "; + Q_EMIT lanAdd(p_connectItem->m_ifaceName, info); + + return; +} + +void LanPage::sendLanStateChangeSignal(QString uuid, ConnectState state) +{ + if (state == Activating || state == Deactivating) { + if (m_activeResourse->connectionIsVirtual(uuid)) { + return; + } + } + + Q_EMIT this->lanConnectChanged(state); + + return; +} + +void LanPage::updateConnectionProperty(KyConnectItem *p_connectItem) +{ + QString newUuid = p_connectItem->m_connectUuid; + + if (m_inactiveConnectionMap.contains(newUuid)) { + QListWidgetItem *p_listWidgetItem = m_inactiveConnectionMap.value(newUuid); + LanListItem *p_lanItem = (LanListItem*)m_inactivatedLanListWidget->itemWidget(p_listWidgetItem); + if (p_connectItem->m_ifaceName != "" + && m_currentDeviceName != p_connectItem->m_ifaceName) { + m_inactivatedLanListWidget->removeItemWidget(p_listWidgetItem); + + delete p_listWidgetItem; + p_listWidgetItem = nullptr; + + delete p_lanItem; + p_lanItem = nullptr; + + m_inactiveConnectionMap.remove(newUuid); + } else { + if (p_connectItem->m_connectName != p_lanItem->getConnectionName()){ + //只要名字改变就要删除,重新插入,主要是为了排序 + deleteConnectionMapItem(m_inactiveConnectionMap, m_inactivatedLanListWidget, newUuid); + QListWidgetItem *p_sortListWidgetItem = insertNewItem(p_connectItem, m_inactivatedLanListWidget); + if (m_inactiveConnectionMap.contains(newUuid)) { + qDebug()<m_connectPath != p_lanItem->getConnectionPath()) { + p_lanItem->updateConnectionPath(p_connectItem->m_connectPath); + } + } + + } else if (!m_activeConnectionMap.contains(newUuid)){ + if (p_connectItem->m_ifaceName == m_currentDeviceName + || p_connectItem->m_ifaceName.isEmpty()) { + QListWidgetItem *p_listWidgetItem = insertNewItem(p_connectItem, m_inactivatedLanListWidget); + if (m_inactiveConnectionMap.contains(newUuid)) { + qDebug()<m_connectUuid; + + if (m_activeConnectionMap.contains(newUuid)) { + QListWidgetItem *p_listWidgetItem = m_activeConnectionMap.value(newUuid); + LanListItem *p_lanItem = (LanListItem *)m_activatedLanListWidget->itemWidget(p_listWidgetItem); + if (m_currentDeviceName != p_connectItem->m_ifaceName) { + m_activeConnectionMap.remove(newUuid); + int takeRow = m_activatedLanListWidget->row(p_listWidgetItem); + m_activatedLanListWidget->takeItem(takeRow); + + delete p_lanItem; + p_lanItem = nullptr; + + p_lanItem = new LanListItem(); + m_activatedLanListWidget->addItem(p_listWidgetItem); + m_activatedLanListWidget->setItemWidget(p_listWidgetItem, p_lanItem); + m_activeConnectionMap.insert(EMPTY_CONNECT_UUID, p_listWidgetItem); + } else { + if (p_lanItem->getConnectionName() != p_connectItem->m_connectName) { + p_lanItem->updateConnectionName(p_connectItem->m_connectName); + } + + if (p_lanItem->getConnectionName() != p_connectItem->m_connectPath) { + p_lanItem->updateConnectionPath(p_connectItem->m_connectPath); + } + + } + } + + return; +} + +void LanPage::onUpdateConnection(QString uuid) +{ + if (!m_connectResourse->isWiredConnection(uuid)) { + return; + } + + qDebug() << "[LanPage]:Connection property Changed." << Q_FUNC_INFO << __LINE__; + + KyConnectItem *p_newItem = nullptr; + if (m_connectResourse->isActivatedConnection(uuid)) { + p_newItem = m_activeResourse->getActiveConnectionByUuid(uuid); + if (nullptr == p_newItem) { + qWarning()<<"[LanPage] get item failed, when update activate connection." + <<"connection uuid" << uuid; + return; + } + + updateActiveConnectionProperty(p_newItem); + } else { + p_newItem = m_connectResourse->getConnectionItemByUuid(uuid); + if (nullptr == p_newItem) { + qWarning()<<"[LanPage] get item failed, when update connection." + <<"connection uuid"<setDeviceManaged(devName, enable); +} + +bool LanPage::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == m_settingsLabel) { + if (event->type() == QEvent::MouseButtonRelease) { + onShowControlCenter(); + } + } else if(watched == m_netSwitch){ + if (event->type() == QEvent::MouseButtonRelease) { + qDebug()<<"[LanPage] On lan switch button clicked! Status:" <isChecked() + <<"devices count:"<showDesktopNotify(tr("No ethernet device avaliable"), "networkwrong"); + m_netSwitch->setChecked(false); + m_netSwitch->setCheckable(false); + } + } + + } + + return QWidget::eventFilter(watched, event); +} + +void LanPage::onWiredEnabledChanged(bool enabled) +{ + if (m_devList.isEmpty()) { + qDebug() << "[LanPage] have no device to use " << Q_FUNC_INFO << __LINE__; + return; + } + + if (m_netSwitch->isChecked() == enabled) { + return; + } else { + m_switchGsettings->set(WIRED_SWITCH, enabled); + } +} + +void LanPage::activateWired(const QString& devName, const QString& connUuid) +{ + qDebug() << "[LanPage] activateWired" << devName << connUuid; + if (!m_deviceResource->wiredDeviceIsCarriered(devName)) { + qDebug() << LOG_FLAG << devName << "is not carried, so can not activate connection"; + this->showDesktopNotify(tr("Wired Device not carried"), "networkwrong"); + } else { + m_wiredConnectOperation->activateConnection(connUuid, devName); + } +} + +void LanPage::deactivateWired(const QString& devName, const QString& connUuid) +{ + qDebug() << "[LanPage] deactivateWired" << devName << connUuid; + QString name(""); + m_wiredConnectOperation->deactivateWiredConnection(name, connUuid); +} + +void LanPage::showDetailPage(QString devName, QString uuid) +{ + KyConnectItem *p_item = nullptr; + bool isActive = true; + + if (m_connectResourse->isActivatedConnection(uuid)) { + p_item = m_activeResourse->getActiveConnectionByUuid(uuid); + isActive = true; + } else { + p_item = m_connectResourse->getConnectionItemByUuid(uuid); + isActive = false; + } + + if (nullptr == p_item) { + qWarning()<<"[LanPage] GetConnectionItemByUuid is empty when showDetailPage." + <<"device name"<m_connectName, uuid, isActive, false, false); + netDetail->show(); + + delete p_item; + p_item = nullptr; +} + +bool LanPage::lanIsConnected() +{ + if (m_activeResourse->wiredConnectIsActived()) { + return true; + } else { + return false; + } +} + +void LanPage::showRate() +{ + //定时获取网速 + setNetSpeed = new QTimer(this); + setNetSpeed->setTimerType(Qt::PreciseTimer); + connect(setNetSpeed, &QTimer::timeout, [&]() { + onSetNetSpeed(m_activatedLanListWidget, m_activeConnectionMap.contains(EMPTY_SSID), m_currentDeviceName); + }); +} + diff --git a/src/frontend/tab-pages/lanpage.h b/src/frontend/tab-pages/lanpage.h new file mode 100644 index 00000000..32da0a91 --- /dev/null +++ b/src/frontend/tab-pages/lanpage.h @@ -0,0 +1,158 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef LANPAGE_H +#define LANPAGE_H + +#include "divider.h" +#include +#include +#include +#include +#include +#include +#include + +#include "list-items/listitem.h" +#include "list-items/lanlistitem.h" +#include "tab-pages/tabpage.h" + +class LanListItem; + +class LanPage : public TabPage +{ + Q_OBJECT +public: + explicit LanPage(QWidget *parent = nullptr); + ~LanPage(); + + //for dbus + void getWiredList(QMap > &map); + void activateWired(const QString& devName, const QString& connUuid); + void deactivateWired(const QString& devName, const QString& connUuid); + void showDetailPage(QString devName, QString uuid); + void setWiredDeviceEnable(const QString& devName, bool enable); + + bool lanIsConnected(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + void initLanDevice(); + void initUI(); + void initLanArea(); + void initNetSwitch(); + void initLanDeviceState(); + + void initDeviceCombox(); + void updateDeviceCombox(QString oldDeviceName, QString newDeviceName); + void deleteDeviceFromCombox(QString deviceName); + void addDeviceForCombox(QString deviceName); + + QListWidgetItem *insertNewItem(KyConnectItem *itemData, QListWidget *listWidget); + QListWidgetItem *addNewItem(KyConnectItem *itemData, QListWidget *listWidget); + bool removeConnectionItem(QMap &connectMap, + QListWidget *lanListWidget, QString path); + + void getEnabledDevice(QStringList &enableDeviceList); + void getDisabledDevices(QStringList &disableDeviceList); + + void constructConnectionArea(); + void constructActiveConnectionArea(); + + void updateConnectionArea(KyConnectItem *p_newItem); + void updateActivatedConnectionArea(KyConnectItem *p_newItem); + void updateConnectionState(QMap &connectMap, + QListWidget *lanListWidget, QString uuid, ConnectState state); + QString getConnectionDevice(QString uuid); + + void updateActiveConnectionProperty(KyConnectItem *p_connectItem); + void updateConnectionProperty(KyConnectItem *p_connectItem); + + void sendLanUpdateSignal(KyConnectItem *p_connectItem); + void sendLanAddSignal(KyConnectItem *p_connectItem); + void sendLanStateChangeSignal(QString uuid, ConnectState state); + + void addEmptyConnectItem(QMap &connectMap, + QListWidget *lanListWidget); + void clearConnectionMap(QMap &connectMap, + QListWidget *lanListWidget); + void deleteConnectionMapItem(QMap &connectMap, + QListWidget *lanListWidget, QString uuid); + + void updateCurrentDevice(QString deviceName); + void showRate(); + +Q_SIGNALS: + void lanAdd(QString devName, QStringList info); + void lanRemove(QString dbusPath); + void lanUpdate(QString devName, QStringList info); + + void lanActiveConnectionStateChanged(QString interface, QString uuid, int status); + void lanConnectChanged(int state); + + void showLanRate(QListWidget *widget, QMap &map, QString dev, bool isLan); + +private Q_SLOTS: + void onConnectionStateChange(QString uuid, NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason); + + void onAddConnection(QString uuid); + void onRemoveConnection(QString path); + void onUpdateConnection(QString uuid); + + void onSwithGsettingsChanged(const QString &key); + + void onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType); + void onDeviceRemove(QString deviceName); + void onDeviceNameUpdate(QString oldName, QString newName); + void onDeviceManagedChange(QString deviceName, bool managed); + + void onDeviceCarriered(QString deviceName, bool pluged); + void onDeviceActiveChanage(QString deviceName, bool deviceActive); + + void onDeviceComboxIndexChanged(int currentIndex); + + void onShowControlCenter(); + + void onWiredEnabledChanged(bool); + +private: + QListWidget * m_activatedLanListWidget = nullptr; + QListWidget * m_inactivatedLanListWidget = nullptr; + + KyNetworkDeviceResourse *m_deviceResource = nullptr; + KyWiredConnectOperation *m_wiredConnectOperation = nullptr; + KyActiveConnectResourse *m_activeResourse = nullptr; //激活的连接 + KyConnectResourse *m_connectResourse = nullptr; //未激活的连接 + + QMap m_inactiveConnectionMap; + QMap m_activeConnectionMap; + + QString m_currentDeviceName; + QStringList m_devList; + QStringList m_enableDeviceList; + QStringList m_disableDeviceList; + + QGSettings *m_switchGsettings = nullptr; + +}; + +#endif // LANPAGE_H diff --git a/src/frontend/tab-pages/tab-pages.pri b/src/frontend/tab-pages/tab-pages.pri new file mode 100644 index 00000000..6d049be2 --- /dev/null +++ b/src/frontend/tab-pages/tab-pages.pri @@ -0,0 +1,12 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/lanpage.h \ + $$PWD/wlanpage.h \ + $$PWD/tabpage.h + +SOURCES += \ + $$PWD/lanpage.cpp \ + $$PWD/wlanpage.cpp \ + $$PWD/tabpage.cpp + diff --git a/src/frontend/tab-pages/tabpage.cpp b/src/frontend/tab-pages/tabpage.cpp new file mode 100644 index 00000000..3e7ef919 --- /dev/null +++ b/src/frontend/tab-pages/tabpage.cpp @@ -0,0 +1,458 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "tabpage.h" +#include +#include +#include +#include +#include +#include +#include + +#include"listitem.h" + +#define LOG_FLAG "[tabPage]" + +TabPage::TabPage(QWidget *parent) : QWidget(parent) +{ + initUI(); + connect(qApp, &QApplication::paletteChanged, this, &TabPage::onPaletteChanged); +} + +TabPage::~TabPage() +{ + delete m_titleDivider; + delete m_activatedNetDivider; + delete m_inactivatedNetDivider; +} + +void TabPage::initUI() +{ + m_mainLayout = new QVBoxLayout(this); + m_mainLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); + m_mainLayout->setSpacing(MAIN_LAYOUT_SPACING); + this->setLayout(m_mainLayout); + + m_titleFrame = new QFrame(this); + m_titleFrame->setFixedHeight(TITLE_FRAME_HEIGHT); + m_titleLayout = new QHBoxLayout(m_titleFrame); + m_titleLayout->setContentsMargins(TITLE_LAYOUT_MARGINS); + m_titleLabel = new QLabel(m_titleFrame); + m_netSwitch = new KSwitchButton(m_titleFrame); + m_netSwitch->setTranslucent(true); + m_titleLayout->addWidget(m_titleLabel); + m_titleLayout->addStretch(); + m_titleLayout->addWidget(m_netSwitch); + m_titleDivider = new Divider(this); + + //临时增加的下拉框选择网卡区域 + m_deviceFrame = new QFrame(this); + m_deviceFrame->setFixedHeight(TITLE_FRAME_HEIGHT); + m_deviceLayout = new QHBoxLayout(m_deviceFrame); + m_deviceLayout->setContentsMargins(DEVICE_LAYOUT_MARGINS); + m_deviceFrame->setLayout(m_deviceLayout); + m_deviceLabel = new QLabel(m_deviceFrame); + m_deviceLabel->setText(tr("Current Device")); + m_deviceComboBox = new QComboBox(m_deviceFrame); + m_deviceComboBox->setFixedWidth(DEVICE_COMBOBOX_WIDTH); + + m_tipsLabel = new QLabel(m_deviceFrame); + m_tipsLabel->setText(tr("Devices Closed!")); + m_deviceLayout->addWidget(m_deviceLabel); + m_deviceLayout->addStretch(); + m_deviceLayout->addWidget(m_deviceComboBox); + m_deviceLayout->addWidget(m_tipsLabel); + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &TabPage::onDeviceComboxIndexChanged); + + m_activatedNetFrame = new QFrame(this); + m_activatedNetFrame->setMaximumHeight(ACTIVE_AREA_MAX_HEIGHT); + m_activatedNetLayout = new QVBoxLayout(m_activatedNetFrame); + m_activatedNetLayout->setContentsMargins(ACTIVE_NET_LAYOUT_MARGINS); +// m_activatedNetLayout->setSpacing(NET_LAYOUT_SPACING); + m_activatedNetLabel = new QLabel(m_activatedNetFrame); + m_activatedNetLabel->setContentsMargins(TEXT_MARGINS); + m_activatedNetLabel->setFixedHeight(TEXT_HEIGHT); + m_activatedNetLayout->addWidget(m_activatedNetLabel); + m_activatedNetDivider = new Divider(this); + + m_inactivatedNetFrame = new QFrame(this); + m_inactivatedNetFrame->setMinimumHeight(INACTIVE_AREA_MIN_HEIGHT); + m_inactivatedNetLayout = new QVBoxLayout(m_inactivatedNetFrame); + m_inactivatedNetLayout->setContentsMargins(NET_LAYOUT_MARGINS); +// m_inactivatedNetLayout->setSpacing(NET_LAYOUT_SPACING); + m_inactivatedNetFrame->setLayout(m_inactivatedNetLayout); + + m_inactivatedNetLabel = new QLabel(m_inactivatedNetFrame); + m_inactivatedNetLabel->setContentsMargins(TEXT_MARGINS); + m_inactivatedNetLabel->setFixedHeight(TEXT_HEIGHT); + +// m_inactivatedNetListArea = new QScrollArea(m_inactivatedNetFrame); +// m_inactivatedNetListArea->setFrameShape(QFrame::Shape::NoFrame); +// m_inactivatedNetListArea->setWidgetResizable(true); +// m_inactivatedNetListArea->setBackgroundRole(QPalette::Base); +// m_inactivatedNetListArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +// m_inactivatedNetListArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_inactivatedNetListArea = new QWidget(m_inactivatedNetFrame); + m_inactivatedAreaLayout = new QVBoxLayout(m_inactivatedNetListArea); + m_inactivatedAreaLayout->setSpacing(MAIN_LAYOUT_SPACING); + m_inactivatedAreaLayout->setContentsMargins(MAIN_LAYOUT_MARGINS); +// m_inactivatedNetListArea->setLayout(m_inactivatedAreaLayout); + + m_inactivatedNetLayout->addWidget(m_inactivatedNetLabel); + m_inactivatedNetLayout->addWidget(m_inactivatedNetListArea); + + m_inactivatedNetDivider = new Divider(this); + m_settingsFrame = new QFrame(this); + m_settingsFrame->setFixedHeight(TITLE_FRAME_HEIGHT); + + m_settingsLayout = new QHBoxLayout(m_settingsFrame); + m_settingsLayout->setContentsMargins(SETTINGS_LAYOUT_MARGINS); + +// m_settingsBtn = new KBorderlessButton(m_settingsFrame); +// m_settingsBtn->setText(tr("Settings")); +// m_settingsLayout->addWidget(m_settingsBtn); + + m_settingsLabel = new KyLable(m_settingsFrame); + m_settingsLabel->setCursor(Qt::PointingHandCursor); + m_settingsLabel->setText(tr("Settings")); + m_settingsLabel->setScaledContents(true); + + m_settingsLayout->addWidget(m_settingsLabel); + m_settingsLayout->addStretch(); + m_settingsFrame->setLayout(m_settingsLayout); + + m_mainLayout->addWidget(m_titleFrame); + //临时增加的设备选择区域 + m_mainLayout->addWidget(m_deviceFrame); + m_mainLayout->addWidget(m_titleDivider); + m_mainLayout->addWidget(m_activatedNetFrame); + m_mainLayout->addWidget(m_activatedNetDivider); + m_mainLayout->addWidget(m_inactivatedNetFrame); + m_mainLayout->addStretch(); + m_mainLayout->addWidget(m_inactivatedNetDivider); + m_mainLayout->addWidget(m_settingsFrame); + +// QPalette pal = m_inactivatedNetListArea->palette(); +// pal.setBrush(QPalette::Base, QColor(0,0,0,0)); //背景透明 +// m_inactivatedNetListArea->setPalette(pal); + + onPaletteChanged(); +} + +void TabPage::onPaletteChanged() +{ + QPalette labPal = m_activatedNetLabel->palette(); + QColor color = qApp->palette().color(QPalette::PlaceholderText); + labPal.setColor(QPalette::WindowText, color); + m_activatedNetLabel->setPalette(labPal); + m_inactivatedNetLabel->setPalette(labPal); + + if (m_deviceComboBox->view()) { + QPalette view_pal = m_deviceComboBox->view()->palette(); + QColor view_color = qApp->palette().color(QPalette::Active, QPalette::Button); + view_pal.setColor(QPalette::Base, view_color); + m_deviceComboBox->setPalette(view_pal); + m_deviceComboBox->view()->setPalette(view_pal); + } +} + +int TabPage::getCurrentLoadRate(QString dev, long *save_rate, long *tx_rate) +{ + FILE * net_dev_file; //文件指针 + char buffer[1024]; //文件中的内容暂存在字符缓冲区里 + //size_t bytes_read; //实际读取的内容大小 + char * match; //用以保存所匹配字符串及之后的内容 + char * device;//将QString转为Char * + QByteArray ba = dev.toLatin1(); // must + device = ba.data(); + int counter = 0; + //int i = 0; + char tmp_value[128]; + + if ((NULL == device) || (NULL == save_rate) || (NULL == tx_rate)) { + qDebug() << LOG_FLAG << "parameter pass error" ; + return -1; + } + + if ((net_dev_file = fopen("/proc/net/dev", "r")) == NULL) { + //打开文件/pro/net/dev/,从中读取流量数据 + qDebug() << LOG_FLAG << "error occurred when try to open file /proc/net/dev/"; + return -1; + } + memset(buffer, 0, sizeof(buffer)); + + while (fgets(buffer, sizeof(buffer), net_dev_file) != NULL) { + match = strstr(buffer, device); + + if (NULL == match) { + // qDebug()<<"No eth0 keyword to find!"; + continue; + } else { + match = match + strlen(device) + strlen(":"); //地址偏移到冒号 + sscanf(match, "%ld ", save_rate); + memset(tmp_value, 0, sizeof(tmp_value)); + sscanf(match, "%s ", tmp_value); + match = match + strlen(tmp_value); + for (size_t i=0; iitem(0); + ListItem *p_item = (ListItem *)m_activatedNetListWidget->itemWidget(activeitem); + if (isEmpty) { + p_item->m_lbLoadUp->hide(); + p_item->m_lbLoadDown->hide(); + p_item->m_lbLoadDownImg->hide(); + p_item->m_lbLoadUpImg->hide(); + return; + } + + if (this->isVisible()) { + + if (getCurrentLoadRate(dev, &start_rcv_rates, &start_tx_rates) == -1) { + start_rcv_rates = end_rcv_rates; + return; + } + + long int delta_rcv = (start_rcv_rates - end_rcv_rates) / 1024; + long int delta_tx = (start_tx_rates - end_tx_rates) / 1024; + + //简易滤波 + if (delta_rcv < 0 || delta_tx < 0) { + delta_rcv = 0; + delta_tx = 0; + } + else if (end_rcv_rates == 0 || end_tx_rates == 0){ + delta_rcv = 0; + delta_tx = 0; + } + + end_rcv_rates = start_rcv_rates; + end_tx_rates = start_tx_rates; + + int rcv_num = delta_rcv; + int tx_num = delta_tx; + + QString str_rcv = 0; + QString str_tx = 0; + + if (rcv_num < 1024) { + str_rcv = QString::number(rcv_num) + "KB/s"; + } else { + int remainder; + if (rcv_num % 1024 < 100) { + remainder = 0; + } else { + remainder = (rcv_num % 1024) / 100; + } + str_rcv = QString::number(rcv_num / 1024) + "." + QString::number(remainder) + "MB/s"; + } + + if (tx_num < 1024) { + str_tx = QString::number(tx_num) + "KB/s"; + } else { + int remainder; + if (tx_num % 1024 < 100) { + remainder = 0; + } else { + remainder = (tx_num % 1024)/100; + } + str_tx = QString::number(tx_num / 1024) + "." + QString::number(remainder) + "MB/s"; + } + p_item->m_lbLoadDown->setText(str_rcv); + p_item->m_lbLoadUp->setText(str_tx); + if (!p_item->m_hoverButton->isVisible()) { + p_item->m_lbLoadDown->show(); + p_item->m_lbLoadUp->show(); + p_item->m_lbLoadDownImg->show(); + p_item->m_lbLoadUpImg->show(); + } + } +} + +void TabPage::showDesktopNotify(const QString &message, QString soundName) +{ + QDBusInterface iface("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications", + QDBusConnection::sessionBus()); + QStringList actions; //跳转动作 + actions.append("kylin-nm"); + actions.append("default"); //默认动作:点击消息体时打开麒麟录音 + QMap hints; + if (!soundName.isEmpty()) { + hints.insert("sound-name",soundName); //添加声音 + } + QList args; + args<<(tr("Kylin NM")) + <<((unsigned int) 0) + <beginGroup("DEFAULTCARD"); + defaultDevice = m_settings->value(key).toString(); + m_settings->endGroup(); + + delete m_settings; + m_settings = nullptr; + + return defaultDevice; +} + +void setDefaultDevice(KyDeviceType deviceType, QString deviceName) +{ + QString key; + switch (deviceType) { + case WIRED: + key = "wired"; + break; + case WIRELESS: + key = "wireless"; + break; + default: + return; + } + + QSettings * m_settings = new QSettings(CONFIG_FILE_PATH, QSettings::IniFormat); + m_settings->beginGroup("DEFAULTCARD"); + m_settings->setValue(key, deviceName); + m_settings->endGroup(); + m_settings->sync(); + + delete m_settings; + m_settings = nullptr; +} + +bool checkDeviceExist(KyDeviceType deviceType, QString deviceName) +{ + NetworkManager::Device::Type type; + switch (deviceType) { + case WIRED: + type = NetworkManager::Device::Type::Ethernet; + break; + case WIRELESS: + type = NetworkManager::Device::Type::Wifi; + break; + default: + return false; + break; + } + + KyNetworkDeviceResourse * kdr = new KyNetworkDeviceResourse(); + QStringList devList; + devList.clear(); + + kdr->getNetworkDeviceList(type, devList); + delete kdr; + return devList.contains(deviceName); +} + +void getDeviceEnableState(int type, QMap &map) +{ + map.clear(); + if (type != WIRED && type != WIRELESS) { + qDebug() << "getDeviceEnableState but wrong type"; + return; + } + + KyNetworkDeviceResourse * kdr = new KyNetworkDeviceResourse(); + QStringList wiredDevList,wirelessDevList; + wiredDevList.clear(); + wirelessDevList.clear(); + + if (type == WIRED) { + kdr->getNetworkDeviceList(NetworkManager::Device::Type::Ethernet, wiredDevList); + if (!wiredDevList.isEmpty()) { + for (int i = 0; i < wiredDevList.size(); ++i) { + QString devName = wiredDevList.at(i); + map.insert(devName, kdr->getDeviceManaged(devName)); + } + } + } else if (type == WIRELESS) { + kdr->getNetworkDeviceList(NetworkManager::Device::Type::Wifi, wirelessDevList); + if (!wirelessDevList.isEmpty()) { + for (int i = 0; i < wirelessDevList.size(); ++i) { + QString devName = wirelessDevList.at(i); + map.insert(devName, kdr->getDeviceManaged(devName)); + } + } + } + + delete kdr; + kdr = nullptr; +} + +bool getOldVersionWiredSwitchState(bool state) +{ + QSettings * m_settings = new QSettings(CONFIG_FILE_PATH, QSettings::IniFormat); + QVariant value = m_settings->value("lan_switch_opened"); + + if (!value.isValid()) { + delete m_settings; + m_settings = nullptr; + return false; + } + state = value.toBool(); + m_settings->remove("lan_switch_opened"); + delete m_settings; + m_settings = nullptr; + return true; +} diff --git a/src/frontend/tab-pages/tabpage.h b/src/frontend/tab-pages/tabpage.h new file mode 100644 index 00000000..de09b3ce --- /dev/null +++ b/src/frontend/tab-pages/tabpage.h @@ -0,0 +1,174 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef TABPAGE_H +#define TABPAGE_H + +#include "divider.h" +#include "kylable.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kylinnetworkdeviceresource.h" +#include "firewalldialog.h" +#include "kwidget.h" +#include "kswitchbutton.h" +//#include "kborderlessbutton.h" + +#define EMPTY_SSID "emptyssid" + +#define REFRESH_NETWORKSPEED_TIMER 1000 + +using namespace kdk; + +enum network_mode { + KSC_FIREWALL_PUBLIC = 0, + KSC_FIREWALL_PRIVATE +}; + +#define MAIN_LAYOUT_MARGINS 0,0,0,0 +#define MAIN_LAYOUT_SPACING 0 +#define TITLE_FRAME_HEIGHT 50 //TabWidget的tab和widget有间隙,和设计稿看起来一致就不能设为设计稿里的高度 +#define TITLE_LAYOUT_MARGINS 24,0,24,0 +#define DEVICE_LAYOUT_MARGINS 24,0,24,8 +#define DEVICE_COMBOBOX_WIDTH 180 +#define ACTIVE_NET_LAYOUT_MARGINS 8,8,8,8 +#define NET_LAYOUT_MARGINS 8,8,0,1 +#define NET_LAYOUT_SPACING 8 +#define NET_LIST_SPACING 0 +#define TEXT_MARGINS 16,0,0,0 +#define TEXT_HEIGHT 20 +//#define SCROLL_AREA_HEIGHT 200 +#define SETTINGS_LAYOUT_MARGINS 23,0,24,0 +#define TRANSPARENT_COLOR QColor(0,0,0,0) +#define INACTIVE_AREA_MIN_HEIGHT 170 +#define ACTIVE_AREA_MAX_HEIGHT 92 + +#define MAX_ITEMS 4 +#define MAX_WIDTH 412 +#define MIN_WIDTH 404 + +#define SCROLL_STEP 4 + +enum KyDeviceType +{ + WIRED, + WIRELESS +}; + +const QString CONFIG_FILE_PATH = QDir::homePath() + "/.config/ukui/kylin-nm.conf"; +bool checkDeviceExist(KyDeviceType deviceType, QString deviceName); +QString getDefaultDeviceName(KyDeviceType deviceType); +void setDefaultDevice(KyDeviceType deviceType, QString deviceName); +void getDeviceEnableState(int type, QMap &map); +bool getOldVersionWiredSwitchState(bool state); + +class TabPage : public QWidget +{ + Q_OBJECT +public: + explicit TabPage(QWidget *parent = nullptr); + ~TabPage(); + +// void updateDefaultDevice(QString &deviceName); +// QString getDefaultDevice(); + static void showDesktopNotify(const QString &message, QString soundName); + + void hideSetting() { + if (nullptr != m_settingsFrame) { + m_settingsFrame->hide(); + m_inactivatedNetDivider->hide(); + m_inactivatedNetFrame->setMinimumHeight(INACTIVE_AREA_MIN_HEIGHT + 100); + } + } + void showSetting() { + if (nullptr != m_settingsFrame) { + m_inactivatedNetFrame->setMinimumHeight(INACTIVE_AREA_MIN_HEIGHT); + m_settingsFrame->show(); + m_inactivatedNetDivider->show(); + } + } + +Q_SIGNALS: + void deviceStatusChanged(); + void deviceNameChanged(QString oldName, QString newName, int type); + void activateFailed(QString errorMessage); + void deactivateFailed(QString errorMessage); + +protected: + void initUI(); + int getCurrentLoadRate(QString dev, long *save_rate, long *tx_rate); +// virtual void initDevice() = 0;//初始化默认设备 + virtual void initDeviceCombox() = 0;//初始化设备选择下拉框 + QTimer *setNetSpeed = nullptr; + QVBoxLayout * m_mainLayout = nullptr; + QFrame * m_titleFrame = nullptr; + QHBoxLayout * m_titleLayout = nullptr; + QLabel * m_titleLabel = nullptr; + KSwitchButton * m_netSwitch = nullptr; + Divider * m_titleDivider = nullptr; + + QFrame * m_activatedNetFrame = nullptr; + QVBoxLayout * m_activatedNetLayout = nullptr; + QLabel * m_activatedNetLabel = nullptr; + Divider * m_activatedNetDivider = nullptr; + + QFrame * m_inactivatedNetFrame = nullptr; + QVBoxLayout * m_inactivatedNetLayout = nullptr; + QLabel * m_inactivatedNetLabel = nullptr; +// QScrollArea * m_inactivatedNetListArea = nullptr; + QWidget * m_inactivatedNetListArea = nullptr; + QVBoxLayout * m_inactivatedAreaLayout = nullptr; + + Divider * m_inactivatedNetDivider = nullptr; + + QFrame * m_settingsFrame = nullptr; + QHBoxLayout * m_settingsLayout = nullptr; + KyLable * m_settingsLabel = nullptr; +// KBorderlessButton *m_settingsBtn = nullptr; + + //临时增加的下拉框选择网卡区域 + QFrame * m_deviceFrame = nullptr; + QHBoxLayout * m_deviceLayout = nullptr; + QLabel * m_deviceLabel = nullptr; + QComboBox * m_deviceComboBox = nullptr; + QLabel * m_tipsLabel = nullptr; + + long int start_rcv_rates = 0; //保存开始时的流量计数 + long int end_rcv_rates = 0; //保存结束时的流量计数 + long int start_tx_rates = 0; //保存开始时的流量计数 + long int end_tx_rates = 0; //保存结束时的流量计数 + +public Q_SLOTS: + virtual void onDeviceComboxIndexChanged(int currentIndex) = 0; + void onPaletteChanged(); + +protected Q_SLOTS: + void onSetNetSpeed(QListWidget* m_activatedNetListWidget, bool isActive, QString dev); +}; + +#endif // TABPAGE_H diff --git a/src/frontend/tab-pages/wlanpage.cpp b/src/frontend/tab-pages/wlanpage.cpp new file mode 100644 index 00000000..eac23b4e --- /dev/null +++ b/src/frontend/tab-pages/wlanpage.cpp @@ -0,0 +1,1578 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wlanpage.h" +#include "kywirelessnetitem.h" +#include "networkmodeconfig.h" +#include +#include +#include +#include +#include + +#define AP_SCAN_INTERVAL (20*1000) +#define ICON_REFRESH_INTERVAL (5*1000) +#define LOG_FLAG "[WlanPage]" +#define LAN_PAGE_INDEX 0 + +const QString NotApConnection = "0"; +const QString IsApConnection = "1"; + +WlanPage::WlanPage(QWidget *parent) : TabPage(parent) +{ + qRegisterMetaType("NetworkManager::Device::State"); + qRegisterMetaType("NetworkManager::Device::StateChangeReason"); + m_wirelessNetResource = new KyWirelessNetResource(this); + m_activatedConnectResource = new KyActiveConnectResourse(this); + m_netDeviceResource=new KyNetworkDeviceResourse(this); + m_connectResource = new KyConnectResourse(this); + m_wirelessConnectOpreation = new KyWirelessConnectOperation(this); + + initDevice(); + initWlanUI(); + initWlanSwitchState(); + initDeviceCombox(); + initWlanArea(); + + initTimer(); + + connect(m_wirelessNetResource, &KyWirelessNetResource::wifiNetworkAdd, this, &WlanPage::onWlanAdded); + connect(m_wirelessNetResource, &KyWirelessNetResource::wifiNetworkRemove, this, &WlanPage::onWlanRemoved); + + connect(m_wirelessNetResource, &KyWirelessNetResource::signalStrengthChange, this, &WlanPage::signalStrengthChange); + connect(m_wirelessNetResource, &KyWirelessNetResource::secuTypeChange, this, &WlanPage::onSecurityTypeChange); + + connect(m_wirelessNetResource, &KyWirelessNetResource::connectionAdd, this, &WlanPage::onConnectionAdd); + connect(m_wirelessNetResource, &KyWirelessNetResource::connectionRemove, this, &WlanPage::onConnectionRemove); + + connect(m_activatedConnectResource, &KyActiveConnectResourse::stateChangeReason, + this, &WlanPage::onConnectionStateChanged); + + connect(m_netDeviceResource, &KyNetworkDeviceResourse::deviceAdd, this, &WlanPage::onDeviceAdd); + connect(m_netDeviceResource, &KyNetworkDeviceResourse::deviceRemove, this, &WlanPage::onDeviceRemove); + connect(m_netDeviceResource, &KyNetworkDeviceResourse::deviceNameUpdate, this, &WlanPage::onDeviceNameUpdate); + + connect(m_netDeviceResource, &KyNetworkDeviceResourse::stateChanged, this, &WlanPage::onWlanStateChanged); + + connect(m_wirelessConnectOpreation, &KyWirelessConnectOperation::activateConnectionError, this, &WlanPage::activateFailed); + connect(m_wirelessConnectOpreation, &KyWirelessConnectOperation::addAndActivateConnectionError, this, &WlanPage::activateFailed); + connect(m_wirelessConnectOpreation, &KyWirelessConnectOperation::deactivateConnectionError, this, &WlanPage::deactivateFailed); + + connect(m_wirelessConnectOpreation, &KyWirelessConnectOperation::wifiEnabledChanged, this, &WlanPage::onWifiEnabledChanged); + + connect(m_connectResource, &KyConnectResourse::connectivityChanged, this, &WlanPage::connectivityChanged); + connect(m_netSwitch, &KSwitchButton::clicked, this, [=](bool checked) { + //解决switchBtn不支持点击的情况下,点击按钮,有无线网卡后不自动开启的问题 + if (getSwitchBtnEnable()) { + setSwitchBtnState(!checked); + setWirelessEnable(checked); + } + }); +} + +bool WlanPage::eventFilter(QObject *w, QEvent *e) +{ + if (w == m_settingsLabel) { + if (e->type() == QEvent::MouseButtonRelease) { + //ZJP_TODO 打开控制面板 + qDebug() << LOG_FLAG <<"recive event show control center"; + showControlCenter(); + } + } else if (w == m_netSwitch) { + if (e->type() == QEvent::MouseButtonRelease) { + if (!getSwitchBtnEnable()) { + showDesktopNotify(tr("No wireless network card detected"), "networkwrong"); + //检测不到无线网卡不再触发click信号 + } + } + } + return QWidget::eventFilter(w,e); +} + +void WlanPage::initWlanUI() +{ + m_titleLabel->setText(tr("WLAN")); + + m_activatedNetLabel->setText(tr("Activated WLAN")); + m_activatedNetListWidget = new QListWidget(m_activatedNetFrame); + m_activatedNetListWidget->setFrameShape(QFrame::Shape::NoFrame); + m_activatedNetListWidget->setContentsMargins(MAIN_LAYOUT_MARGINS); + m_activatedNetListWidget->setSpacing(NET_LIST_SPACING); + m_activatedNetListWidget->setFixedHeight(NORMAL_HEIGHT); + m_activatedNetListWidget->setFixedWidth(MIN_WIDTH); + m_activatedNetListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_activatedNetListWidget->setProperty("needTranslucent", true); + m_activatedNetLayout->addWidget(m_activatedNetListWidget); + + m_inactivatedNetLabel->setText(tr("Other WLAN")); + m_inactivatedNetListWidget = new QListWidget(m_inactivatedNetListArea); + m_inactivatedNetListWidget->setContentsMargins(MAIN_LAYOUT_MARGINS); + m_inactivatedNetListWidget->setSpacing(NET_LIST_SPACING); + m_inactivatedNetListWidget->setFrameShape(QFrame::Shape::NoFrame); + m_inactivatedNetListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_inactivatedNetListWidget->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel); + m_inactivatedNetListWidget->verticalScrollBar()->setProperty("drawScrollBarGroove",false); //去除滚动条的外侧黑框 + m_inactivatedNetListWidget->verticalScrollBar()->setSingleStep(SCROLL_STEP); + m_inactivatedNetListWidget->verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu); + m_inactivatedNetListWidget->verticalScrollBar()->setProperty("needTranslucent", true); + m_inactivatedNetListWidget->setProperty("needTranslucent", true); + addWlanMoreItem(); + m_inactivatedAreaLayout->addWidget(m_inactivatedNetListWidget); + + QPalette pal = m_activatedNetListWidget->palette(); + pal.setBrush(QPalette::Base, QColor(0,0,0,0)); //背景透明 + m_activatedNetListWidget->setPalette(pal); + m_inactivatedNetListWidget->setPalette(pal); + + m_settingsLabel->installEventFilter(this); + m_netSwitch->installEventFilter(this); + + showRate(); +} + +bool WlanPage::getWirelessDevieceUseable() +{ + for (auto devname : m_devList) { + if (m_netDeviceResource->getDeviceState(devname) >= NetworkManager::Device::Disconnected) { + return true; + } + } + return false; +} + +void WlanPage::setWirelessEnable(bool state) +{ + m_wirelessConnectOpreation->setWirelessEnabled(state); + return; +} + +bool WlanPage::getWirelessEnable() +{ + return m_wirelessConnectOpreation->getWirelessEnabled(); +} + +void WlanPage::initWlanSwitchState() +{ + if (m_devList.isEmpty()) { + setSwitchBtnState(false); + setSwitchBtnEnable(false); + return ; + } + + setSwitchBtnEnable(true); + setSwitchBtnState(getWirelessDevieceUseable()); + return; +} + +void WlanPage::initTimer() +{ + m_scanTimer = new QTimer(this); + connect(m_scanTimer, &QTimer::timeout, this, &WlanPage::requestScan); + + m_refreshIconTimer = new QTimer(this); + connect(m_refreshIconTimer, &QTimer::timeout, this, &WlanPage::onRefreshIconTimer); + m_refreshIconTimer->start(ICON_REFRESH_INTERVAL); +} + +/** + * @brief WlanPage::initDevice 初始化默认网卡 + */ +void WlanPage::initDevice() +{ + m_devList.clear(); + m_netDeviceResource->getNetworkDeviceList(NetworkManager::Device::Type::Wifi, m_devList); + + m_currentDevice = getDefaultDeviceName(WIRELESS); + return; +} + +void WlanPage::initDeviceCombox() +{ + //TODO 获取设备列表,单设备时隐藏下拉框,多设备时添加到下拉框 + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged); + m_deviceComboBox->clear(); + + if (getSwitchBtnState()) { + if (0 == m_devList.count()) { + m_deviceFrame->show(); + m_tipsLabel->show(); + m_deviceComboBox->hide(); + m_currentDevice = ""; + setDefaultDevice(WIRELESS, m_currentDevice); + } else if (1 == m_devList.count()) { + m_deviceFrame->hide(); + if (m_currentDevice != m_devList.at(0)) { + m_currentDevice = m_devList.at(0); + setDefaultDevice(WIRELESS, m_currentDevice); + } + } else { + m_deviceFrame->show(); + m_deviceComboBox->show(); + m_tipsLabel->hide(); + for (int index = 0; index < m_devList.count(); ++index) { + m_deviceComboBox->addItem(m_devList.at(index)); + } + + if (m_devList.contains(m_currentDevice)) { + m_deviceComboBox->setCurrentText(m_currentDevice); + } else { + m_currentDevice = m_deviceComboBox->currentText(); + setDefaultDevice(WIRELESS, m_currentDevice); + } + } + } else { + m_deviceFrame->hide(); + //解决因m_currentDevice被置空,安全中心网络显示BUG +// m_currentDevice = ""; +// setDefaultDevice(WIRELESS, m_currentDevice); + } + + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged, Qt::DirectConnection); + return; +} + +QListWidgetItem *WlanPage::addEmptyItem(QListWidget *wirelessListWidget) +{ + WlanListItem *p_wlanItem = new WlanListItem(); + QListWidgetItem *p_listWidgetItem = new QListWidgetItem(); + p_listWidgetItem->setFlags(p_listWidgetItem->flags() & (~Qt::ItemIsSelectable)); //设置不可被选中 + p_listWidgetItem->setSizeHint(QSize(wirelessListWidget->width(), p_wlanItem->height())); + wirelessListWidget->addItem(p_listWidgetItem); + wirelessListWidget->setItemWidget(p_listWidgetItem, p_wlanItem); + + return p_listWidgetItem; +} + +QListWidgetItem *WlanPage::addNewItem(KyWirelessNetItem &wirelessNetItem, + QListWidget *wirelessListWidget) +{ + WlanListItem *p_wlanItem = new WlanListItem( + wirelessNetItem, + m_currentDevice, + m_connectResource->isApConnection(wirelessNetItem.m_connectUuid)); + connect(p_wlanItem, &WlanListItem::itemHeightChanged, this, &WlanPage::onItemHeightChanged); + + QListWidgetItem *p_listWidgetItem = new QListWidgetItem(); + p_listWidgetItem->setFlags(p_listWidgetItem->flags() & (~Qt::ItemIsSelectable)); + p_listWidgetItem->setSizeHint(QSize(wirelessListWidget->width(), p_wlanItem->height())); + wirelessListWidget->addItem(p_listWidgetItem); + wirelessListWidget->setItemWidget(p_listWidgetItem, p_wlanItem); + + return p_listWidgetItem; +} + +QListWidgetItem *WlanPage::insertNewItem(KyWirelessNetItem &wirelessNetItem, + QListWidget *wirelessListWidget, + int row) +{ + WlanListItem *p_wlanItem = new WlanListItem(wirelessNetItem, m_currentDevice); + connect(p_wlanItem, &WlanListItem::itemHeightChanged, this, &WlanPage::onItemHeightChanged); + + QListWidgetItem *p_listWidgetItem = new QListWidgetItem(); + p_listWidgetItem->setFlags(p_listWidgetItem->flags() & (~Qt::ItemIsSelectable)); + p_listWidgetItem->setSizeHint(QSize(wirelessListWidget->width(), p_wlanItem->height())); + wirelessListWidget->insertItem(row, p_listWidgetItem); + wirelessListWidget->setItemWidget(p_listWidgetItem, p_wlanItem); + + return p_listWidgetItem; +} + +QListWidgetItem *WlanPage::insertNewItemWithSort(KyWirelessNetItem &wirelessNetItem, + QListWidget *p_ListWidget) +{ + int row = 0; + + // qDebug()<< "insertNewItemWithSort" << wirelessNetItem.m_NetSsid + // <<"sort item config" << wirelessNetItem.m_isConfigured + // << "signal strength" << wirelessNetItem.m_signalStrength; + WlanListItem *p_sortWlanItem = new WlanListItem(wirelessNetItem, m_currentDevice); + connect(p_sortWlanItem, &WlanListItem::itemHeightChanged, this, &WlanPage::onItemHeightChanged); + + QListWidgetItem *p_sortListWidgetItem = new QListWidgetItem(); + p_sortListWidgetItem->setFlags(p_sortListWidgetItem->flags() & (~Qt::ItemIsSelectable)); + p_sortListWidgetItem->setSizeHint(QSize(p_ListWidget->width(), p_sortWlanItem->height())); + + // qDebug() << "insertNewItemWithSort, count" << p_ListWidget->count(); + for (row = 0; row < p_ListWidget->count() - 1; ++row) { + QListWidgetItem *p_listWidgetItem = p_ListWidget->item(row); + WlanListItem *p_wlanItem = (WlanListItem *)p_ListWidget->itemWidget(p_listWidgetItem); + + if (WMI_OB_NAME == p_wlanItem->objectName()) { + qDebug() << "insertNewItemWithSort" << "p_wlanItem is WlanMoreItem"; + continue; + } + + // qDebug()<< "insertNewItemWithSort" << p_wlanItem->getSsid() + // <<"item config" << p_wlanItem->isConfigured() + // << "signal strength" << p_wlanItem->getSignalStrength(); + + if (wirelessNetItem.m_isConfigured == p_wlanItem->isConfigured()) { + if (wirelessNetItem.m_signalStrength > p_wlanItem->getSignalStrength()) { + break; + } + } else { + if (wirelessNetItem.m_isConfigured) { + break; + } + } + } + + p_ListWidget->insertItem(row, p_sortListWidgetItem); + p_ListWidget->setItemWidget(p_sortListWidgetItem, p_sortWlanItem); + + //qDebug()<< "insertNewItemWithSort" << "insert sort item finished. row" << row; + return p_sortListWidgetItem; +} + +void WlanPage::clearWirelessNetItemMap(QMap &wirelessNetItem, + QListWidget *wirelessListWidget) +{ + QMap::iterator iter; + + iter = wirelessNetItem.begin(); + while (iter != wirelessNetItem.end()) { + QListWidgetItem *p_listWidgetItem = iter.value(); + if (p_listWidgetItem == m_hiddenItem) { + continue; + } + + WlanListItem *p_wlanItem = (WlanListItem *)wirelessListWidget->itemWidget(p_listWidgetItem); + wirelessListWidget->removeItemWidget(p_listWidgetItem); + + delete p_wlanItem; + p_wlanItem = nullptr; + + delete p_listWidgetItem; + p_listWidgetItem = nullptr; + + iter = wirelessNetItem.erase(iter); + } + + return; +} + +void WlanPage::deleteWirelessItemFormMap(QMap &wirelessNetItemMap, + QListWidget *wirelessListWidget, QString ssid) +{ + QListWidgetItem *p_listWidgetItem = wirelessNetItemMap.value(ssid); + if (nullptr == p_listWidgetItem) { + qWarning()<< LOG_FLAG <<"wireless item is not exsit, it's ssid is " << ssid; + return; + } + + WlanListItem *p_wlanItem = (WlanListItem *)wirelessListWidget->itemWidget(p_listWidgetItem); + if (nullptr == p_wlanItem) { + qWarning() << LOG_FLAG << "p_wlanItem is null"; + return; + } + + wirelessNetItemMap.remove(ssid); + + wirelessListWidget->takeItem(wirelessListWidget->row(p_listWidgetItem)); + + delete p_wlanItem; + p_wlanItem = nullptr; + + delete p_listWidgetItem; + p_listWidgetItem = nullptr; + + if (m_inactivatedNetListWidget->count() <= MAX_ITEMS) { + m_inactivatedNetListWidget->setFixedWidth(MIN_WIDTH); + } + return; +} + +void WlanPage::updateWlanItemState(QListWidget *p_wirelessListWidget, + QListWidgetItem *p_listWidgetItem, + ConnectState state) +{ + WlanListItem *p_wlanItem = nullptr; + p_wlanItem = (WlanListItem *)p_wirelessListWidget->itemWidget(p_listWidgetItem); + if (nullptr != p_wlanItem) { + p_wlanItem->updateConnectState(state); + } + + return; +} + +void WlanPage::constructActivateConnectionArea() +{ + int height = 0; + clearWirelessNetItemMap(m_activateConnectionItemMap, m_activatedNetListWidget); + + if (!m_currentDevice.isEmpty()) { + KyWirelessNetItem wirelessNetItem; + bool ret = m_wirelessNetResource->getActiveWirelessNetItem(m_currentDevice, wirelessNetItem); + if (ret == true) { + QListWidgetItem *p_listWidgetItem = addNewItem(wirelessNetItem, m_activatedNetListWidget); + m_activateConnectionItemMap.insert(wirelessNetItem.m_NetSsid, p_listWidgetItem); + updateWlanItemState(m_activatedNetListWidget, p_listWidgetItem, Activated); + + int configType = NetworkModeConfig::getInstance()->getNetworkModeConfig(wirelessNetItem.m_connectUuid); + if (configType == -1) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(wirelessNetItem.m_connectUuid, + m_currentDevice, + wirelessNetItem.m_connName, + KSC_FIREWALL_PUBLIC); + } else { + NetworkModeConfig::getInstance()->setNetworkModeConfig(wirelessNetItem.m_connectUuid, + m_currentDevice, + wirelessNetItem.m_connName, + configType); + } + + height += p_listWidgetItem->sizeHint().height(); + setNetSpeed->start(REFRESH_NETWORKSPEED_TIMER); + } + } + + if (height == 0) { + QListWidgetItem *p_listWidgetItem = addEmptyItem(m_activatedNetListWidget); + m_activateConnectionItemMap.insert(EMPTY_SSID, p_listWidgetItem); + + height += p_listWidgetItem->sizeHint().height(); + } + + m_activatedNetListWidget->setFixedHeight(height); + + return; +} + +void WlanPage::constructWirelessNetArea() +{ + qDebug() << "[WlanPage] Started loading wireless net list!" + << QDateTime::currentDateTime().toString("hh:mm:ss.zzzz"); + + clearWirelessNetItemMap(m_wirelessNetItemMap, m_inactivatedNetListWidget); + m_expandedItem = nullptr; + + QList wirelessNetItemList; + if (!m_wirelessNetResource->getDeviceWifiNetwork(m_currentDevice, wirelessNetItemList)) { + qWarning()<<"[WlanPage] get wireless net item list failed."; + return; + } + + QString activateSsid = m_activateConnectionItemMap.firstKey(); + + Q_FOREACH (auto wirelessNetItem, wirelessNetItemList) { + if (wirelessNetItem.m_NetSsid == activateSsid) { + continue; + } + + QListWidgetItem *p_listWidgetItem = addNewItem(wirelessNetItem, m_inactivatedNetListWidget); + m_wirelessNetItemMap.insert(wirelessNetItem.m_NetSsid, p_listWidgetItem); + updateWlanItemState(m_inactivatedNetListWidget, p_listWidgetItem, Deactivated); + } + + addWlanMoreItem(); + + qDebug() << "[WlanPage] Stopped loading wireless net list! time=" + << QDateTime::currentDateTime().toString("hh:mm:ss.zzzz"); + if (m_inactivatedNetListWidget->count() <= MAX_ITEMS) { + m_inactivatedNetListWidget->setFixedWidth(MIN_WIDTH); + } else { + m_inactivatedNetListWidget->setFixedWidth(MAX_WIDTH); + } + return; +} + +void WlanPage::initWlanArea() +{ + if (getSwitchBtnState()) { + m_activatedNetFrame->show(); + m_activatedNetDivider->show(); + constructActivateConnectionArea(); + + m_inactivatedNetFrame->show(); + constructWirelessNetArea(); + } else { + m_activatedNetFrame->hide(); + m_activatedNetDivider->hide(); + + m_inactivatedNetFrame->hide(); + } + + return; +} + +void WlanPage::onWlanAdded(QString interface, KyWirelessNetItem &item) +{ + //for dbus + QStringList info; + info << item.m_NetSsid + << QString::number(item.m_signalStrength) + << item.m_secuType + << (m_connectResource->isApConnection(item.m_connectUuid) ? IsApConnection : NotApConnection) + << QString::number(item.getCategory(item.m_uni)); + Q_EMIT wlanAdd(interface, info); + + if (interface != m_currentDevice) { + qDebug() << "[WlanPage] wlan add interface not equal defaultdevice"; + return; + } + + if (m_wirelessNetItemMap.contains(item.m_NetSsid)) { + return; + } + + qDebug() << "[WlanPage] A Wlan Added! interface = " + << interface << "; ssid = " << item.m_NetSsid << Q_FUNC_INFO <<__LINE__; + + QListWidgetItem *p_listWidgetItem = insertNewItemWithSort(item, m_inactivatedNetListWidget); + m_wirelessNetItemMap.insert(item.m_NetSsid, p_listWidgetItem); + updateWlanItemState(m_inactivatedNetListWidget, p_listWidgetItem, Deactivated); + + addWlanMoreItem(); + if (m_inactivatedNetListWidget->count() > MAX_ITEMS) { + m_inactivatedNetListWidget->setFixedWidth(MAX_WIDTH); + } + return; +} + +void WlanPage::onWlanRemoved(QString interface, QString ssid) +{ + Q_EMIT wlanRemove(interface, ssid); + + if (interface != m_currentDevice) { + qDebug()<<"[WlanPage] the device is not current device," + <<"current device" << m_currentDevice + << "remove wlan device" << interface; + return; + } + + if (!m_wirelessNetItemMap.contains(ssid) && !m_activateConnectionItemMap.contains(ssid)) { + return; + } + + if (m_expandedItem == m_wirelessNetItemMap.value(ssid)) { + m_expandedItem = nullptr; + } + + qDebug() << "[WlanPage] A Wlan Removed! interface = " << interface + << "; ssid = " << ssid << Q_FUNC_INFO <<__LINE__; + + + if (m_wirelessNetItemMap.contains(ssid)) { + deleteWirelessItemFormMap(m_wirelessNetItemMap, + m_inactivatedNetListWidget, ssid); + } else { + deleteWirelessItemFormMap(m_activateConnectionItemMap, + m_activatedNetListWidget, ssid); +// showDesktopNotify(tr("WLAN Disconnected Successfully"), "networkdisconnected"); + + QListWidgetItem *p_listWidgetItem = addEmptyItem(m_activatedNetListWidget); + m_activateConnectionItemMap.insert(EMPTY_SSID, p_listWidgetItem); + } + + return; +} + +void WlanPage::updateWlanListItem(QString ssid) +{ + KyWirelessNetItem wirelessNetItem; + + qDebug() << LOG_FLAG << "update wlan list item " << ssid; + + bool ret = m_wirelessNetResource->getWifiNetwork(m_currentDevice, ssid, wirelessNetItem); + if (ret) { + QListWidgetItem *p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + if (p_listWidgetItem) { + WlanListItem *p_wlanItem = (WlanListItem *)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + p_wlanItem->updateWirelessNetItem(wirelessNetItem); + p_wlanItem->updateConnectState(Deactivated); + Q_EMIT this->wlanConnectChanged(Deactivated); + } + } + + return; +} + +void WlanPage::onConnectionAdd(QString deviceName, QString ssid) +{ + qDebug() << LOG_FLAG << "one connection is added, it's ssid " << ssid << "device name"<< deviceName; + + if (deviceName == m_currentDevice) { + updateWlanListItem(ssid); + } + + return; +} + +void WlanPage::onConnectionRemove(QString deviceName, QString ssid, QString path) +{ + qDebug() << LOG_FLAG << "one connection is removed, it's ssid " << ssid << "device name"<< deviceName; + if (deviceName == m_currentDevice) { + if (m_activateConnectionItemMap.contains(ssid)) { + updateWirelessNetArea(nullptr, ssid, deviceName, path); + } + updateWlanListItem(ssid); + } + + return; +} + +void WlanPage::onSecurityTypeChange(QString devName, QString ssid, QString secuType) +{ + QListWidgetItem *p_listWidgetItem = nullptr; + WlanListItem *p_wlanItem = nullptr; + + qDebug()<< LOG_FLAG << "security type is chenged"; + + if (m_wirelessNetItemMap.contains(ssid)) { + p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + p_wlanItem = (WlanListItem*)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + } else if (m_activateConnectionItemMap.contains(ssid)) { + p_listWidgetItem = m_activateConnectionItemMap.value(ssid); + p_wlanItem = (WlanListItem*)m_activatedNetListWidget->itemWidget(p_listWidgetItem); + } + + if (nullptr != p_wlanItem) { + p_wlanItem->updateWirelessNetSecurity(ssid, secuType); + } + + Q_EMIT secuTypeChange(devName, ssid, secuType); + + return; +} + + +void WlanPage::addDeviceToCombox(QString deviceName) +{ + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged); + if (getSwitchBtnState()) { + if (m_currentDevice.isEmpty()){ + m_deviceFrame->hide(); + m_currentDevice = deviceName; + setDefaultDevice(WIRELESS, m_currentDevice); + } else if (m_deviceComboBox->count() == 0) { + m_deviceComboBox->addItem(m_currentDevice); + m_deviceComboBox->addItem(deviceName); + m_deviceFrame->show(); + m_deviceComboBox->show(); + m_tipsLabel->hide(); + } else { + m_deviceComboBox->addItem(deviceName); + } + } + + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged); + return; +} + +void WlanPage::onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType) +{ + qDebug() << LOG_FLAG << "currentDevice" << m_currentDevice << "deviceAdd" << deviceName; + if (deviceType != NetworkManager::Device::Type::Wifi) { + return; + } + + if (m_devList.contains(deviceName)) { + return; + } + + m_devList << deviceName; + setSwitchBtnEnable(true); + setSwitchBtnState(getWirelessDevieceUseable()); + + addDeviceToCombox(deviceName); + if (m_currentDevice == deviceName) { + initWlanArea(); + } + + Q_EMIT deviceStatusChanged(); + + return; +} + +void WlanPage::deleteDeviceFromCombox(QString deviceName) +{ + disconnect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged); + + if (getSwitchBtnState()) { + if (0 == m_devList.count()) { + m_deviceFrame->hide(); + //m_tipsLabel->show(); + //m_deviceComboBox->hide(); + m_currentDevice = ""; + setDefaultDevice(WIRELESS, m_currentDevice); + } else if (1 == m_devList.count()) { + m_deviceFrame->hide(); + m_deviceComboBox->clear(); + m_currentDevice = m_devList.at(0); + setDefaultDevice(WIRELESS, m_currentDevice); + } else { + int index = m_deviceComboBox->findData(deviceName); + if (-1 != index) { + m_deviceComboBox->removeItem(index); + m_currentDevice = m_deviceComboBox->currentText(); + setDefaultDevice(WIRELESS, m_currentDevice); + } + } + } + + connect(m_deviceComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, &WlanPage::onDeviceComboxIndexChanged); + return; +} + +void WlanPage::onDeviceRemove(QString deviceName) +{ + if (!m_devList.contains(deviceName)) { + return; + } + + qDebug() << "deviceRemove" << deviceName; + + QString originalDeviceName = m_currentDevice; + + m_devList.removeOne(deviceName); + deleteDeviceFromCombox(deviceName); + + if (m_devList.isEmpty()) { + setSwitchBtnState(false); + setSwitchBtnEnable(false); + } + + if (originalDeviceName == deviceName) { + initWlanArea(); + } + + Q_EMIT deviceStatusChanged(); +} + +void WlanPage::updateDeviceForCombox(QString oldDeviceName, QString newDeviceName) +{ + if (m_currentDevice == oldDeviceName) { + m_currentDevice = newDeviceName; + setDefaultDevice(WIRELESS, m_currentDevice); + } + + int index = m_deviceComboBox->findText(oldDeviceName); + if (index != -1) { + m_deviceComboBox->setItemText(index, newDeviceName); + } + + return; +} + +void WlanPage::onDeviceNameUpdate(QString oldName, QString newName) +{ + if (!m_devList.contains(oldName)) { + return; + } + + qDebug()<<"[WlanPage] update device name, old name" + << oldName << "new Name" << newName; + + m_devList.removeOne(oldName); + m_devList.append(newName); + + QString originalDeviceName = m_currentDevice; + + updateDeviceForCombox(oldName, newName); + if (originalDeviceName != m_currentDevice) { + initWlanArea(); + } + + Q_EMIT deviceNameChanged(oldName, newName, WIRELESS); +} + +void WlanPage::onWlanStateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason) +{ + if (getSwitchBtnState() == getWirelessDevieceUseable()) { + return ; + } + setSwitchBtnState(getWirelessDevieceUseable()); + initDeviceCombox(); + initWlanArea(); + Q_EMIT wirelessSwitchBtnChanged(getSwitchBtnState()); +} + +void WlanPage::sendApStateChangeSignal(QString uuid, + QString ssid, + QString deviceName, + NetworkManager::ActiveConnection::State state) +{ + bool ret = false; + ret = m_connectResource->isApConnection(uuid); + + if (!ret) { + return; + } + + if (state == NetworkManager::ActiveConnection::State::Deactivated) { + qDebug() << "[WlanPage] hotspot Deactivated"; + Q_EMIT hotspotDeactivated(deviceName, ssid); + } else if (state == NetworkManager::ActiveConnection::State::Activated) { + QString activePath; + QString settingPath; + activePath = m_activatedConnectResource->getAcitveConnectionPathByUuid(uuid); + settingPath = m_connectResource->getApConnectionPathByUuid(uuid); + qDebug() << "[WlanPage] hotspot activated"<showDesktopNotify(tr("WLAN Connected Successfully"), "networkconnected"); + } + + return; +} +#endif + +void WlanPage::updateActivatedArea(QString uuid, QString ssid, QString devName) +{ + if (m_activateConnectionItemMap.contains(ssid)) { + return; + } + + if (m_expandedItem == m_wirelessNetItemMap.value(ssid)) { + m_expandedItem = nullptr; + } + deleteWirelessItemFormMap(m_wirelessNetItemMap, + m_inactivatedNetListWidget, ssid); + + KyWirelessNetItem wirelessNetItem; + bool ret = m_wirelessNetResource->getWifiNetwork(devName, ssid, wirelessNetItem); + if (!ret) { + qWarning()<<"[WlanPage] get wireless item failed, when update activated connection area."; + return; + } + + deleteWirelessItemFormMap(m_activateConnectionItemMap, m_activatedNetListWidget, EMPTY_SSID); + QListWidgetItem *p_listWidgetItem = addNewItem(wirelessNetItem, m_activatedNetListWidget); + m_activateConnectionItemMap.insert(wirelessNetItem.m_NetSsid, p_listWidgetItem); + + m_activatedNetListWidget->setFixedHeight(p_listWidgetItem->sizeHint().height()); + if (m_inactivatedNetListWidget->count() <= MAX_ITEMS) { + m_inactivatedNetListWidget->setFixedWidth(MIN_WIDTH); + } + return; +} + +void WlanPage::updateWirelessNetArea(QString uuid, QString ssid, QString devName, QString path) +{ + if(m_wirelessNetItemMap.contains(ssid)) { + return; + } + + if (m_activateConnectionItemMap.contains(ssid)) { + QListWidgetItem *p_listWidgetItem = m_activateConnectionItemMap.value(ssid); + if (nullptr == p_listWidgetItem) { + qWarning()<< LOG_FLAG <<"wireless item is not exsit, it's ssid is " << ssid; + return; + } + WlanListItem *p_wlanItem = (WlanListItem *)m_activatedNetListWidget->itemWidget(p_listWidgetItem); + if (nullptr == p_wlanItem) { + qWarning() << LOG_FLAG << "p_wlanItem is null"; + return; + } + + if (p_wlanItem->getUuid() == uuid || uuid.isEmpty()) { + if (uuid.isEmpty() && p_wlanItem->getPath() != path) { + return; + } + + deleteWirelessItemFormMap(m_activateConnectionItemMap, m_activatedNetListWidget, ssid); + QListWidgetItem *p_activeListWidgetItem = addEmptyItem(m_activatedNetListWidget); + m_activateConnectionItemMap.insert(EMPTY_SSID, p_activeListWidgetItem); + m_activatedNetListWidget->setFixedHeight(p_activeListWidgetItem->sizeHint().height()); + } + } else { + qDebug() << LOG_FLAG << ssid << "is not in activeconnection map"; + } + + KyWirelessNetItem wirelessNetItem; + bool ret = m_wirelessNetResource->getWifiNetwork(devName, ssid, wirelessNetItem); + if (!ret) { + qWarning()<<"[WlanPage] get wireless item failed, when update wireless area."; + return; + } + + QListWidgetItem *p_listWidgetItem = insertNewItemWithSort(wirelessNetItem, m_inactivatedNetListWidget); + m_wirelessNetItemMap.insert(wirelessNetItem.m_NetSsid, p_listWidgetItem); + + // 更新‘更多’条目,以保证其处于listwidget的最底部 + addWlanMoreItem(); + if (m_inactivatedNetListWidget->count() <= MAX_ITEMS) { + m_inactivatedNetListWidget->setFixedWidth(MIN_WIDTH); + } else { + m_inactivatedNetListWidget->setFixedWidth(MAX_WIDTH); + } + return; +} + +void WlanPage::onConnectionStateChanged(QString uuid, + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason) +{ + QString devName, ssid; + m_wirelessNetResource->getSsidByUuid(uuid, ssid); + m_wirelessNetResource->getDeviceByUuid(uuid, devName); + + qDebug()<< LOG_FLAG << "Q_EMIT wlanActiveConnectionStateChanged" << devName << ssid << state; + Q_EMIT wlanActiveConnectionStateChanged(devName, ssid, uuid, state); + + //解决通过高级设置添加的未指定网卡的无线连接无法断开的问题,去掉设备为空的判断 + if (ssid.isEmpty()) { + qDebug()<< LOG_FLAG << "ssid or devicename is empty" + << "devicename"<< devName <<"ssid"<isWirelessConnection(uuid)) { + qDebug()<< LOG_FLAG << "it is not wireless connection" << uuid; + return; + } + + Q_EMIT this->wlanConnectChanged(state); + + bool isApConnection = m_connectResource->isApConnection(uuid); + + if (isApConnection) { + sendApStateChangeSignal(uuid, ssid, devName, state); + } else { + if (state == NetworkManager::ActiveConnection::State::Deactivated && + !m_activateConnectionItemMap.contains(ssid)) { + qDebug() << "wlan remove before deactivated"; + } else { +// wlanShowNotify(ssid, state, reason); + } + } + + if (!devName.isEmpty() && devName != m_currentDevice) { + return; + } + + qDebug()<< "[WlanPage] wlan state changed, ssid = " << ssid + << "; state = " << state << "; reason = " << reason << Q_FUNC_INFO <<__LINE__; + if (state == NetworkManager::ActiveConnection::State::Activated) { + m_updateStrength = true; + + if (!isApConnection) { + int configType = NetworkModeConfig::getInstance()->getNetworkModeConfig(uuid); + if (configType == -1) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, devName, ssid, KSC_FIREWALL_PUBLIC); //默认公有配置 + FirewallDialog *fireWallDialog = new FirewallDialog(); //弹窗 供用户配置 + fireWallDialog->setUuid(uuid); + fireWallDialog->setWindowTitle(ssid); + + connect(fireWallDialog, &FirewallDialog::setPrivateNetMode, this, [=](){ + fireWallDialog->hide(); + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, devName, ssid, KSC_FIREWALL_PRIVATE); + }); + + connect(fireWallDialog, &FirewallDialog::setPublicNetMode, this, [=](){ + fireWallDialog->hide(); + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, devName, ssid, KSC_FIREWALL_PUBLIC); + }); + + connect(m_activatedConnectResource, &KyActiveConnectResourse::stateChangeReason, fireWallDialog, &FirewallDialog::closeMyself); + + fireWallDialog->show(); + fireWallDialog->centerToScreen(); + + } else if (configType == KSC_FIREWALL_PUBLIC) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, devName, ssid, KSC_FIREWALL_PUBLIC); + } else if (configType == KSC_FIREWALL_PRIVATE) { + NetworkModeConfig::getInstance()->setNetworkModeConfig(uuid, devName, ssid, KSC_FIREWALL_PRIVATE); + } + } + + updateActivatedArea(uuid, ssid, devName); + setNetSpeed->start(REFRESH_NETWORKSPEED_TIMER); + if (m_activateConnectionItemMap.contains(ssid)) { + QListWidgetItem *p_listWidgetItem = m_activateConnectionItemMap.value(ssid); + updateWlanItemState(m_activatedNetListWidget, p_listWidgetItem, Activated); + } + } else if (state == NetworkManager::ActiveConnection::State::Deactivated) { + m_updateStrength = true; + if (devName.isEmpty()) { + devName = m_currentDevice; + } + + updateWirelessNetArea(uuid, ssid, devName,""); + setNetSpeed->stop(); + + if (m_wirelessNetItemMap.contains(ssid)) { + QListWidgetItem *p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + updateWlanItemState(m_inactivatedNetListWidget, p_listWidgetItem, Deactivated); + } + NetworkModeConfig::getInstance()->breakNetworkConnect(uuid, devName, ssid); + } else if (state == NetworkManager::ActiveConnection::State::Deactivating){ + m_updateStrength = false; + if (m_activateConnectionItemMap.contains(ssid)) { + QListWidgetItem *p_listWidgetItem = m_activateConnectionItemMap.value(ssid); + updateWlanItemState(m_activatedNetListWidget, p_listWidgetItem, Deactivating); + } + } else if (state == NetworkManager::ActiveConnection::State::Activating) { + m_updateStrength = false; + if (m_wirelessNetItemMap.contains(ssid)) { + QListWidgetItem *p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + updateWlanItemState(m_inactivatedNetListWidget, p_listWidgetItem, Activating); + } + } + return; +} + +void WlanPage::onItemHeightChanged(const bool isExpanded, const QString &ssid) +{ + if (!m_wirelessNetItemMap.contains(ssid)) { + return; + } + + QListWidgetItem *p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + + qDebug()<sizeHint().height(); + int width = p_listWidgetItem->sizeHint().width(); + + if (isExpanded) { + if (m_expandedItem != p_listWidgetItem) { + qDebug()<setSizeHint(expandedSize); + } + m_inactivatedNetListWidget->scrollToItem(p_listWidgetItem, QAbstractItemView::QAbstractItemView::EnsureVisible); + } else { + m_expandedItem = nullptr; + + if (height > NORMAL_HEIGHT) { + qDebug()<setSizeHint(normalSize); + } + } + + return; +} + +void WlanPage::onDeviceComboxIndexChanged(int currentIndex) +{ + qDebug() << "onDeviceComboxIndexChanged"; + if (!m_deviceComboBox || currentIndex < 0) { + return; + } + + m_currentDevice = m_deviceComboBox->itemText(currentIndex); + setDefaultDevice(WIRELESS, m_currentDevice); + + initWlanArea(); + + return; +} + +//申请触发扫描,初始化执行&定时执行 +void WlanPage::requestScan() +{ + if (!m_wirelessConnectOpreation) { + qWarning() << "[WlanPage]Scan failed! m_wirelessConnectOpreation is nullptr!" << Q_FUNC_INFO << __LINE__; + return; + } + + m_wirelessConnectOpreation->requestWirelessScan(); + + return; +} + +void WlanPage::onHiddenWlanClicked() +{ +// qDebug() << "[wlanPage] AddHideWifi Clicked! " << Q_FUNC_INFO << __LINE__ ; +// NetDetail *netDetail = new NetDetail(m_currentDevice, "", "", false, true, true); +// netDetail->show(); + if(m_hiddenWiFi != nullptr){ + m_hiddenWiFi->activateWindow(); + return; + } + + m_hiddenWiFi = new JoinHiddenWiFiPage(m_currentDevice); + + connect(m_hiddenWiFi, &JoinHiddenWiFiPage::showWlanList, this, &WlanPage::showMainWindow); + connect(m_hiddenWiFi, &JoinHiddenWiFiPage::destroyed, [&](){ + if (m_hiddenWiFi != nullptr) { + m_hiddenWiFi = nullptr; + } + }); + + m_hiddenWiFi->show(); +} + +void WlanPage::showControlCenter() +{ + qDebug() << LOG_FLAG <<"show control center"; + + QProcess process; + process.startDetached("ukui-control-center -m wlanconnect"); + + return; +} + +void WlanPage::onWifiEnabledChanged(bool isWifiOn) +{ + //监听外部命令导致wifi状态变化,更新界面 + qDebug() << "[WlanPage] onWifiEnabledChanged wifi state" << isWifiOn; + return; +} + +void WlanPage::refreshActiveConnectionIcon(QString ssid, const int &signal) +{ + QListWidgetItem *p_listWidgetItem = m_activateConnectionItemMap.value(ssid); + if (p_listWidgetItem) { + WlanListItem *p_wlanItem = (WlanListItem *)m_activatedNetListWidget->itemWidget(p_listWidgetItem); + if (nullptr != p_wlanItem) { + p_wlanItem->setSignalStrength(signal); + return; + } + } +} + +void WlanPage::onRefreshIconTimer() +{ + if (!m_updateStrength) { + return; + } + + Q_EMIT timeToUpdate(); + + if(!this->isVisible()) { + return; + } + //qDebug() << "onRefreshIconTimer"; + + if (m_expandedItem) { + qDebug()<< LOG_FLAG << "Has expanded item and forbid refresh wifi strength" << Q_FUNC_INFO << __LINE__; + return; + } + + QList wlanList; + if (!m_wirelessNetResource->getDeviceWifiNetwork(m_currentDevice, wlanList)) { + return; + } + + //解决没有无线设备且m_currentDevice不清空的情况下,m_activateConnectionItemMap为空造成的段错误 + if (m_activateConnectionItemMap.isEmpty()) { + return ; + } + QString activateSsid = m_activateConnectionItemMap.firstKey(); + int sortRow = 0; + for (int index = 0; index < wlanList.length(); index++) { + KyWirelessNetItem sortItem = wlanList.at(index); + QString sortSsid = sortItem.m_NetSsid; //应该在第currentRow行的新的WiFi名称 + //qDebug()<< LOG_FLAG << "sort ssid"<< sortSsid << "active ssid" << activateSsid << "sort row"<< sortRow; + if (sortSsid == activateSsid) { //排除已连接WiFi + refreshActiveConnectionIcon(activateSsid, sortItem.m_signalStrength); + continue; + } + + QListWidgetItem *p_listWidgetItem = m_inactivatedNetListWidget->item(sortRow); + if (p_listWidgetItem) { + WlanListItem *p_wlanItem = (WlanListItem *)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + + if (nullptr == p_wlanItem) { + qDebug() << LOG_FLAG << "p_wlanItem is null continue"; + continue;//暂时先保持continue,后续讨论是否使用break直接跳出循环 + } + + // 该item是‘更多’条目,不需要更新 + if (WMI_OB_NAME == p_wlanItem->objectName()) { + qDebug() << LOG_FLAG << "p_wlanItem is WlanMoreItem"; + continue; + } + + //qDebug()<< LOG_FLAG << "row" << sortRow << "item ssid" << p_wlanItem->getSsid(); + if (sortSsid == p_wlanItem->getSsid()) { + // qDebug()<< LOG_FLAG << "sort wlan set signal strength." << Q_FUNC_INFO << __LINE__; + p_wlanItem->setSignalStrength(sortItem.m_signalStrength); + sortRow++; + continue; + } + + QListWidgetItem *p_sortListWidgetItem = m_wirelessNetItemMap.value(sortSsid); + if (p_sortListWidgetItem) { + WlanListItem *p_wlanItem = (WlanListItem *)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + if (p_wlanItem == nullptr) { + continue; + } + + if (Deactivated != p_wlanItem->getConnectionState()) { + continue; + } + // qDebug()<< LOG_FLAG << "sort wlan update position." << sortSsid << Q_FUNC_INFO << __LINE__; + int takeRow = m_inactivatedNetListWidget->row(p_sortListWidgetItem); + m_inactivatedNetListWidget->takeItem(takeRow); + + WlanListItem *p_sortWlanItem = new WlanListItem(sortItem, m_currentDevice); + connect(p_sortWlanItem, &WlanListItem::itemHeightChanged, this, &WlanPage::onItemHeightChanged); + m_inactivatedNetListWidget->insertItem(sortRow, p_sortListWidgetItem); + m_inactivatedNetListWidget->setItemWidget(p_sortListWidgetItem, p_sortWlanItem); + updateWlanItemState(m_inactivatedNetListWidget, p_sortListWidgetItem, Deactivated); + sortRow++; + continue; + } + } + + //qDebug()<< LOG_FLAG << "sort wlan add new item." << Q_FUNC_INFO << __LINE__; + QListWidgetItem *p_newListWidgetItem = insertNewItem(sortItem, m_inactivatedNetListWidget, sortRow); + m_wirelessNetItemMap.insert(sortItem.m_NetSsid, p_newListWidgetItem); + updateWlanItemState(m_inactivatedNetListWidget, p_listWidgetItem, Deactivated); + + sortRow++; + } + + // qDebug()<< LOG_FLAG << "sort wlan finished." << Q_FUNC_INFO << __LINE__; + + return; +} + +//for dbus +void WlanPage::getWirelessList(QMap > &map) +{ + QMap actMap; + m_wirelessNetResource->getWirelessActiveConnection(NetworkManager::ActiveConnection::State::Activated, actMap); + + QMap > wlanMap; + if (!m_wirelessNetResource->getAllDeviceWifiNetwork(wlanMap)) { + return; + } + + QMap >::iterator iter = wlanMap.begin(); + while (iter != wlanMap.end()) { + QVector vector; + QString activeSsid ; + //先是已连接 + if (actMap.contains(iter.key())) { + qDebug() << "find " <getSsidByUuid(actMap[iter.key()].at(0), ssid); + if (m_wirelessNetResource->getWifiNetwork(iter.key(), ssid, data)) { + int category = 0; + int signalStrength; + QString uni,secuType; + + if (m_netDeviceResource->getActiveConnectionInfo(iter.key(), signalStrength, uni, secuType)) { + category = data.getCategory(uni); + } + vector.append(QStringList() << data.m_NetSsid + << QString::number(signalStrength) + << secuType + << data.m_connectUuid + << (m_connectResource->isApConnection(data.m_connectUuid) ? IsApConnection : NotApConnection) + << QString::number(category)); + activeSsid = data.m_NetSsid; + } else { + vector.append(QStringList("--")); + } + } else { + vector.append(QStringList("--")); + } + //未连接 + Q_FOREACH (auto itemData, iter.value()) { + if (itemData.m_NetSsid == activeSsid) { + continue; + } + vector.append(QStringList()<isApConnection(itemData.m_connectUuid) ? IsApConnection : NotApConnection) + << QString::number(itemData.getCategory(itemData.m_uni))); + } + + map.insert(iter.key(), vector); + iter++; + } + + return; +} + +//for dbus +bool WlanPage::getWirelessSwitchBtnState() +{ + return getSwitchBtnState(); +} + +//开启热点 +void WlanPage::activeWirelessAp(const QString apName, const QString apPassword, const QString wirelessBand, const QString apDevice) +{ + QString uuid(""); + QList apConnectItemList; + m_connectResource->getApConnections(apConnectItemList); + if (!apConnectItemList.isEmpty()) { + uuid = apConnectItemList.at(0)->m_connectUuid; + } + + m_wirelessConnectOpreation->activeWirelessAp(uuid, apName, apPassword, apDevice, wirelessBand); +} + +//断开热点 +void WlanPage::deactiveWirelessAp(const QString apName, const QString uuid) +{ + if (!uuid.isEmpty()) { + m_wirelessConnectOpreation->deactiveWirelessAp(apName, uuid); + } +} + +void WlanPage::getStoredApInfo(QStringList &list) +{ + list.clear(); + QList apConnectItemList; + m_connectResource->getApConnections(apConnectItemList); + if (!apConnectItemList.isEmpty()) { + list << apConnectItemList.at(0)->m_connectSsid; + list << apConnectItemList.at(0)->m_password; + list << apConnectItemList.at(0)->m_ifaceName; + list << (apConnectItemList.at(0)->m_isActivated? "true":"false"); + list << apConnectItemList.at(0)->m_connectUuid; + list << apConnectItemList.at(0)->m_band; + } +} + +void WlanPage::getApConnectionPath(QString &path, QString uuid) +{ + path.clear(); + path = m_connectResource->getApConnectionPathByUuid(uuid); +} + +void WlanPage::getActiveConnectionPath(QString &path, QString uuid) +{ + path.clear(); + path = m_activatedConnectResource->getAcitveConnectionPathByUuid(uuid); +} + +void WlanPage::getApInfoBySsid(QString devName, QString ssid, QStringList &list) +{ + list.clear(); + QList apConnectItemList; + m_connectResource->getApConnections(apConnectItemList); + for (int i = 0; i < apConnectItemList.size(); i++) { + if (apConnectItemList.at(i)->m_connectSsid == ssid + && apConnectItemList.at(i)->m_ifaceName == devName) { + list << apConnectItemList.at(i)->m_password; + list << apConnectItemList.at(i)->m_band; + } + } + + return; +} + +void WlanPage::activateWirelessConnection(const QString& devName, const QString& ssid) +{ + KyWirelessNetItem wirelessNetItem; + if (!m_wirelessNetResource->getWifiNetwork(devName, ssid, wirelessNetItem)) { + qDebug() << "[WlanPage] no such wifi " << ssid << " in " << devName; + return; + } + + if (devName != m_currentDevice) { + int index = m_deviceComboBox->findText(devName); + if (index >= 0) { + m_deviceComboBox->setCurrentIndex(index); + } else { + qDebug() << "[WlanPage]activateWirelessConnection no such " << devName; + return; + } + } + + QListWidgetItem *p_listWidgetItem = nullptr; + WlanListItem *p_wlanItem = nullptr; + + if (m_wirelessNetItemMap.contains(ssid)) { + p_listWidgetItem = m_wirelessNetItemMap.value(ssid); + p_wlanItem = (WlanListItem*)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + + m_inactivatedNetListWidget->scrollToItem(p_listWidgetItem, QAbstractItemView::EnsureVisible); + + + QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, QPoint(0,0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QApplication::postEvent(p_wlanItem, event); + Q_EMIT showMainWindow(WLAN_PAGE_INDEX); + } else { + qDebug() << "[WlanPage]activateWirelessConnection no such " << ssid << "in" << devName; + } + return; +} + +void WlanPage::deactivateWirelessConnection(const QString& devName, const QString& ssid) +{ + KyWirelessNetItem wirelessNetItem; + if (!m_wirelessNetResource->getWifiNetwork(devName, ssid, wirelessNetItem)) { + qDebug() << "[WlanPage] no such wifi " << ssid << " in " << devName; + return; + } + + if (!m_connectResource->isActivatedConnection(wirelessNetItem.m_connectUuid)) { + qDebug()<<"[WlanPage]"<deActivateWirelessConnection(wirelessNetItem.m_connName, wirelessNetItem.m_connectUuid); + + return; +} + +void WlanPage::onMainWindowVisibleChanged(const bool &visible) +{ + qDebug() << "[WlanPage] Received signal of mainwindow visible changed. cur_state = " << visible << Q_FUNC_INFO << __LINE__; + //开关关闭状态不刷新 + if (visible && getSwitchBtnState()) { + //打开页面时先触发一次扫描,然后定时扫描wifi热点和刷新icon + requestScan(); + m_scanTimer->start(AP_SCAN_INTERVAL); + onRefreshIconTimer(); +// m_refreshIconTimer->start(ICON_REFRESH_INTERVAL); + } else { + //界面关闭的时候,停止wifi扫描和刷新 + m_scanTimer->stop(); +// m_refreshIconTimer->stop(); + qDebug() << "wlanpage not visible"; + showNonePwd(); + } + + return; +} + +void WlanPage::onWlanPageVisibleChanged(int index) +{ + if (index == LAN_PAGE_INDEX) { + qDebug() << "wlanpage not visible"; + showNonePwd(); + } +} + +void WlanPage::showNonePwd() +{ + QMap::iterator iter; + for(iter=m_wirelessNetItemMap.begin();iter!= m_wirelessNetItemMap.end();iter++) + { + if(iter.value() != nullptr) { + QListWidgetItem *p_listWidgetItem = iter.value(); + WlanListItem *p_wlanItem = (WlanListItem*)m_inactivatedNetListWidget->itemWidget(p_listWidgetItem); + p_wlanItem->forgetPwd(); + p_wlanItem->setExpanded(false); + } + } + return; +} + + +void WlanPage::showRate() +{ + //定时获取网速 + setNetSpeed = new QTimer(this); + setNetSpeed->setTimerType(Qt::PreciseTimer); + connect(setNetSpeed, &QTimer::timeout, [&](){ + onSetNetSpeed(m_activatedNetListWidget, m_activateConnectionItemMap.contains(EMPTY_SSID), m_currentDevice); + }); +} + +void WlanPage::showDetailPage(QString devName, QString ssid) +{ + KyWirelessNetItem wirelessNetItem; + if (!m_wirelessNetResource->getWifiNetwork(devName, ssid, wirelessNetItem)) { + qDebug()<<"[WlanPage] " << ssid << " is missing when showDetailPage"; + return; + } + + bool isActive = m_connectResource->isActivatedConnection(wirelessNetItem.m_connectUuid); + + NetDetail *netDetail = new NetDetail(devName, ssid, wirelessNetItem.m_connectUuid, isActive, true, !wirelessNetItem.m_isConfigured); + netDetail->show(); + + return; +} + +bool WlanPage::checkWlanStatus(NetworkManager::ActiveConnection::State state) +{ + if (m_activatedConnectResource->checkWirelessStatus(state)) { + return true; + } else { + return false; + } +} + +void WlanPage::setWirelessSwitchEnable(bool enable) +{ + qDebug() << "dbus setWirelessSwitchEnable = " << enable << __LINE__; + setWirelessEnable(enable); +} + +void WlanPage::getWirelessDeviceCap(QMap &map) +{ + for (int i = 0; i < m_devList.size(); ++i) { + QString devName = m_devList.at(i); + map.insert(devName, m_netDeviceResource->getWirelessDeviceCapability(devName)); + } +} + +void WlanPage::getConnectivity(NetworkManager::Connectivity &connectivity) +{ + m_connectResource->getConnectivity(connectivity); +} + +/** + * @brief WlanPage::addWlanMoreItem + * 添加‘更多网络’的条目 + */ +void WlanPage::addWlanMoreItem() +{ + if (m_hiddenItem) { + m_inactivatedNetListWidget->takeItem(m_inactivatedNetListWidget->row(m_hiddenItem)); + delete m_hiddenItem; + m_hiddenItem = nullptr; + } + + if (m_hiddenWlanWidget) { +// disconnect(m_hiddenWlanWidget, &WlanMoreItem::hiddenWlanClicked, this, &WlanPage::onHiddenWlanClicked); + m_hiddenWlanWidget->setParent(nullptr); + delete m_hiddenWlanWidget; + m_hiddenWlanWidget = nullptr; + } + + m_hiddenWlanWidget = new WlanMoreItem(this); + connect(m_hiddenWlanWidget, &WlanMoreItem::hiddenWlanClicked, this, &WlanPage::onHiddenWlanClicked); + m_hiddenWlanWidget->setFixedHeight(NORMAL_HEIGHT); + + m_hiddenItem = new QListWidgetItem(m_inactivatedNetListWidget); + m_hiddenItem->setFlags(m_hiddenItem->flags() & (~Qt::ItemIsSelectable)); + m_hiddenItem->setSizeHint(QSize(m_inactivatedNetListWidget->width(), m_hiddenWlanWidget->height())); + m_inactivatedNetListWidget->addItem(m_hiddenItem); + m_inactivatedNetListWidget->setItemWidget(m_hiddenItem, m_hiddenWlanWidget); + m_hiddenWlanWidget->m_freq->hide(); + return; +} diff --git a/src/frontend/tab-pages/wlanpage.h b/src/frontend/tab-pages/wlanpage.h new file mode 100644 index 00000000..c6feb182 --- /dev/null +++ b/src/frontend/tab-pages/wlanpage.h @@ -0,0 +1,237 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef WLANPAGE_H +#define WLANPAGE_H + +#include "tabpage.h" +#include "kywirelessnetresource.h" +#include "kylinactiveconnectresource.h" +#include "kylinnetworkdeviceresource.h" +#include "kywirelessconnectoperation.h" +#include "wlanlistitem.h" +#include "wlanmoreitem.h" +#include "kylinconnectoperation.h" +#include +#include "netdetails/netdetail.h" +#include +#include "kylinactiveconnectresource.h" +#include "kywirelessnetresource.h" +#include "netdetails/joinhiddenwifipage.h" + +//#define SCROLLAREA_HEIGHT 150 +#define MORE_TEXT_MARGINS 16,0,0,0 +#define SCROLLAREA_HEIGHT 200 + +#define LAN_PAGE_INDEX 0 +#define WLAN_PAGE_INDEX 1 + +class WlanListItem; + +class WlanPage : public TabPage +{ + Q_OBJECT +public: + explicit WlanPage(QWidget *parent = nullptr); + ~WlanPage() = default; + + //for dbus + void getWirelessList(QMap > &map); + //开启热点 + void activeWirelessAp(const QString apName, const QString apPassword, const QString wirelessBand, const QString apDevice); + //断开热点 + void deactiveWirelessAp(const QString apName, const QString uuid); + //获取热点 + void getStoredApInfo(QStringList &list); + void getApConnectionPath(QString &path, QString uuid); + void getActiveConnectionPath(QString &path, QString uuid); + + void activateWirelessConnection(const QString& devName, const QString& ssid); + void deactivateWirelessConnection(const QString& devName, const QString& ssid); + + void showDetailPage(QString devName, QString uuid); + + bool checkWlanStatus(NetworkManager::ActiveConnection::State state); + + void getApInfoBySsid(QString devName, QString ssid, QStringList &list); + //无线总开关 + void setWirelessSwitchEnable(bool enable); + void getWirelessDeviceCap(QMap &map); + + void getConnectivity(NetworkManager::Connectivity &connectivity); + + bool getWirelessSwitchBtnState(); + +Q_SIGNALS: + void oneItemExpanded(const QString &ssid); + void wlanAdd(QString devName, QStringList info); + void wlanRemove(QString devName,QString ssid); + void wlanActiveConnectionStateChanged(QString interface, QString ssid, QString uuid, int status); + void hotspotDeactivated(QString devName, QString ssid); + void hotspotActivated(QString devName, QString ssid, QString uuid, QString activePath, QString settingPath); + void signalStrengthChange(QString devName, QString ssid, int strength); + void secuTypeChange(QString devName, QString ssid, QString secuType); + void hiddenWlanClicked(); + void wlanConnectChanged(int state); + void timeToUpdate(); + + void showMainWindow(int type); + + void connectivityChanged(NetworkManager::Connectivity connectivity); + + void wirelessSwitchBtnChanged(bool state); + +public Q_SLOTS: + void onMainWindowVisibleChanged(const bool &visible); + void onSecurityTypeChange(QString devName, QString ssid, QString secuType); + void requestScan(); + void onWlanPageVisibleChanged(int index); + +private Q_SLOTS: + void onWlanAdded(QString interface, KyWirelessNetItem &item); + void onWlanRemoved(QString interface, QString ssid); + + void onConnectionAdd(QString deviceName, QString ssid); + void onConnectionRemove(QString deviceName, QString ssid, QString path); + + void onDeviceAdd(QString deviceName, NetworkManager::Device::Type deviceType); + void onDeviceRemove(QString deviceName); + void onDeviceNameUpdate(QString oldName, QString newName); + + void onConnectionStateChanged(QString uuid, + NetworkManager::ActiveConnection::State state, + NetworkManager::ActiveConnection::Reason reason); + void onItemHeightChanged(const bool isExpanded, const QString &ssid); + + void onDeviceComboxIndexChanged(int currentIndex); + void onHiddenWlanClicked(); + void showControlCenter(); + void onWifiEnabledChanged(bool isWifiOn); + void onRefreshIconTimer(); + + void onWlanStateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + //定时触发扫描的定时器 + void initTimer(); + void initWlanUI(); + void initConnections(); + void initDevice();//初始化默认设备 + void initDeviceCombox(); + void initWlanSwitchState(); + void initWlanArea(); + void addWlanMoreItem(); + + void showNonePwd(); + + void showRate(); + + QListWidgetItem *addEmptyItem(QListWidget *wirelessListWidget); + QListWidgetItem *addNewItem(KyWirelessNetItem &wirelessNetItem, + QListWidget *wirelessListWidget); + QListWidgetItem *insertNewItem(KyWirelessNetItem &wirelessNetItem, + QListWidget *wirelessListWidget, + int row); + QListWidgetItem *insertNewItemWithSort(KyWirelessNetItem &wirelessNetItem, + QListWidget *p_ListWidget); + + void clearWirelessNetItemMap(QMap &wirelessNetItem, + QListWidget *wirelessListWidget); + void deleteWirelessItemFormMap(QMap &wirelessNetItemMap, + QListWidget *wirelessListWidget, QString ssid); + + void updateWlanItemState(QListWidget *p_wirelessListWidget, + QListWidgetItem *p_listWidgetItem, + ConnectState state); + void updateWlanListItem(QString ssid); + void refreshActiveConnectionIcon(QString ssid, const int &signal); + + void constructWirelessNetArea(); + void constructActivateConnectionArea(); + + void updateActivatedArea(QString uuid, QString ssid, QString devName); + void updateWirelessNetArea(QString uuid, QString ssid, QString devName, QString path); + + void addDeviceToCombox(QString deviceName); + void deleteDeviceFromCombox(QString deviceName); + void updateDeviceForCombox(QString oldDeviceName, QString newDeviceName); + + void sendApStateChangeSignal(QString uuid, QString ssid, QString deviceName, + NetworkManager::ActiveConnection::State state); +// void wlanShowNotify(QString ssid, NetworkManager::ActiveConnection::State state, +// NetworkManager::ActiveConnection::Reason reason); + + //是否存在可用的无线网卡 + bool getWirelessDevieceUseable(); + void setWirelessEnable(bool state); + bool getWirelessEnable(); + inline void setSwitchBtnState(bool state) { + if (m_netSwitch != nullptr) { + m_netSwitch->setChecked(state); + } + } + inline bool getSwitchBtnState() { + if (m_netSwitch != nullptr) { + return m_netSwitch->isChecked(); + } + } + inline void setSwitchBtnEnable(bool state) { + if (m_netSwitch != nullptr) { + m_netSwitch->setCheckable(state); + } + } + inline bool getSwitchBtnEnable() { + if (m_netSwitch != nullptr) { + return m_netSwitch->isCheckable(); + } + } + +private: + QMap m_wirelessNetItemMap; + QMap m_activateConnectionItemMap; + + QListWidgetItem *m_expandedItem = nullptr; + + WlanMoreItem * m_hiddenWlanWidget = nullptr; + QListWidgetItem *m_hiddenItem = nullptr; + + QListWidget * m_activatedNetListWidget = nullptr; + QListWidget * m_inactivatedNetListWidget = nullptr; + + QStringList m_devList; + QString m_currentDevice; + + KyWirelessNetResource *m_wirelessNetResource = nullptr; + KyActiveConnectResourse *m_activatedConnectResource = nullptr; + KyNetworkDeviceResourse *m_netDeviceResource = nullptr; + KyWirelessConnectOperation * m_wirelessConnectOpreation = nullptr; + KyConnectResourse * m_connectResource = nullptr; + + bool m_updateStrength = true; + + QTimer *m_scanTimer = nullptr; + QTimer *m_refreshIconTimer = nullptr; + + JoinHiddenWiFiPage *m_hiddenWiFi = nullptr; +}; + +#endif // WLANPAGE_H diff --git a/src/frontend/tools/divider.cpp b/src/frontend/tools/divider.cpp new file mode 100644 index 00000000..1bb28182 --- /dev/null +++ b/src/frontend/tools/divider.cpp @@ -0,0 +1,42 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "divider.h" +#include +#include + +Divider::Divider(QWidget * parent) : QFrame(parent) +{ + this->setFixedHeight(1); +} + + + +void Divider::paintEvent(QPaintEvent * e) +{ + QPainter p(this); + QColor color = qApp->palette().color(QPalette::BrightText); + color.setAlphaF(0.08); + p.save(); + p.setBrush(color); + p.setPen(Qt::transparent); + p.drawRoundedRect(this->rect(), 6, 6); + p.restore(); + return QFrame::paintEvent(e); +} diff --git a/src/frontend/tools/divider.h b/src/frontend/tools/divider.h new file mode 100644 index 00000000..9d7b1729 --- /dev/null +++ b/src/frontend/tools/divider.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef DIVIDER_H +#define DIVIDER_H +#include + +class Divider : public QFrame +{ +public: + Divider(QWidget * parent = nullptr); + ~Divider() = default; + +protected: + void paintEvent(QPaintEvent *event); +}; + +#endif // DIVIDER_H diff --git a/src/frontend/tools/infobutton.cpp b/src/frontend/tools/infobutton.cpp new file mode 100644 index 00000000..62ff0d01 --- /dev/null +++ b/src/frontend/tools/infobutton.cpp @@ -0,0 +1,119 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "infobutton.h" +#include +#include +#include + +#define BUTTON_SIZE 36,36 +#define ICON_SIZE 16,16 +#define BACKGROUND_COLOR QColor(0,0,0,0) +#define FOREGROUND_COLOR_NORMAL qApp->palette().text().color() +//#define FOREGROUND_COLOR_HOVER QColor(55,144,250,255) +//#define FOREGROUND_COLOR_PRESS QColor(36,109,212,255) +#define FOREGROUND_COLOR_BRIGHTTEXT qApp->palette().brightText().color() +#define FOREGROUND_COLOR_HIGHLIGHT qApp->palette().highlight().color() +#define OUTER_PATH 8,10,16,16 +#define INNER_PATH 9,11,14,14 +#define TEXT_POS 14,7,16,16,0 + +#define BUTTON_SIZE 36,36 + +QColor mixColor(const QColor &c1, const QColor &c2, qreal bias); + +InfoButton::InfoButton(QWidget *parent) : QPushButton(parent) +{ + this->setFixedSize(BUTTON_SIZE); + initUI(); + connect(qApp, &QApplication::paletteChanged, this, &InfoButton::onPaletteChanged); +} + +void InfoButton::initUI() +{ + this->setFixedSize(BUTTON_SIZE); + m_backgroundColor = BACKGROUND_COLOR; + m_foregroundColor = FOREGROUND_COLOR_NORMAL; +} + +void InfoButton::onPaletteChanged() +{ + m_foregroundColor = FOREGROUND_COLOR_NORMAL; + this->repaint(); +} + +void InfoButton::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + pal.setColor(QPalette::Base, m_backgroundColor); + pal.setColor(QPalette::Text, m_foregroundColor); + + QPainterPath cPath; + cPath.addRect(0, 0, ICON_SIZE); + cPath.addEllipse(0, 0, ICON_SIZE); + + QPainterPath outerPath; + outerPath.addEllipse(OUTER_PATH); + + QPainterPath innerPath; + innerPath.addEllipse(INNER_PATH); + outerPath -= innerPath; + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + + painter.setBrush(pal.color(QPalette::Base)); + painter.drawPath(cPath); + + painter.fillPath(outerPath, pal.color(QPalette::Text)); + painter.setPen(m_foregroundColor); + QFont font("Noto Sans CJK SC", 11, QFont::Normal, false); + painter.setFont(font); + painter.drawText(TEXT_POS, "i"); +} + +void InfoButton::enterEvent(QEvent *event) +{ +// m_foregroundColor = FOREGROUND_COLOR_HOVER; + m_foregroundColor = FOREGROUND_COLOR_HIGHLIGHT; + this->update(); +} + +void InfoButton::leaveEvent(QEvent *event) +{ + m_foregroundColor = FOREGROUND_COLOR_NORMAL; + this->update(); +} + +void InfoButton::mousePressEvent(QMouseEvent *event) +{ +// m_foregroundColor = FOREGROUND_COLOR_PRESS; + m_foregroundColor = mixColor(FOREGROUND_COLOR_HIGHLIGHT, FOREGROUND_COLOR_BRIGHTTEXT, 0.2); + this->update(); + return QPushButton::mousePressEvent(event); +} + +void InfoButton::mouseReleaseEvent(QMouseEvent *event) +{ +// m_foregroundColor = FOREGROUND_COLOR_HOVER; + m_foregroundColor = mixColor(FOREGROUND_COLOR_HIGHLIGHT, FOREGROUND_COLOR_BRIGHTTEXT, 0.2); + this->update(); + return QPushButton::mouseReleaseEvent(event); +} diff --git a/src/frontend/tools/infobutton.h b/src/frontend/tools/infobutton.h new file mode 100644 index 00000000..34e57891 --- /dev/null +++ b/src/frontend/tools/infobutton.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef INFOBUTTON_H +#define INFOBUTTON_H +#include +#include + +class InfoButton : public QPushButton +{ + Q_OBJECT +public: + explicit InfoButton(QWidget * parent = nullptr); + ~InfoButton() = default; + +protected: + void paintEvent(QPaintEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +private: + void initUI(); + +private: + QColor m_backgroundColor; + QColor m_foregroundColor; + +private Q_SLOTS: + void onPaletteChanged(); +}; + +#endif // INFOBUTTON_H diff --git a/src/frontend/tools/kylable.cpp b/src/frontend/tools/kylable.cpp new file mode 100644 index 00000000..a734877b --- /dev/null +++ b/src/frontend/tools/kylable.cpp @@ -0,0 +1,117 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "kylable.h" +#include +#include +#include + +#define FOREGROUND_COLOR_NORMAL qApp->palette().text().color() + +static inline qreal mixQreal(qreal a, qreal b, qreal bias) +{ + return a + (b - a) * bias; +} + + +QColor mixColor(const QColor &c1, const QColor &c2, qreal bias) +{ + if (bias <= 0.0) { + return c1; + } + if (bias >= 1.0) { + return c2; + } + if (qIsNaN(bias)) { + return c1; + } + + qreal r = mixQreal(c1.redF(), c2.redF(), bias); + qreal g = mixQreal(c1.greenF(), c2.greenF(), bias); + qreal b = mixQreal(c1.blueF(), c2.blueF(), bias); + qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias); + + return QColor::fromRgbF(r, g, b, a); +} + +KyLable::KyLable(QWidget *parent) : QLabel(parent) +{ + connect(qApp, &QApplication::paletteChanged, this, &KyLable::onPaletteChanged); + onPaletteChanged(); +} + +void KyLable::onPaletteChanged() +{ + m_foregroundColor = FOREGROUND_COLOR_NORMAL; + this->repaint(); +} + +void KyLable::setPressColor() +{ + QColor hightlight = this->palette().color(QPalette::Active,QPalette::Highlight); + QColor mix = this->palette().color(QPalette::Active,QPalette::BrightText); + m_foregroundColor = mixColor(hightlight, mix, 0.2); +} + +void KyLable::setHoverColor() +{ +// QColor hightlight = this->palette().color(QPalette::Active,QPalette::Highlight); +// QColor mix = this->palette().color(QPalette::Active,QPalette::BrightText); +// m_foregroundColor = mixColor(hightlight, mix, 0.2); + m_foregroundColor = this->palette().color(QPalette::Active,QPalette::Highlight); +} + +void KyLable::setNormalColor() +{ + m_foregroundColor = FOREGROUND_COLOR_NORMAL; +} + +void KyLable::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + pal.setColor(QPalette::WindowText, m_foregroundColor); + this->setPalette(pal); + return QLabel::paintEvent(event); +} + +void KyLable::enterEvent(QEvent *event) +{ + setHoverColor(); + this->update(); +} + +void KyLable::leaveEvent(QEvent *event) +{ + setNormalColor(); + this->update(); +} + +void KyLable::mousePressEvent(QMouseEvent *event) +{ + setPressColor(); + this->update(); + return QLabel::mousePressEvent(event); +} + +void KyLable::mouseReleaseEvent(QMouseEvent *event) +{ + setHoverColor(); + this->update(); + return QLabel::mouseReleaseEvent(event); +} diff --git a/src/frontend/tools/kylable.h b/src/frontend/tools/kylable.h new file mode 100644 index 00000000..3a3cb24a --- /dev/null +++ b/src/frontend/tools/kylable.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef KYLABLE_H +#define KYLABLE_H + +#include +#include + +class KyLable : public QLabel +{ + Q_OBJECT +public: + explicit KyLable(QWidget *parent = nullptr); + ~KyLable() = default; + +protected: + void paintEvent(QPaintEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +private: + QColor m_foregroundColor; + + void setPressColor(); + void setHoverColor(); + void setNormalColor(); + +private Q_SLOTS: + void onPaletteChanged(); + +}; + +#endif // KYLABLE_H diff --git a/src/frontend/tools/loadingdiv.cpp b/src/frontend/tools/loadingdiv.cpp new file mode 100644 index 00000000..9e3b1f87 --- /dev/null +++ b/src/frontend/tools/loadingdiv.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see + +#define FRAMESPEED 60 //帧与帧之间的间隔时间(ms) +#define ALLTIME 40*1000 //等待动画持续总时间 + +//加载动画控件'loadingGif' +LoadingDiv::LoadingDiv(QWidget *parent) : QWidget(parent) +{ + this->resize(480, 538); + + this->loadingGif = new QLabel(this); + this->loadingGif->resize(96, 96); + this->loadingGif->move(this->width()/2 - 96/2 + 41/2 - 40, this->height()/2 + 20); + this->loadingGif->show(); + + this->switchTimer = new QTimer(this); //QTimer对象,控制等待动画播放 + connect(switchTimer, SIGNAL(timeout()), this, SLOT(switchAnimStep())); + + this->raise(); + this->hide(); +} + +//加载动画控件'loadingGif' +void LoadingDiv::switchAnimStep() +{ + //另外一种加载方法 + QString qpmQss = ":/res/s/conning-b/"; + qpmQss.append(QString::number(this->currentPage)); + qpmQss.append(".png"); + loadingGif->setPixmap(QPixmap(qpmQss)); + loadingGif->setProperty("useIconHighlightEffect", true); + loadingGif->setProperty("iconHighlightEffectMode", true); + + this->currentPage --; + + if (this->currentPage < 1) { + this->currentPage = 12; //循环播放 + } + this->countCurrentTime += FRAMESPEED; + if (this->countCurrentTime >= ALLTIME) { + Q_EMIT this->toStopLoading(); //发出信号停止主界面和托盘区的等待动画 + } +} + +//开始播放动画 +void LoadingDiv::startLoading() +{ + this->currentPage = 12; + this->countCurrentTime = 0; + this->switchTimer->start(FRAMESPEED); + this->show(); +} + +//结束播放动画 +void LoadingDiv::stopLoading() +{ + this->switchTimer->stop(); + this->hide(); +} diff --git a/src/frontend/tools/loadingdiv.h b/src/frontend/tools/loadingdiv.h new file mode 100644 index 00000000..f8ee9e30 --- /dev/null +++ b/src/frontend/tools/loadingdiv.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include +#include +#include + +class LoadingDiv : public QWidget +{ + Q_OBJECT +public: + explicit LoadingDiv(QWidget *parent = nullptr); + +Q_SIGNALS: + void toStopLoading(); + +public Q_SLOTS: + void switchAnimStep(); + void startLoading(); + void stopLoading(); + +private: + QLabel *loadingGif = nullptr; + QTimer *switchTimer = nullptr; + + int currentPage; + int countCurrentTime; +}; + +#endif // LOADINGDIV_H diff --git a/src/frontend/tools/radioitembutton.cpp b/src/frontend/tools/radioitembutton.cpp new file mode 100644 index 00000000..02cd9a70 --- /dev/null +++ b/src/frontend/tools/radioitembutton.cpp @@ -0,0 +1,285 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "radioitembutton.h" +#include +#include +#include +#include +#include +#define FLASH_SPEED 100 +#define TIMEOUT_TIMER 90*1000 +#define BUTTON_SIZE 36,36 +#define ICON_SIZE 16,16 +#define BACKGROUND_COLOR QColor(0,0,0,0) +#define FOREGROUND_COLOR_NORMAL_INACTIVE_LIGHT QColor(230,230,230,255) +#define FOREGROUND_COLOR_NORMAL_INACTIVE_DARK QColor(55,55,55,255) +#define FOREGROUND_COLOR_PRESS_INACTIVE_LIGHT QColor(217,217,217,255) +#define FOREGROUND_COLOR_PRESS_INACTIVE_DARK QColor(70,70,70,255) +#define FOREGROUND_COLOR_NORMAL_ACTIVE QColor(55,144,250,255) +#define FOREGROUND_COLOR_PRESS_ACTIVE QColor(36,109,212,255) +#define COLOR_BRIGHT_TEXT qApp->palette().brightText().color() +#define COLOR_HIGH_LIGHT qApp->palette().highlight().color() +#define THEME_SCHAME "org.ukui.style" + +QColor mixColor(const QColor &c1, const QColor &c2, qreal bias); + +RadioItemButton::RadioItemButton(QWidget *parent) : QPushButton(parent) +{ + this->setAutoFillBackground(false); + m_iconLabel = new QLabel(this); + + this->setFixedSize(BUTTON_SIZE); + m_iconLabel->setFixedSize(BUTTON_SIZE); + m_iconLabel->setAlignment(Qt::AlignCenter); + + setActive(false); + + const QByteArray id(THEME_SCHAME); + if (QGSettings::isSchemaInstalled(id)) { + m_styleGSettings = new QGSettings(id); + connect(m_styleGSettings, &QGSettings::changed, this, [=](QString key){ + if ("themeColor" == key) { + onPaletteChanged(); + } + }); + } + + //JXJ_TODO loading动画 + connect(this, &RadioItemButton::requestStartLoading, this, &RadioItemButton::onLoadingStarted); + connect(this , &RadioItemButton::requestStopLoading, this, &RadioItemButton::onLoadingStopped); + connect(qApp, &QApplication::paletteChanged, this, &RadioItemButton::onPaletteChanged); +} + +RadioItemButton::~RadioItemButton() +{ + if (m_styleGSettings != nullptr) { + delete m_styleGSettings; + m_styleGSettings = nullptr; + } +} + +void RadioItemButton::startLoading() +{ + Q_EMIT this->requestStartLoading(); +} + +void RadioItemButton::stopLoading() +{ + Q_EMIT this->requestStopLoading(); +} +//设置图标 +void RadioItemButton::setButtonIcon(const QIcon &icon) +{ + if (icon.isNull()) { + return; + } + m_pixmap = icon.pixmap(ICON_SIZE); +// m_iconLabel->setPixmap(m_pixmap); +} +//显示默认图标 +void RadioItemButton::setDefaultPixmap() +{ + m_iconLabel->setPixmap(m_pixmap); +} +//根据连接状态更改图标颜色 +void RadioItemButton::setActive(const bool &isActive) +{ + m_isActivated = isActive; + refreshButtonIcon(); +} +void RadioItemButton::onLoadingStarted() +{ +#define ANIMATION_SPEED 0.5*1000 +#define START_ROTATION 0 +#define END_ROTATION 360 +#define ANIMATION_LOOP -1 //无限旋转 + if (!m_iconLabel) { + qWarning() << "Start loading failed, iconLabel is null pointer!" << Q_FUNC_INFO << __LINE__; + } + if (!m_animation) { + m_animation = new QVariantAnimation(m_iconLabel); + } + m_animation->setDuration(ANIMATION_SPEED); + m_animation->setStartValue(START_ROTATION); + m_animation->setEndValue(END_ROTATION); + m_animation->setLoopCount(ANIMATION_LOOP); + connect(m_animation, &QVariantAnimation::valueChanged, this, &RadioItemButton::onAnimationValueChanged); + m_animation->start(); +} + +void RadioItemButton::onLoadingStopped() +{ + if (!m_animation) { + qWarning() << "Stop loading failed, m_animation is null pointer!" << Q_FUNC_INFO << __LINE__; + return; + } else { + m_iconLabel->setPixmap(m_pixmap); + m_animation->stop(); + Q_EMIT this->animationStoped(); + } + +} + +void RadioItemButton::onPaletteChanged() +{ + refreshButtonIcon(); +} + +void RadioItemButton::onAnimationValueChanged(const QVariant& value) +{ + if (!m_iconLabel) { + return; + } + QTransform t; + t.rotate(value.toReal()); + m_iconLabel->setPixmap(QIcon(":/res/s/conning-a/1.png").pixmap(ICON_SIZE).transformed(t)); +} + +void RadioItemButton::paintEvent(QPaintEvent *event) +{ + QPalette pal = this->palette(); + pal.setColor(QPalette::Base, BACKGROUND_COLOR); + pal.setColor(QPalette::Text, m_backgroundColor); + + QPainterPath cPath; + cPath.addRect(0, 0, this->width(), this->height()); + cPath.addEllipse(0, 0, this->width(), this->width()); + + QPainterPath innerPath; + innerPath.addEllipse(0, 0, this->width(), this->width()); + + QPainter painter(this); + painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿 + painter.setPen(Qt::NoPen); + + painter.setBrush(pal.color(QPalette::Base)); + painter.drawPath(cPath); + + painter.fillPath(innerPath, pal.color(QPalette::Text)); +} + +void RadioItemButton::mousePressEvent(QMouseEvent *event) +{ + if (m_isActivated) { +// m_backgroundColor = qApp->palette().highlight().color(); + m_backgroundColor = mixColor(COLOR_HIGH_LIGHT, COLOR_BRIGHT_TEXT, 0.2); + } else { + m_backgroundColor = COLOR_BRIGHT_TEXT; + m_backgroundColor.setAlphaF(0.21); + } + this->update(); + return QPushButton::mousePressEvent(event); +} + +void RadioItemButton::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_isActivated) { + m_backgroundColor = COLOR_HIGH_LIGHT; + } else { + m_backgroundColor = COLOR_BRIGHT_TEXT; + m_backgroundColor.setAlphaF(0.12); + } + this->update(); + return QPushButton::mouseReleaseEvent(event); +} + +void RadioItemButton::enterEvent(QEvent *event) +{ + if (m_isActivated) { + m_backgroundColor = COLOR_HIGH_LIGHT; + } else { + m_backgroundColor = COLOR_BRIGHT_TEXT; + m_backgroundColor.setAlphaF(0.15); + } + this->update(); + return QPushButton::enterEvent(event); +} + +void RadioItemButton::leaveEvent(QEvent *event) +{ + if (m_isActivated) { + m_backgroundColor = COLOR_HIGH_LIGHT; + } else { + m_backgroundColor = COLOR_BRIGHT_TEXT; + m_backgroundColor.setAlphaF(0.12); + } + this->update(); + return QPushButton::leaveEvent(event); +} + +void RadioItemButton::refreshButtonIcon() +{ + if (m_isActivated) { + m_backgroundColor = COLOR_HIGH_LIGHT; + m_iconLabel->setPixmap(loadSvg(m_pixmap, PixmapColor::WHITE)); + } else { + m_backgroundColor = COLOR_BRIGHT_TEXT; + m_backgroundColor.setAlphaF(0.18); + if (qApp->palette().base().color().red() > MIDDLE_COLOR) { + m_iconLabel->setPixmap(m_pixmap); + } else { + m_iconLabel->setPixmap(loadSvg(m_pixmap, PixmapColor::WHITE)); + } + } + + return; +} + +const QPixmap RadioItemButton::loadSvg(const QPixmap &source, const PixmapColor &cgColor) +{ + QImage img = source.toImage(); + for (int x = 0; x < img.width(); x++) { + for (int y = 0; y < img.height(); y++) { + auto color = img.pixelColor(x, y); + if (color.alpha() > 0) { + switch (cgColor) { + case PixmapColor::WHITE: + color.setRed(255); + color.setGreen(255); + color.setBlue(255); + img.setPixelColor(x, y, color); + break; + case PixmapColor::BLACK: + color.setRed(0); + color.setGreen(0); + color.setBlue(0); + img.setPixelColor(x, y, color); + break; + case PixmapColor::GRAY: + color.setRed(152); + color.setGreen(163); + color.setBlue(164); + img.setPixelColor(x, y, color); + break; + case PixmapColor::BLUE: + color.setRed(61); + color.setGreen(107); + color.setBlue(229); + img.setPixelColor(x, y, color); + break; + default: + return source; + break; + } + } + } + } + return QPixmap::fromImage(img); +} diff --git a/src/frontend/tools/radioitembutton.h b/src/frontend/tools/radioitembutton.h new file mode 100644 index 00000000..1904f7da --- /dev/null +++ b/src/frontend/tools/radioitembutton.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#ifndef NETBUTTON_H +#define NETBUTTON_H +#include +#include +#include +#include +#include +#include + +#define MIDDLE_COLOR 178 + +class RadioItemButton : public QPushButton +{ + Q_OBJECT + +public: + RadioItemButton(QWidget * parent = nullptr); + ~RadioItemButton(); + void startLoading(); + void stopLoading(); + void setButtonIcon(const QIcon &icon); + void setDefaultPixmap(); + void setActive(const bool &isActive); + enum PixmapColor { + WHITE = 0, + BLACK, + GRAY, + BLUE, + }; + const QPixmap loadSvg(const QPixmap &source, const PixmapColor &color); + +Q_SIGNALS: + void requestStartLoading(); + void requestStopLoading(); + void animationStoped(); + +protected: + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + +private: + bool m_isActivated = false; + QLabel * m_iconLabel = nullptr; + QColor m_backgroundColor; + QVariantAnimation * m_animation = nullptr; + + QPixmap m_pixmap; + QGSettings *m_styleGSettings = nullptr; + + void refreshButtonIcon(); + +private Q_SLOTS: + void onLoadingStarted(); + void onLoadingStopped(); + void onPaletteChanged(); + void onAnimationValueChanged(const QVariant& value); +}; + +#endif // NETBUTTON_H + diff --git a/src/frontend/tools/switchbutton.cpp b/src/frontend/tools/switchbutton.cpp new file mode 100644 index 00000000..e906f78f --- /dev/null +++ b/src/frontend/tools/switchbutton.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see setInterval(5); + + if(m_bIsOn == 1) { + m_fCurrentValue = m_fWidth - 16 - 4; + } + else { + m_fCurrentValue = 4; + } + connect(m_cTimer, SIGNAL(timeout()), this, SLOT(startAnimation())); + + +} + +void SwitchButton::setSwitchStatus(bool check) { + if (!m_enabled) + return; + + if(check == true) { + m_bIsOn = 1; + } else { + m_bIsOn = 0; + } + Q_EMIT this->switchStatusChanged(); + + m_cTimer->start(); //开始播放动画 +} + +bool SwitchButton::getSwitchStatus() +{ + if (m_bIsOn == 1) + return true; + return false; +} + +void SwitchButton::setEnabled(bool enabled) +{ + m_enabled = enabled; + update(); + + return; +} + +bool SwitchButton::getEnabled() +{ + return m_enabled; +} +/* 播放按钮开启关闭动画 */ +void SwitchButton::startAnimation() { //滑动按钮动作播放 + int pos = 4; + int size = m_fWidth - 16; + if(m_bIsOn) { + m_fCurrentValue ++; //往右滑动 + if(m_fCurrentValue >= size - pos) { //到达边界停下来 + m_fCurrentValue = size - pos; + m_cTimer->stop(); + } + } else { + m_fCurrentValue --; + if(m_fCurrentValue <= pos) { //到达最小值,停止继续前进 + m_fCurrentValue = pos; + m_cTimer->stop(); + } + } + update(); +} + +/* 按钮按下处理 */ +void SwitchButton::mousePressEvent(QMouseEvent *event) { + Q_UNUSED(event); + + if (m_enabled) { + m_bIsOn = !m_bIsOn; + } + Q_EMIT clicked(); + return QWidget::mousePressEvent(event); +} + +void SwitchButton::enterEvent(QEvent *event) +{ + if (m_enabled && m_bIsOn) { + m_colorActive = COLOR_ACTIVE_HOVER; + } else if (m_enabled && !m_bIsOn) { + m_colorInactive = COLOR_INACTIVE_HOVER; + } + + this->update(); + + return QWidget::enterEvent(event); +} + +void SwitchButton::leaveEvent(QEvent *event) +{ + if (m_enabled && m_bIsOn) { + m_colorActive = COLOR_ACTIVE; + } else if (m_enabled && !m_bIsOn) { + m_colorInactive = COLOR_INACTIVE; + } + + this->update(); + + return QWidget::leaveEvent(event); +} + +/* 绘制滑动按钮主体 */ +void SwitchButton::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); + QPainter painter(this); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + painter.setRenderHint(QPainter::Antialiasing); //抗锯齿效果 + painter.setPen(Qt::NoPen); + if(m_bIsOn && m_enabled) { + painter.save(); + painter.setBrush(m_colorActive); + QRectF active_rect = QRectF(0,0,m_fWidth,m_fHeight); + painter.drawRoundedRect(active_rect, 0.5 * m_fHeight, 0.5 * m_fHeight); //画开启状态 + } else { + painter.save(); + painter.setBrush(m_colorInactive); + QRectF inactive_rect = QRectF(0 ,0,m_fWidth,m_fHeight); + painter.drawRoundedRect(inactive_rect, 0.5 * m_fHeight, 0.5 * m_fHeight); //画关闭状态 + } + painter.restore(); + painter.save(); + if (!m_enabled) { + painter.setBrush(COLOR_UNABLE); +// QRectF enableRect = QRectF(30, 10, 8, 4); +// painter.drawRoundedRect(enableRect, 2, 2); + } else { + painter.setBrush(Qt::white); + } + painter.drawEllipse(m_fCurrentValue,4, 16, 16); + + painter.restore(); +} + diff --git a/src/frontend/tools/switchbutton.h b/src/frontend/tools/switchbutton.h new file mode 100644 index 00000000..fea1e480 --- /dev/null +++ b/src/frontend/tools/switchbutton.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include +#include + +class SwitchButton : public QWidget +{ + Q_OBJECT +public: + explicit SwitchButton(QWidget *parent = nullptr); + void setSwitchStatus(bool check); + bool getSwitchStatus(); + void setEnabled(bool enabled); + bool getEnabled(); + +private: + QColor m_colorActive; + QColor m_colorInactive; + int m_bIsOn = 1; + QTimer *m_cTimer; + float m_fWidth; + float m_fHeight; + float m_fCurrentValue; + void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *event); + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + bool m_enabled = true; + +Q_SIGNALS: + void clicked(); + void switchStatusChanged(); + +private Q_SLOTS: + void startAnimation(); + +}; + +#endif // SWITCHBUTTON_H diff --git a/src/frontend/tools/tools.pri b/src/frontend/tools/tools.pri new file mode 100644 index 00000000..7863428b --- /dev/null +++ b/src/frontend/tools/tools.pri @@ -0,0 +1,18 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/divider.h \ + $$PWD/infobutton.h \ + $$PWD/loadingdiv.h \ + $$PWD/radioitembutton.h \ + $$PWD/switchbutton.h \ + $$PWD/kylable.h + + +SOURCES += \ + $$PWD/divider.cpp \ + $$PWD/infobutton.cpp \ + $$PWD/loadingdiv.cpp \ + $$PWD/radioitembutton.cpp \ + $$PWD/switchbutton.cpp \ + $$PWD/kylable.cpp diff --git a/src/frontend/wificonfigdialog.cpp b/src/frontend/wificonfigdialog.cpp new file mode 100644 index 00000000..3207eca7 --- /dev/null +++ b/src/frontend/wificonfigdialog.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "wificonfigdialog.h" +#include "ui_wificonfigdialog.h" +#include "utils.h" + +#include +#include +#include +#include + +#include + +WiFiConfigDialog::WiFiConfigDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::WiFiConfigDialog) +{ + ui->setupUi(this); + + initTransparentState(); //初始化窗口透明度的GSetting方法 + + this->setWindowFlags(Qt::FramelessWindowHint); //Qt::WindowStaysOnTopHint + this->setWindowTitle(tr("WLAN Authentication"));//"Wifi 认证" + this->setAttribute(Qt::WA_TranslucentBackground); + this->setWindowIcon(QIcon::fromTheme("kylin-network", QIcon(":/res/x/setup.png")) ); + + QPainterPath path; + auto rect = this->rect(); + rect.adjust(1, 1, -1, -1); + path.addRoundedRect(rect, 6, 6); + setProperty("blurRegion", QRegion(path.toFillPolygon().toPolygon())); + KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); + + ui->lbTitle->setText(tr("Input WLAN Information Please")); //输入Wi-Fi名称和密码后点击确定 + ui->lbWifiId->setText(tr("WLAN ID:")); //Wi-Fi连接名称: + ui->lbWifiName->setText(tr("WLAN Name:")); //Wi-Fi名称: + ui->lbWifiPassord->setText(tr("Password:")); //Wi-Fi密码: + ui->btnCancel->setText(tr("Cancl")); + ui->btnOk->setText(tr("Ok")); + ui->leWifiId->setContextMenuPolicy(Qt::NoContextMenu); + ui->leWiFiName->setContextMenuPolicy(Qt::NoContextMenu); + + ui->leWifiPassword->setContextMenuPolicy(Qt::NoContextMenu); + ui->leWifiPassword ->setEchoMode(QLineEdit::Password); + + ui->checkBoxPwd->setStyleSheet(checkBoxQss); + ui->checkBoxPwd->setFocusPolicy(Qt::NoFocus); + + ui->leWifiId->setContextMenuPolicy(Qt::NoContextMenu); //禁止LineEdit的右键菜单 + ui->leWiFiName->setContextMenuPolicy(Qt::NoContextMenu); + ui->leWifiPassword->setContextMenuPolicy(Qt::NoContextMenu); + + this->setEnableOfBtn(); + this->setFixedSize(474, 320); +} + +WiFiConfigDialog::~WiFiConfigDialog() +{ + delete ui; +} + +void WiFiConfigDialog::paintEvent(QPaintEvent *event) +{ + double trans = this->getTransparentData(); + + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + + QRect rect = this->rect(); + p.setRenderHint(QPainter::Antialiasing); // 反锯齿; + p.setBrush(opt.palette.color(QPalette::Base)); + p.setOpacity(trans); + p.setPen(Qt::NoPen); + p.drawRoundedRect(rect, 6, 6); + QWidget::paintEvent(event); +} + +//创建获取窗口透明度信息的GSetting的对象 +void WiFiConfigDialog::initTransparentState() +{ + if (QGSettings::isSchemaInstalled("org.ukui.control-center.personalise")) { + m_transparency_gsettings = new QGSettings("org.ukui.control-center.personalise"); + } +} + +//使用GSetting获取当前窗口应该使用的透明度 +double WiFiConfigDialog::getTransparentData() +{ + if (!m_transparency_gsettings) { + return 0.7; + } + + QStringList keys = m_transparency_gsettings->keys(); + if (keys.contains("transparency")) { + double tp = m_transparency_gsettings->get("transparency").toDouble(); + return tp; + } else { + return 0.7; + } +} + +void WiFiConfigDialog::on_btnCancel_clicked() +{ + ui->leWiFiName->setText(""); + ui->leWifiPassword->setText(""); + hide(); +} + +void WiFiConfigDialog::on_btnOk_clicked() +{ + QFuture < void > future1 = QtConcurrent::run([=](){ + this->toConfigWifi(); + }); + hide(); +} + +void WiFiConfigDialog::toConfigWifi() +{ + QString connName = ui->leWiFiName->text(); + QString password = ui->leWifiPassword->text(); + + QString strConntype = "nmcli connection modify '" + connName + "' wifi-sec.psk-flags 0"; + Utils::m_system(strConntype.toUtf8().data()); + + QString tmpPath = "/tmp/kylin-nm-btoutput-" + QDir::home().dirName(); + QString cmdStr = "export LANG='en_US.UTF-8';export LANGUAGE='en_US';nmcli device wifi connect '" + connName + "' password '" + password + "' > " + tmpPath; + Utils::m_system(cmdStr.toUtf8().data()); + + QFile file(tmpPath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug()<<"Can't open the file /tmp/kylin-nm-btoutput in function toConfigWifi !"; + } + QString line = file.readLine(); + file.close(); + qDebug()<<"connect_wifi_result: "<< line; + + if (line.indexOf("successfully") != -1) { + QString strConntype = "nmcli connection modify '" + connName + "' wifi-sec.psk-flags 2"; + system(strConntype.toUtf8().data()); + } else { + QString cmd = "export LANG='en_US.UTF-8';export LANGUAGE='en_US';nmcli connection delete '" + ui->leWifiId->text() + "'"; + int status = system(cmd.toUtf8().data()); + qDebug()<<"executed cmd="< + + WiFiConfigDialog + + + + 0 + 0 + 474 + 320 + + + + Dialog + + + + + 60 + 30 + 290 + 30 + + + + + + + + + + 60 + 140 + 90 + 30 + + + + + + + + + + 60 + 200 + 90 + 30 + + + + + + + + + + 190 + 140 + 240 + 30 + + + + + + + 190 + 200 + 241 + 30 + + + + + + + 220 + 260 + 96 + 36 + + + + + + + + + + 330 + 260 + 96 + 36 + + + + + + + + + + 60 + 80 + 121 + 30 + + + + + + + + + + 190 + 80 + 240 + 30 + + + + + + + 400 + 211 + 18 + 9 + + + + + + + + + + diff --git a/src/frontend/xatom/xatom-helper.cpp b/src/frontend/xatom/xatom-helper.cpp new file mode 100644 index 00000000..cf7b2936 --- /dev/null +++ b/src/frontend/xatom/xatom-helper.cpp @@ -0,0 +1,210 @@ +/* + * KWin Style UKUI + * + * Copyright (C) 2020, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Yue Lan + * + */ + +#include "xatom-helper.h" +#include +#include +#include +#include + +static XAtomHelper *global_instance = nullptr; + +XAtomHelper *XAtomHelper::getInstance() +{ + if(!global_instance) + global_instance = new XAtomHelper; + return global_instance; +} + +bool XAtomHelper::isFrameLessWindow(int winId) +{ + auto hints = getInstance()->getWindowMotifHint(winId); + if(hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { + return true; + } + return false; +} + +bool XAtomHelper::isWindowDecorateBorderOnly(int winId) +{ + return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); +} + +bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) { + bool isDeco = false; + if(hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { + if(hint.decorations == MWM_DECOR_BORDER) + isDeco = true; + } + return isDeco; +} + +bool XAtomHelper::isUKUICsdSupported() +{ + // fixme: + return false; +} + +bool XAtomHelper::isUKUIDecorationWindow(int winId) +{ + if(m_ukuiDecorationAtion == None) + return false; + + Atom type; + int format; + ulong nitems; + ulong bytes_after; + uchar *data; + + bool isUKUIDecoration = false; + + XGetWindowProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, + 0, LONG_MAX, false, + m_ukuiDecorationAtion, &type, + &format, &nitems, + &bytes_after, &data); + + if(type == m_ukuiDecorationAtion) { + if(nitems == 1) { + isUKUIDecoration = data[0]; + } + } + + return isUKUIDecoration; +} + +UnityCorners XAtomHelper::getWindowBorderRadius(int winId) +{ + UnityCorners corners; + + Atom type; + int format; + ulong nitems; + ulong bytes_after; + uchar *data; + + if(m_unityBorderRadiusAtom != None) { + XGetWindowProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, + 0, LONG_MAX, false, + XA_CARDINAL, &type, + &format, &nitems, + &bytes_after, &data); + + if(type == XA_CARDINAL) { + if(nitems == 4) { + corners.topLeft = static_cast(data[0]); + corners.topRight = static_cast(data[1 * sizeof(ulong)]); + corners.bottomLeft = static_cast(data[2 * sizeof(ulong)]); + corners.bottomRight = static_cast(data[3 * sizeof(ulong)]); + } + XFree(data); + } + } + + return corners; +} + +void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) +{ + if(m_unityBorderRadiusAtom == None) + return; + + ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight}; + + XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof(corners) / sizeof(corners[0])); +} + +void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) +{ + if(m_unityBorderRadiusAtom == None) + return; + + ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight}; + + XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof(corners) / sizeof(corners[0])); +} + +void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) +{ + if(m_ukuiDecorationAtion == None) + return; + + XChangeProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &set, 1); +} + +void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) +{ + if(m_unityBorderRadiusAtom == None) + return; + + XChangeProperty(QX11Info::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom, + 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&hints, sizeof(MotifWmHints) / sizeof(ulong)); +} + +MotifWmHints XAtomHelper::getWindowMotifHint(int winId) +{ + MotifWmHints hints; + + if(m_unityBorderRadiusAtom == None) + return hints; + + uchar *data; + Atom type; + int format; + ulong nitems; + ulong bytes_after; + + XGetWindowProperty(QX11Info::display(), winId, m_motifWMHintsAtom, + 0, sizeof(MotifWmHints) / sizeof(long), false, AnyPropertyType, &type, + &format, &nitems, &bytes_after, &data); + + if(type == None) { + return hints; + } else { + hints = *(MotifWmHints *)data; + XFree(data); + } + return hints; +} + +XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) +{ + if(!QX11Info::isPlatformX11()) + return; + + m_motifWMHintsAtom = XInternAtom(QX11Info::display(), "_MOTIF_WM_HINTS", true); + m_unityBorderRadiusAtom = XInternAtom(QX11Info::display(), "_UNITY_GTK_BORDER_RADIUS", false); + m_ukuiDecorationAtion = XInternAtom(QX11Info::display(), "_KWIN_UKUI_DECORAION", false); +} + +Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() +{ + // fixme: + return None; +} + +void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() +{ + // fixme: +} diff --git a/src/frontend/xatom/xatom-helper.h b/src/frontend/xatom/xatom-helper.h new file mode 100644 index 00000000..87272454 --- /dev/null +++ b/src/frontend/xatom/xatom-helper.h @@ -0,0 +1,110 @@ +/* + * KWin Style UKUI + * + * Copyright (C) 2020, KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Yue Lan + * + */ + +#ifndef XATOMHELPER_H +#define XATOMHELPER_H + +#include +#include +#include + +struct UnityCorners { + ulong topLeft = 0; + ulong topRight = 0; + ulong bottomLeft = 0; + ulong bottomRight = 0; +}; + +typedef struct { + ulong flags = 0; + ulong functions = 0; + ulong decorations = 0; + long input_mode = 0; + ulong status = 0; +} MotifWmHints, MwmHints; + +#define MWM_HINTS_FUNCTIONS (1L << 0) +#define MWM_HINTS_DECORATIONS (1L << 1) +#define MWM_HINTS_INPUT_MODE (1L << 2) +#define MWM_HINTS_STATUS (1L << 3) + +#define MWM_FUNC_ALL (1L << 0) +#define MWM_FUNC_RESIZE (1L << 1) +#define MWM_FUNC_MOVE (1L << 2) +#define MWM_FUNC_MINIMIZE (1L << 3) +#define MWM_FUNC_MAXIMIZE (1L << 4) +#define MWM_FUNC_CLOSE (1L << 5) + +#define MWM_DECOR_ALL (1L << 0) +#define MWM_DECOR_BORDER (1L << 1) +#define MWM_DECOR_RESIZEH (1L << 2) +#define MWM_DECOR_TITLE (1L << 3) +#define MWM_DECOR_MENU (1L << 4) +#define MWM_DECOR_MINIMIZE (1L << 5) +#define MWM_DECOR_MAXIMIZE (1L << 6) + +#define MWM_INPUT_MODELESS 0 +#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 +#define MWM_INPUT_SYSTEM_MODAL 2 +#define MWM_INPUT_FULL_APPLICATION_MODAL 3 +#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL + +#define MWM_TEAROFF_WINDOW (1L<<0) + +namespace UKUI { +class Decoration; +} + +class XAtomHelper : public QObject +{ + // friend class UKUI::Decoration; + Q_OBJECT +public: + static XAtomHelper *getInstance(); + + static bool isFrameLessWindow(int winId); + + static bool isWindowDecorateBorderOnly(int winId); + static bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint); + bool isUKUICsdSupported(); + bool isUKUIDecorationWindow(int winId); + + UnityCorners getWindowBorderRadius(int winId); + void setWindowBorderRadius(int winId, const UnityCorners &data); + void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); + void setUKUIDecoraiontHint(int winId, bool set = true); + + void setWindowMotifHint(int winId, const MotifWmHints &hints); + MotifWmHints getWindowMotifHint(int winId); + +private: + explicit XAtomHelper(QObject *parent = nullptr); + + Atom registerUKUICsdNetWmSupportAtom(); + void unregisterUKUICsdNetWmSupportAtom(); + + Atom m_motifWMHintsAtom = None; + Atom m_unityBorderRadiusAtom = None; + Atom m_ukuiDecorationAtion = None; +}; + +#endif // XATOMHELPER_H diff --git a/src/frontend/xatom/xatom.pri b/src/frontend/xatom/xatom.pri new file mode 100644 index 00000000..2d5b1409 --- /dev/null +++ b/src/frontend/xatom/xatom.pri @@ -0,0 +1,7 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/xatom-helper.h \ + +SOURCES += \ + $$PWD/xatom-helper.cpp \ diff --git a/src/kylin-nm.desktop b/src/kylin-nm.desktop new file mode 100644 index 00000000..849c402e --- /dev/null +++ b/src/kylin-nm.desktop @@ -0,0 +1,18 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Kylin NM +Name[zh_CN]=麒麟网络设置工具 +Name[zh_HK]=麒麟網路設置工具 +Name[zh_TW]=麒麟網路設置工具 +Icon=gnome-dev-ethernet +Comment=Beautiful Network Config Applet +Comment[zh_CN]=麒麟网络设置工具,提供查看和简单设置功能,拥有美观的界面和舒适的操作. +Keywords=applet;nm;network;network-manager; +Exec=/usr/bin/kylin-nm +StartupNotify=false +Terminal=false +Type=Application +OnlyShowIn=UKUI +X-UKUI-AutoRestart=true +NoDisplay=true +X-UKUI-Autostart-Phase=Application diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..2454937e --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see +#include +#include "qt-single-application.h" +#include +#include +#include +#include +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +#include "xatom-helper.h" +#endif + +#define LOG_IDENT "ukui_kylin_nm" + +const QString QT_TRANSLATE_FILE = "/usr/share/qt5/translations/qt_zh_CN.qm"; + +void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + QByteArray localMsg = msg.toLocal8Bit(); + QByteArray currentDateTime = QDateTime::currentDateTime().toString().toLocal8Bit(); + + bool showDebug = true; + QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/ukui/kylin-nm.log"; + //若不需要自动创建日志文件,请放开此注释 +// if (!QFile::exists(logFilePath)) { +// showDebug = false; +// } + FILE *log_file = nullptr; + + if (showDebug) { + log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+"); + } + + const char *file = context.file ? context.file : ""; + const char *function = context.function ? context.function : ""; + switch (type) { + case QtDebugMsg: + if (!log_file) { + break; + } + fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtInfoMsg: + fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtWarningMsg: + fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtCriticalMsg: + fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function); + break; + case QtFatalMsg: + fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function); + break; + } + + if (log_file) + fclose(log_file); +} + +int main(int argc, char *argv[]) +{ + initUkuiLog4qt("kylin-nm"); + + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + +// QApplication a(argc, argv); + QString id = QString("kylin-nm"+ QLatin1String(getenv("DISPLAY"))); + QtSingleApplication a(id, argc, argv); + + QApplication::setQuitOnLastWindowClosed(false); + + + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("main", "kylinnm")); + parser.addHelpOption(); + parser.addVersionOption(); + + QCommandLineOption swOption(QStringLiteral("sw"),QCoreApplication::translate("main", "show kylin-nm wifi page")); + QCommandLineOption snOption(QStringLiteral("sn"),QCoreApplication::translate("main", "show kylin-nm lan page")); + + parser.addOptions({swOption,snOption}); + parser.process(a); + + QDBusInterface interface("com.kylin.network", + "/com/kylin/network", + "com.kylin.network", + QDBusConnection::sessionBus()); + if(interface.isValid()) { + if (parser.isSet(swOption)) + { + interface.call(QStringLiteral("showKylinNM"),1); + } else { + interface.call(QStringLiteral("showKylinNM"),0); + } + return 0; + } + + QThread thread; + KyNetworkResourceManager *p_networkResource = KyNetworkResourceManager::getInstance(); + p_networkResource->moveToThread(&thread); + QObject::connect(&thread, SIGNAL(started()), p_networkResource, SLOT(onInitNetwork())); + thread.start(); + + // Internationalization + QString locale = QLocale::system().name(); + QTranslator trans_global; + qDebug() << "QLocale " << QLocale(); + if (trans_global.load(QLocale(), "kylin-nm", "_", ":/translations/")) + { + a.installTranslator(&trans_global); + qDebug()<<"Translations load success"; + } else { + qWarning() << "Translations load fail"; + } + + QTranslator qtBaseTranslator; + if (qtBaseTranslator.load(QLocale(), "qt", "_", "/usr/share/qt5/translations/")) + { + a.installTranslator(&qtBaseTranslator); + qDebug()<<"QtBase Translations load success"; + } else { + qWarning() << "QtBase Translations load fail"; + } + + while (!p_networkResource->NetworkManagerIsInited()) { + ::usleep(1000); + } + + MainWindow w; + a.setActivationWindow(&w); + w.setProperty("useStyleWindowManager", false); //禁用拖动 + a.setWindowIcon(QIcon::fromTheme("kylin-network")); + //设置窗口无边框,阴影 + +// MotifWmHints window_hints; +// window_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; +// window_hints.functions = MWM_FUNC_ALL; +// window_hints.decorations = MWM_DECOR_BORDER; +// XAtomHelper::getInstance()->setWindowMotifHint(w.winId(), window_hints); + +// w.setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint /*| Qt::X11BypassWindowManagerHint*/); + + + DbusAdaptor adaptor(&w); + Q_UNUSED(adaptor); + + auto connection = QDBusConnection::sessionBus(); + if (!connection.registerService("com.kylin.network") || !connection.registerObject("/com/kylin/network", &w)) { + qCritical() << "QDbus register service failed reason:" << connection.lastError(); + } + + return a.exec(); +} diff --git a/src/org.ukui.kylin-nm.switch.gschema.xml b/src/org.ukui.kylin-nm.switch.gschema.xml new file mode 100644 index 00000000..544f2cd0 --- /dev/null +++ b/src/org.ukui.kylin-nm.switch.gschema.xml @@ -0,0 +1,14 @@ + + + + true +

wireless switch + Wireless switch.true is open,false is close. + + + true + wired switch + Wired switch.true is open,false is close. + + + diff --git a/src/singleapplication/qt-local-peer.cpp b/src/singleapplication/qt-local-peer.cpp new file mode 100644 index 00000000..4a62537c --- /dev/null +++ b/src/singleapplication/qt-local-peer.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +** +****************************************************************************/ + + +#include "qt-local-peer.h" +#include +#include +#include + +#if defined(Q_OS_UNIX) +#include +#include +#include +#endif + +namespace QtLP_Private { +#include "qt-locked-file.cpp" +#include "qt-locked-file-unix.cpp" +} + +const char* QtLocalPeer::ack = "ack"; + +QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId) + : QObject(parent), id(appId) { + QString prefix = id; + if(id.isEmpty()) { + id = QCoreApplication::applicationFilePath(); +#if defined(Q_OS_WIN) + id = id.toLower(); +#endif + prefix = id.section(QLatin1Char('/'), -1); //完整路径按‘/’分隔后取最后一个字段 + } + prefix.remove(QRegExp("[^a-zA-Z]")); //去掉名称中的非字母 + prefix.truncate(6); //取前六位 + + QByteArray idc = id.toUtf8(); + quint16 idNum = qChecksum(idc.constData(), idc.size()); + socketName = QLatin1String("qtsingleapp-") + prefix + + QLatin1Char('-') + QString::number(idNum, 16); + +#if defined(Q_OS_WIN) + if(!pProcessIdToSessionId) { + QLibrary lib("kernel32"); + pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId"); + } + if(pProcessIdToSessionId) { + DWORD sessionId = 0; + pProcessIdToSessionId(GetCurrentProcessId(), &sessionId); + socketName += QLatin1Char('-') + QString::number(sessionId, 16); + } +#else + socketName += QLatin1Char('-') + QString::number(::getuid(), 16); +#endif + + server = new QLocalServer(this); + QString lockName = QDir(QDir::tempPath()).absolutePath() + + QLatin1Char('/') + socketName + + QLatin1String("-lockfile"); //tmp目录下的锁文件 + lockFile.setFileName(lockName); + lockFile.open(QIODevice::ReadWrite); +} + + + +bool QtLocalPeer::isClient() { + if(lockFile.isLocked()) + return false; + + if(!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false)) + return true; + + //由于文件锁的存在,仅当本进程第一次启动时能执行到此并使server进行监听和关联槽函数 + bool res = server->listen(socketName); +#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0)) + // ### Workaround + if(!res && server->serverError() == QAbstractSocket::AddressInUseError) { + QFile::remove(QDir::cleanPath(QDir::tempPath()) + QLatin1Char('/') + socketName); + res = server->listen(socketName); + } +#endif + if(!res) + qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString())); + QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection); + return false; +} + + +bool QtLocalPeer::sendMessage(const QString &message, int timeout) { + if(!isClient()) + return false; + + QLocalSocket socket; + bool connOk = false; + for(int i = 0; i < 2; i++) { + // Try twice, in case the other instance is just starting up + socket.connectToServer(socketName); + connOk = socket.waitForConnected(timeout / 2); + if(connOk || i) + break; + int ms = 250; +#if defined(Q_OS_WIN) + Sleep(DWORD(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); +#endif + } + if(!connOk) + return false; + + QByteArray uMsg(message.toUtf8()); + QDataStream ds(&socket); + ds.writeBytes(uMsg.constData(), uMsg.size()); + bool res = socket.waitForBytesWritten(timeout); + if(res) { + res &= socket.waitForReadyRead(timeout); // wait for ack + if(res) + res &= (socket.read(qstrlen(ack)) == ack); + } + return res; +} + +/** + * @brief QtLocalPeer::receiveConnection 当新进程启动时,会尝试连接此进程server,server接收到newConnection信号并触发此槽函数 + */ +void QtLocalPeer::receiveConnection() { + QLocalSocket* socket = server->nextPendingConnection(); //获取新进程的socket + if(!socket) + return; + + while(true) { + if(socket->state() == QLocalSocket::UnconnectedState) { + qWarning("QtLocalPeer: Peer disconnected"); + delete socket; + return; + } + if(socket->bytesAvailable() >= qint64(sizeof(quint32))) + break; + socket->waitForReadyRead(); + } + + QDataStream ds(socket); + QByteArray uMsg; + quint32 remaining; + ds >> remaining; + uMsg.resize(remaining); + int got = 0; + char* uMsgBuf = uMsg.data(); + do { + got = ds.readRawData(uMsgBuf, remaining); + remaining -= got; + uMsgBuf += got; + } while(remaining && got >= 0 && socket->waitForReadyRead(2000)); + if(got < 0) { + qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData()); + delete socket; + return; + } + QString message(QString::fromUtf8(uMsg)); + socket->write(ack, qstrlen(ack)); + socket->waitForBytesWritten(1000); + socket->waitForDisconnected(1000); // make sure client reads ack + delete socket; + Q_EMIT messageReceived(message); //获取新进程的启动信息并作为信号发送给前端 +} diff --git a/src/singleapplication/qt-local-peer.h b/src/singleapplication/qt-local-peer.h new file mode 100644 index 00000000..883aec2a --- /dev/null +++ b/src/singleapplication/qt-local-peer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +** +****************************************************************************/ + +#ifndef QTLOCALPEER_H +#define QTLOCALPEER_H + +#include +#include +#include + +#include "qt-locked-file.h" + +class QtLocalPeer : public QObject { + Q_OBJECT + +public: + QtLocalPeer(QObject *parent = 0, const QString &appId = QString()); + bool isClient(); + bool sendMessage(const QString &message, int timeout); + QString applicationId() const { + return id; + } + +Q_SIGNALS: + void messageReceived(const QString &message); + +protected Q_SLOTS: + void receiveConnection(); + +protected: + QString id; + QString socketName; + QLocalServer* server; + QtLP_Private::QtLockedFile lockFile; + +private: + static const char* ack; +}; + +#endif // QTLOCALPEER_H diff --git a/src/singleapplication/qt-locked-file-unix.cpp b/src/singleapplication/qt-locked-file-unix.cpp new file mode 100644 index 00000000..51472520 --- /dev/null +++ b/src/singleapplication/qt-locked-file-unix.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qt-locked-file.h" + +bool QtLockedFile::lock(LockMode mode, bool block) { + if(!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if(mode == NoLock) + return unlock(); + + if(mode == m_lock_mode) + return true; + + if(m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if(ret == -1) { + if(errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() { + if(!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if(!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if(ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() { + if(isOpen()) + unlock(); +} + diff --git a/src/singleapplication/qt-locked-file.cpp b/src/singleapplication/qt-locked-file.cpp new file mode 100644 index 00000000..707b4cfa --- /dev/null +++ b/src/singleapplication/qt-locked-file.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt-locked-file.h" + +/*! + \class QtLockedFile + + \brief The QtLockedFile class extends QFile with advisory locking + functions. + + A file may be locked in read or write mode. Multiple instances of + \e QtLockedFile, created in multiple processes running on the same + machine, may have a file locked in read mode. Exactly one instance + may have it locked in write mode. A read and a write lock cannot + exist simultaneously on the same file. + + The file locks are advisory. This means that nothing prevents + another process from manipulating a locked file using QFile or + file system functions offered by the OS. Serialization is only + guaranteed if all processes that access the file use + QLockedFile. Also, while holding a lock on a file, a process + must not open the same file again (through any API), or locks + can be unexpectedly lost. + + The lock provided by an instance of \e QtLockedFile is released + whenever the program terminates. This is true even when the + program crashes and no destructors are called. +*/ + +/*! \enum QtLockedFile::LockMode + + This enum describes the available lock modes. + + \value ReadLock A read lock. + \value WriteLock A write lock. + \value NoLock Neither a read lock nor a write lock. +*/ + +/*! + Constructs an unlocked \e QtLockedFile object. This constructor + behaves in the same way as \e QFile::QFile(). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile() + : QFile() { +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Constructs an unlocked QtLockedFile object with file \a name. This + constructor behaves in the same way as \e QFile::QFile(const + QString&). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) { +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Opens the file in OpenMode \a mode. + + This is identical to QFile::open(), with the one exception that the + Truncate mode flag is disallowed. Truncation would conflict with the + advisory file locking, since the file would be modified before the + write lock is obtained. If truncation is required, use resize(0) + after obtaining the write lock. + + Returns true if successful; otherwise false. + + \sa QFile::open(), QFile::resize() +*/ +bool QtLockedFile::open(OpenMode mode) { + if(mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + +/*! + Returns \e true if this object has a in read or write lock; + otherwise returns \e false. + + \sa lockMode() +*/ +bool QtLockedFile::isLocked() const { + return m_lock_mode != NoLock; +} + +/*! + Returns the type of lock currently held by this object, or \e + QtLockedFile::NoLock. + + \sa isLocked() +*/ +QtLockedFile::LockMode QtLockedFile::lockMode() const { + return m_lock_mode; +} + +/*! + \fn bool QtLockedFile::lock(LockMode mode, bool block = true) + + Obtains a lock of type \a mode. The file must be opened before it + can be locked. + + If \a block is true, this function will block until the lock is + aquired. If \a block is false, this function returns \e false + immediately if the lock cannot be aquired. + + If this object already has a lock of type \a mode, this function + returns \e true immediately. If this object has a lock of a + different type than \a mode, the lock is first released and then a + new lock is obtained. + + This function returns \e true if, after it executes, the file is + locked by this object, and \e false otherwise. + + \sa unlock(), isLocked(), lockMode() +*/ + +/*! + \fn bool QtLockedFile::unlock() + + Releases a lock. + + If the object has no lock, this function returns immediately. + + This function returns \e true if, after it executes, the file is + not locked by this object, and \e false otherwise. + + \sa lock(), isLocked(), lockMode() +*/ + +/*! + \fn QtLockedFile::~QtLockedFile() + + Destroys the \e QtLockedFile object. If any locks were held, they + are released. +*/ diff --git a/src/singleapplication/qt-locked-file.h b/src/singleapplication/qt-locked-file.h new file mode 100644 index 00000000..332d648e --- /dev/null +++ b/src/singleapplication/qt-locked-file.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_OS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +namespace QtLP_Private { + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile { +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; +} +#endif diff --git a/src/singleapplication/qt-single-application.cpp b/src/singleapplication/qt-single-application.cpp new file mode 100644 index 00000000..b924430c --- /dev/null +++ b/src/singleapplication/qt-single-application.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +** +****************************************************************************/ + + +#include "qt-single-application.h" +#include "qt-local-peer.h" +#include +#include +#include +#include +#include +#include +#include "../mainwindow.h" + + +/*! + \class QtSingleApplication qtsingleapplication.h + \brief The QtSingleApplication class provides an API to detect and + communicate with running instances of an application. + + This class allows you to create applications where only one + instance should be running at a time. I.e., if the user tries to + launch another instance, the already running instance will be + activated instead. Another usecase is a client-server system, + where the first started instance will assume the role of server, + and the later instances will act as clients of that server. + + By default, the full path of the executable file is used to + determine whether two processes are instances of the same + application. You can also provide an explicit identifier string + that will be compared instead. + + The application should create the QtSingleApplication object early + in the startup phase, and call isRunning() to find out if another + instance of this application is already running. If isRunning() + returns false, it means that no other instance is running, and + this instance has assumed the role as the running instance. In + this case, the application should continue with the initialization + of the application user interface before entering the event loop + with exec(), as normal. + + The messageReceived() signal will be emitted when the running + application receives messages from another instance of the same + application. When a message is received it might be helpful to the + user to raise the application so that it becomes visible. To + facilitate this, QtSingleApplication provides the + setActivationWindow() function and the activateWindow() slot. + + If isRunning() returns true, another instance is already + running. It may be alerted to the fact that another instance has + started by using the sendMessage() function. Also data such as + startup parameters (e.g. the name of the file the user wanted this + new instance to open) can be passed to the running instance with + this function. Then, the application should terminate (or enter + client mode). + + If isRunning() returns true, but sendMessage() fails, that is an + indication that the running instance is frozen. + + Here's an example that shows how to convert an existing + application to use QtSingleApplication. It is very simple and does + not make use of all QtSingleApplication's functionality (see the + examples for that). + + \code + // Original + int main(int argc, char **argv) + { + QApplication app(argc, argv); + + MyMainWidget mmw; + mmw.show(); + return app.exec(); + } + + // Single instance + int main(int argc, char **argv) + { + QtSingleApplication app(argc, argv); + + if (app.isRunning()) + return !app.sendMessage(someDataString); + + MyMainWidget mmw; + app.setActivationWindow(&mmw); + mmw.show(); + return app.exec(); + } + \endcode + + Once this QtSingleApplication instance is destroyed (normally when + the process exits or crashes), when the user next attempts to run the + application this instance will not, of course, be encountered. The + next instance to call isRunning() or sendMessage() will assume the + role as the new running instance. + + For console (non-GUI) applications, QtSingleCoreApplication may be + used instead of this class, to avoid the dependency on the QtGui + library. + + \sa QtSingleCoreApplication +*/ + + +void QtSingleApplication::sysInit(const QString &appId) { + m_activateWindow = 0; + m_peer = new QtLocalPeer(this, appId); + connect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived); +} + + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a GUIenabled are passed on to the QAppliation constructor. + + If you are creating a console application (i.e. setting \a + GUIenabled to false), you may consider using + QtSingleCoreApplication instead. +*/ + +QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled) + : QApplication(argc, argv, GUIenabled) { + sysInit(); +} + + +/*! + Creates a QtSingleApplication object with the application + identifier \a appId. \a argc and \a argv are passed on to the + QAppliation constructor. +*/ + +QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv) + : QApplication(argc, argv) { + sysInit(appId); +} + +#if QT_VERSION < 0x050000 + +/*! + Creates a QtSingleApplication object. The application identifier + will be QCoreApplication::applicationFilePath(). \a argc, \a + argv, and \a type are passed on to the QAppliation constructor. +*/ +QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type) + : QApplication(argc, argv, type) { + sysInit(); +} + + +# if defined(Q_WS_X11) +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a visual, + and \a cmap are passed on to the QApplication constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, visual, cmap) { + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) { + sysInit(); +} + +/*! + Special constructor for X11, ref. the documentation of + QApplication's corresponding constructor. The application identifier + will be \a appId. \a dpy, \a argc, \a + argv, \a visual, and \a cmap are passed on to the QApplication + constructor. +*/ +QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap) + : QApplication(dpy, argc, argv, visual, cmap) { + sysInit(appId); +} +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + +/*! + Returns true if another instance of this application is running; + otherwise false. + + This function does not find instances of this application that are + being run by a different user (on Windows: that are running in + another session). + + \sa sendMessage() +*/ + +bool QtSingleApplication::isRunning() { + return m_peer->isClient(); +} + + +/*! + Tries to send the text \a message to the currently running + instance. The QtSingleApplication object in the running instance + will emit the messageReceived() signal when it receives the + message. + + This function returns true if the message has been sent to, and + processed by, the current instance. If there is no instance + currently running, or if the running instance fails to process the + message within \a timeout milliseconds, this function return false. + + \sa isRunning(), messageReceived() +*/ +bool QtSingleApplication::sendMessage(const QString &message, int timeout) { + return m_peer->sendMessage(message, timeout); +} + + +/*! + Returns the application identifier. Two processes with the same + identifier will be regarded as instances of the same application. +*/ +QString QtSingleApplication::id() const { + return m_peer->applicationId(); +} + + +/*! + Sets the activation window of this application to \a aw. The + activation window is the widget that will be activated by + activateWindow(). This is typically the application's main window. + + If \a activateOnMessage is true (the default), the window will be + activated automatically every time a message is received, just prior + to the messageReceived() signal being emitted. + + \sa activateWindow(), messageReceived() +*/ + +void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) { + m_activateWindow = aw; + if (activateOnMessage) + connect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); + else + disconnect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow); +} + + +/*! + Returns the applications activation window if one has been set by + calling setActivationWindow(), otherwise returns 0. + + \sa setActivationWindow() +*/ +QWidget* QtSingleApplication::activationWindow() const { + return m_activateWindow; +} + + +/*! + De-minimizes, raises, and activates this application's activation window. + This function does nothing if no activation window has been set. + + This is a convenience function to show the user that this + application instance has been activated when he has tried to start + another instance. + + This function should typically be called in response to the + messageReceived() signal. By default, that will happen + automatically, if an activation window has been set. + + \sa setActivationWindow(), messageReceived(), initialize() +*/ +void QtSingleApplication::activateWindow() { + if (m_activateWindow) { + if(this->applicationState() & Qt::ApplicationInactive) + { + MainWindow* w=qobject_cast(m_activateWindow); + w->showMainwindow(); + m_activateWindow->setWindowState(m_activateWindow->windowState() & ~Qt::WindowMinimized); + m_activateWindow->raise(); + m_activateWindow->showNormal(); + m_activateWindow->activateWindow(); + } + else { + m_activateWindow->setWindowState(m_activateWindow->windowState() & Qt::WindowMinimized); + m_activateWindow->hide(); + } + } +} + + +/*! + \fn void QtSingleApplication::messageReceived(const QString& message) + + This signal is emitted when the current instance receives a \a + message from another instance of this application. + + \sa sendMessage(), setActivationWindow(), activateWindow() +*/ + + +/*! + \fn void QtSingleApplication::initialize(bool dummy = true) + + \obsolete +*/ diff --git a/src/singleapplication/qt-single-application.h b/src/singleapplication/qt-single-application.h new file mode 100644 index 00000000..084b9b7c --- /dev/null +++ b/src/singleapplication/qt-single-application.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) +** 2020 KylinSoft Co., Ltd. +** Contact: http://www.qt-project.org/legal +** +** +** This file is part of the Qt Solutions component. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +** +****************************************************************************/ + +#ifndef QTSINGLEAPPLICATION_H +#define QTSINGLEAPPLICATION_H + +#include + +class QtLocalPeer; + +#if defined(Q_OS_WIN) +# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT) +# define QT_QTSINGLEAPPLICATION_EXPORT +# elif defined(QT_QTSINGLEAPPLICATION_IMPORT) +# if defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# endif +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport) +# elif defined(QT_QTSINGLEAPPLICATION_EXPORT) +# undef QT_QTSINGLEAPPLICATION_EXPORT +# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTSINGLEAPPLICATION_EXPORT +#endif + +class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication { + Q_OBJECT + +public: + QtSingleApplication(int &argc, char **argv, bool GUIenabled = true); + QtSingleApplication(const QString &id, int &argc, char **argv); +#if QT_VERSION < 0x050000 + QtSingleApplication(int &argc, char **argv, Type type); +# if defined(Q_WS_X11) + QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); + QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0); + QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0); +# endif // Q_WS_X11 +#endif // QT_VERSION < 0x050000 + + bool isRunning(); + QString id() const; + + void setActivationWindow(QWidget* aw, bool activateOnMessage = true); + QWidget* activationWindow() const; + + // Obsolete: + void initialize(bool dummy = true) { + isRunning(); + Q_UNUSED(dummy) + } + +public Q_SLOTS: + bool sendMessage(const QString &message, int timeout = 5000); + void activateWindow(); + + +Q_SIGNALS: + void messageReceived(const QString &message); + + +private: + void sysInit(const QString &appId = QString()); + QtLocalPeer *m_peer; + QWidget *m_activateWindow; +}; + +#endif // QTSINGLEAPPLICATION_H diff --git a/src/singleapplication/qt-single-application.pri b/src/singleapplication/qt-single-application.pri new file mode 100644 index 00000000..0a4ca9ae --- /dev/null +++ b/src/singleapplication/qt-single-application.pri @@ -0,0 +1,27 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +QT *= network +greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets + +qtsingleapplication-uselib:!qtsingleapplication-buildlib { + LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME +} else { + SOURCES += + HEADERS += +} + +win32 { + contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT + else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT +} + +HEADERS += \ + $$PWD/qt-local-peer.h \ + $$PWD/qt-locked-file.h \ + $$PWD/qt-single-application.h + +SOURCES += \ + $$PWD/qt-local-peer.cpp \ + $$PWD/qt-locked-file-unix.cpp \ + $$PWD/qt-single-application.cpp \ + $$PWD/qt-locked-file.cpp diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 00000000..f3cf18c7 --- /dev/null +++ b/src/src.pro @@ -0,0 +1,69 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2018-10-19T15:29:47 +# +#------------------------------------------------- + +QT += core gui x11extras dbus KWindowSystem svg concurrent network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = kylin-nm +TEMPLATE = app + +CONFIG += c++14 qt warn_on link_pkgconfig no_keywords +#CONFIG += release + +PKGCONFIG +=gio-2.0 glib-2.0 gio-unix-2.0 libnm libnma libsecret-1 gtk+-3.0 gsettings-qt libcap kysdk-qtwidgets kysdk-waylandhelper +PKGCONFIG +=kysdk-sysinfo + +INCLUDEPATH += /usr/include/KF5/NetworkManagerQt + +LIBS += -L/usr/lib/ -lgsettings-qt -lX11 -lKF5NetworkManagerQt -lukui-log4qt -lkysec + +target.path = /usr/bin +target.source += $$TARGET +desktop.path = /etc/xdg/autostart/ +desktop.files = kylin-nm.desktop +gschema.files = org.ukui.kylin-nm.switch.gschema.xml +gschema.path = /usr/share/glib-2.0/schemas/ + +INSTALLS += target \ + desktop \ + gschema \ + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS WITHKYSEC + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +# QMAKE_CXXFLAGS += -Wno-unused-parameter +QMAKE_CPPFLAGS *= $(shell dpkg-buildflags --get CPPFLAGS) +QMAKE_CFLAGS *= $(shell dpkg-buildflags --get CFLAGS) +QMAKE_CXXFLAGS *= $(shell dpkg-buildflags --get CXXFLAGS) +QMAKE_LFLAGS *= $(shell dpkg-buildflags --get LDFLAGS) + +include(singleapplication/qt-single-application.pri) +include(backend/backend.pri) +include(frontend/frontend.pri) + +RESOURCES += \ + ../nmqrc.qrc + +SOURCES += \ + main.cpp + +unix { + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj +} + +DISTFILES += \ + org.ukui.kylin-nm.switch.gschema.xml diff --git a/src/translations/kylin-nm_bo.qm b/src/translations/kylin-nm_bo.qm new file mode 100644 index 00000000..be651eed --- /dev/null +++ b/src/translations/kylin-nm_bo.qm @@ -0,0 +1 @@ +O30c@imYnTQm%qwf4zcwA$V7 zt}IK04w=vyngW4lOhX~96AYy^Lw{h}q$PwVaf>18G=(q&v@;}NduV8#Caq_RG3|Hm z*}eOA_uc)GSD^!p{K@Ng&bjy8bH8)%-Fx1)Z+RBKa`Ew#KUz`$-8;VioqydWMCm^X zQGBZqMdOS++lBb-Ss}Lmr6_vjX(5~si=sCk5TgGc#(`l`e7F~KuQ68kGS-}9TzVVh z@?DH;8yK5hjGJ#@?6{tB`(DPKrHuU_h~oR66k>0kDE{ghwCiC}{L<}0^!`#bFS=WZ zJ?+AC@naztl!)LvZv%V83;xYQ>|Q2bJ^f$k!?zeevy$UUa%JE{`&nUtz5Nm~ru0#)jJ&SFdH<_#|WNA;zt>jN8kL&JICe_nG3l4WC22 zKg~GsKgAulejai5v*Ll((-@D(i}yWJf#*&YAAS{nt~_4+;^`+aUN4lC{QY-?=ol&~ zt#3oSt}t%@^O8Fr{0hcxwB)X5Fb)+@FfQ4{xW-ZPek=O7Z+oe;@--n`BaGKP&uF+9 z*ZwO$6+$+S6fa95W5f_zz%Xm#44Rmb>VF}`b>9R2rx5j`>}>acL*FUJYpyU}H_d1qW^8O{ z+&XP-vB^>yPicnH9PNp<4-aFh4akw@Xw|d&L92VO&HHFIzM=*2=VoW^37Ymgnm9$-th{a zD%@2*`aSSo-NWVg|MU)gu&?~f-&_O!+so*Dow4d|#$`7$UjKE*4I3F-IvCq7Gj={( z{si%E)A{n3_y0hMoxdo5^=rrnZP!*jb!ZCqe$2S?JmdOs#h={_e-~C(Joo0W;HQ&} z+ZHf(y}{VmS@DxT=xJ`QT=P^d+WYOw9lht!Z)fGB^#>vUUgcvS9ztA|FxH%AT=ER# z@&$}*CKxx}#@PBR#;xZWcf4GA=4G_IaJKTwUH5{wRxw_GBjfrru0^N5EyTi`8EgN7 zafO4i@!uG?bTQu8=NedcJ9za9W9RLz3HrO^ZpNx+#zhY^)<49!;ymNJR~VZwFt**| zn*GdDAqMVp&E87*H?DtJ_&eZ*n;2`l7#mJ8u6~lS^(%~9hh67Be^Q8^N!Q0eMV$7$ zx6u2?tKdi9!k<^3M!x#KSBU-9h465L7!Yo8RQN;yKU2aGT?NbWXRnyR-%SS|5heJk z?(%qy5pT%!7=vbHIuM#D#ix$$fPZXvAT(J(x?G}5ctl8;A}l(Ep=8S-8#2S;P9s&O zMjQ|k*lrX(qEB>-A+b)$IlHDJfySP`?xA(5g5xO-pFl@KP-e)kOyX}I{P^+r88pc+ zy!eftv3AxiJ1e_ha0Ieb&@hFLyTxQd3*-VKq?)s}+wC{}frv30GTjl=@SD@dwDgFd zJz|UnLii*y9+-+m|7Fx2@}#!iSygqbeMJg%X&TDh=Jkur?#+;Vg~Ng$yP{N`>^?6 z{HJ_Swg-NlcF))~u}17ecn!h`#udh_0p{G-HE8(Vlct@Z1F`H&h~<*~ZvT|q#?@8g zH^e1GN(9}XOt9eCZ(>+IcKU13C=((SaA5?PwP9uG^rSmHVJFuLW3jO0Fr0-3GEE_y z8j>C{r5ttLAYv~Tb#5Qx(K8bbOPg@pm14<_(5A^kfgX}0XSGd%Nxhkr|L!MuE6b~` zmcwQw;`JX38?h#gdHvq-xM|Y{r#KkXs&p+lU_&Ama$e71?!u|+(V}7ZaWh@yd2FM$ z!lbB;Ix1DXLF@r5%%Ypb4I?VTlF4r&kzb$J<1zil2x5&imG}6L;UjazJLZ+_R|_Ts zgDM(n!fa|%9dLFZk*x8vd!DkD&Oiw%*6y>=Ul^1%D-2lniZRK*M0T^XQ^(;(8fz={ zMW2^s$b>l|Nspqzk7yt~3Tbi+#fTTo;EfV!07%h8&&=Rizv^Kdr7{jVqDQ$=RlvGGYHKp?;Vyr`KQkGak`bztU22s@yC%>+qGj|;X{u404DgXZ67{xD zWgRkn05dwa(DBn!r{IWESBX{EIH?&$GL}rP(`0~yRCCa{M7)iIWe)W9T^B&Cstug09IDfNzNm==uFmF8!OqhQ+YXw zWppZN-A+@6Rtr4YMzG!*!jLtJ4$&-Hkp)}C3CpU!wr2)QHB6$B-XWv0qq()Ia~l^cOX60C?WSrrfJTBv1Qoj{$U zBoBxoEHg9`n{vK`2xiRdleDc(c^J~<8v6b|hL z)$q6tMSqX)#A=5^fe5l9c7MHH7_}k%nRd+Tu-y9yVPT?eyt+Dw)zz@-V8y{H43Q7| z4(=OH*V3hEDQ(DPrbatQWm^-+$#E!bhG_YpPSHlBEDp>T1Z9WVB$qg}TO==r@qbW^ z!zJ{4oNMYRNLyMvHXX$}k~|w654po>4eeHjwjlm*K=db?8-P=0V75^b-3j~_U!!$l zpVuw=@qgU+E2s%uns11;V!)g+8vD!>w5aMD?(XkTI}r7{OigP#H5{qAS{HP>lx<>q zTK9``$(%lA?=#&&nX*@A$|IJkojH>zwO5k{l#-(1Hzw~>ezI)RlN_W3a!vqBQkMX* zIYiL&>hh@Erpw8o8kNQBQrFnICjiyz`AY!G1kRP>>}-jJO#G}AWXsP=z-6UYi^X*0 zs)Xl@T$O>VC0C`WUQe#pPN$()rE0$ERT=t!L9ePc4e99B;=_ytYtd+bCNT$s9f}cb zy?z&AX=8T#2&FW?tgX~mCGX!9&y`^l!TT?pJg?*%kU+bTRFTDz&1nZXCKsm2>tNCN z8qw9=WsI7k2##-PqmxeMdaX+9nG0=H;_9zWRIiRg(%H#v%b|L_k~UuGFCFv5PQ0o2 z7tkO-9YR@-p{lya1A(wJ+A%p}h-W78+pL;*%LW5RQZ#$RM#%il zDf;pwT|j4>cU2P?Bk#ucAz^GFLim})PkbyYXzO7dH$!yrlFs&AQn+fze5G(@;OaB4 zQsu&)A?7JVG^=4NJIqcpn$x?a6bxVWra-Bj=S_jK zlT)5aTAnH;84`_7Y)#so1$|qV`|d)uDRUarHESO8n9gJliA<*=_uYkZRUVU|u66Ub zflu>g z9_-)L4GQ{R#ys}Y>X^sBL$L-y5Z$Rhb_C9RiS;s;TVe#>1Ot!$P@b{hHlOL!WC z+I**ZK5rRIqd(__rO~s|_KU7e1XM*|d?kNLps}zm2MhXd4VENZO!(eFW4hheG~Il6 z<3Y;!`=*ryvOPC zJj|uBV$F^T_X{&-M@_SJ$4eg_dJQ^)+2ixxiLKhD=~9lbN$^#paQ*ZS7@! zchy!pyWP$$mMb#aD`mF&v%KtOE2||)+o!X*p=B$V^Q9+SEqPyA+gkZ#mesaRvEE8f zSW{ar%cicUZB^Cc+E$~iK^Oz2(FL@KCElDZjUIE%J>`qYyH_p?L5!Gur|D`4$4=i> z9*o(k%!$J66l7p9JCV!;W+yd|{AFh@hvlZ7cy|1i)s>jSgw~=&dn@gzZ>b6^4P;D$f5JU;h@Ju*jPU_maO5VMa6($8oaAkvQ zG*Fjl+iU0WxSNU+({w)XJZRVNPlg8VT2iC#pVBP`Dx*4~{9i_QNxgoLc|zxX>&h#E zLo=?t?AnqO3!<9JT40r+FX)yB5_6}lsDfN5D=PA7s}=#n`%%yTx@bRY zZmzT+70-?)qYr0wPHg8%n%zl-u$I|vE!wh^*4_rkrJwjtEp?4#rz^u$s-i_vAQBD+ zBHgm`QBL4BxZV?yl^j%MHHhn06LN=YBoZ-yBghniX*q69 zmaq%bi2_EB5;NT#qmogo(6ZFysPS8hT18D!D2-*ZnNJhfCiksFhW@zx2AT?EsPrVa z;?_k}_-XW_s40Y!X2Vk8nrtiIoSv*dwdGU`Nbh~1s$q|%vZSKN8y@A7TKmYVg<#@4 z8E|H*;>Qu|tzEP<*m#r|Lr}WgH?u$Bk#~Xv7^Ox)B~=P`8wO9N^f94TC8$O_;NO_?5K*F~z+WbZ zxN0ibk5;TFH>X{O-x1IV)h*kM0zQqu41$*OiFL(vFZ2KfW8!;3jN#F7lWVb(Ep})u z#tPE;v^CJW`W5)I*v>v8XLTgPK#Y?>29Xl4eSE84H#EWdHv(XZE z%sqPl3D(gDdT;o=;nb1CpwuPIZhoVJ^-T(ugY+tqbW@`-y62%1HL9;3#h>(cl^OKL zKpb9*?z7^B$_t0bQKuZ|Zo6P{#Hd^aNm1;b2Fc@97kd=u>?Rg36rux=I;r4+hs@H=dH1d|Q%HD`NcOZeS37+WKg#e`Yun3(Z- z{hR!9JDcpkPg6Q8Kj1eh|ERb9~i}(BVJEr+@fh8)~_l)vkRXDkvR`(f|fKxn(*9Wl=%+f;>Q+rl`41m#aY(NAEo_6 z$G7PE7ZYz!E8eaXpJPBJ^ng|bZV^P-^C2C*mnkF*Xp+|oRa8SlTY+O!A-q8&`sNZ) zN`k)KAaXkRql2qh8lJ)@$7H(Z6v`w{W$R)5d?ZugM|hfQR_K#EEepR@lAL4j|1sRb epbz}+F~bv)K+u@P+hN?t + + + + ConfigPage + + + Network profile type + + + + + Public(recommended) Devices on the network cannot discover this computer. Generally, it is suitable for networks in public places, such as airports or coffee shops, etc. + + + + + Devices on the network can discover this computer. Generally applicable to a network at home or work where you know and trust the individuals and devices on the network. + + + + + Config firewall and security settings + + + + + CreatNetPage + + + Connection Name + + + + + Ipv4Config + + + + + Address + + + + + Netmask + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + + + + + Manual + + + + + DetailPage + + + Auto Connection + + + + + + SSID: + + + + + Copied successfully! + + + + + Copy all + + + + + Please input SSID: + + + + + + Protocol: + + + + + + Security Type: + + + + + + Hz: + + + + + + Chan: + + + + + + BandWidth: + + + + + + IPV6: + + + + + + IPV4: + + + + + + IPV4 Dns: + + + + + + Mac: + + + + + EnterpriseWlanDialog + + + Wi-Fi network requires authentication + + + + + Access to Wi-Fi network " + + + + + " requires a password or encryption key. + + + + + Cancel + + + + + Connect + + + + + FirewallDialog + + + Allow other devices on this network to discover this computer? + + + + + It is not recommended to enable this feature on public networks + + + + + Not allowed (recommended) + + + + + Allowed + + + + + Ipv4Page + + + Ipv4Config + + + + + Address + + + + + Netmask + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + + + + + Manual + + + + + Invalid address + + + + + Invalid subnet mask + + + + + + Required + + + + + Address conflict + + + + + Ipv6Page + + + Ipv6Config + + + + + Address + + + + + Subnet prefix Length + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + + + + + Manual + + + + + + + Required + + + + + Invalid address + + + + + Invalid gateway + + + + + Address conflict + + + + + JoinHiddenWiFiPage + + + Please enter the network name and security type + + + + + Network name(SSID) + + + + + Show Network List + + + + + Cancel + + + + + Join + + + + + Required + + + + + Find and Join Wi-Fi + + + + + LanListItem + + + Not connected + + + + + Wired Device not carried + + + + + + Disconnect + + + + + + Connect + + + + + LanPage + + + No ethernet device avaliable + + + + + LAN + + + + + Activated LAN + + + + + Inactivated LAN + + + + + Wired Device not carried + + + + + ListItem + + + Kylin NM + + + + + kylin network applet desktop message + + + + + MainWindow + + + kylin-nm + + + + + LAN + + + + + WLAN + + + + + Settings + + + + + Network tool + + + + + Show MainWindow + + + + + NetDetail + + + Kylin NM + + + + + kylin network desktop message + + + + + Detail + + + + + Ipv4 + + + + + Ipv6 + + + + + Security + + + + + + Config + + + + + Confirm + + + + + Cancel + + + + + Forget this network + + + + + Add Lan Connect + + + + + connect hiddin wlan + + + + + + + None + + + + + + + Auto + + + + + start check ipv4 address conflict + + + + + start check ipv6 address conflict + + + + + this wifi no support enterprise type + + + + + this wifi no support None type + + + + + this wifi no support WPA2 type + + + + + this wifi no support WPA3 type + + + + + OneConnForm + + + Form + + + + + OneLancForm + + + Form + + + + + SecurityPage + + + Remember the Network + + + + + Security + + + + + + Password + + + + + EAP type + + + + + Identity + + + + + Domain + + + + + CA certficate + + + + + no need for CA certificate + + + + + User certificate + + + + + User private key + + + + + User key password + + + + + Password options + + + + + + + Required + + + + + Ineer authentication + + + + + Usename + + + + + Ask pwd each query + + + + + + + + + + + + + None + + + + + WPA&WPA2 Personal + + + + + WPA&WPA2 Enterprise + + + + + WPA3 Personal + + + + + + + Choose from file... + + + + + Store passwords only for this user + + + + + Store password only for this user + + + + + Store passwords for all users + + + + + Store password for all users + + + + + Ask this password every time + + + + + Ask password every time + + + + + + + Choose a CA certificate + + + + + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + + + + + + + + TabPage + + + Current Device + + + + + Devices Closed! + + + + + Settings + + + + + Kylin NM + + + + + kylin network applet desktop message + + + + + VpnPage + + + Activated VPN + + + + + Inactivated VPN + + + + + Wired Device not carried + + + + + WiFiConfigDialog + + + Dialog + + + + + WLAN Authentication + + + + + Input WLAN Information Please + + + + + WLAN ID: + + + + + WLAN Name: + + + + + Password: + + + + + Cancl + + + + + Ok + + + + + WlanListItem + + + Not connected + + + + + + Disconnect + + + + + + + Connect + + + + + + Forget + + + + + Auto Connect + + + + + WlanMoreItem + + + Add Others... + + + + + WlanPage + + + WLAN + + + + + Activated WLAN + + + + + Other WLAN + + + + + No wireless network card detected + + + + + WLAN Connected Successfully + + + + + WLAN Disconnected Successfully + + + + + main + + + kylinnm + + + + + show kylin-nm wifi page + + + + + show kylin-nm lan page + + + + + vpnMainWindow + + + kylin-vpn + + + + + vpn tool + + + + diff --git a/translations/kylin-nm_bo_CN.qm b/translations/kylin-nm_bo_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..a3eabea1a8c61c447bad0423953b51271000ce79 GIT binary patch literal 17666 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 UGHw- + + + + ConfForm + + Manual + 手动 + + + Cancel + 取消 + + + kylin-nm + 网络工具 + + + kylin network applet desktop message + 网络提示消息 + + + Will check the IP address conflict + 正在检测ip地址冲突 + + + IPv4 address conflict, Please change IP + ip地址冲突,请更改ip + + + IPv6 address conflict, Please change IP + ip地址冲突,请更改ip {6 ?} + + + + ConfigPage + + + Network profile type + དྲ་རྒྱའི་བཀོད་སྒྲིག་ཡིག་ཆའི་རིགས། + + + + Public(recommended) Devices on the network cannot discover this computer. Generally, it is suitable for networks in public places, such as airports or coffee shops, etc. + སྤྱི་སྤྱོད།(འོས་སྦྱོར་བྱས་པ།)དྲ་རྒྱའི་སྒྲིག་ཆས་ཀྱིས་གློག་ཀླད་འདི་མཐོང་མི་ཐུབ། སྤྱིར་བཏང་གི་གནས་ཚུལ་འོག་ཏུ་མི་མང་འདུ་སའི་ནང་གི་དྲ་བ་ལ་འཚམ་པ་སྟེ།དཔེར་ན་གནམ་གྲུ་ཐང་དང་འཚིག་ཇའི་ཁང་སོགས་ལྟ་བུ།. + + + + Devices on the network can discover this computer. Generally applicable to a network at home or work where you know and trust the individuals and devices on the network. + ཆེད་སྤྱོད། དྲ་རྒྱའི་སྒྲིག་ཆས་ཀྱིས་གློག་ཀླད་འདི་མཐོང་ཐུབ། སྤྱིར་བཏང་གི་གནས་ཚུལ་འོག་ཁྱིམ་ཚང་ངམ་ལས་དོན་ཚན་པའི་དྲ་བ་དང་འཚམ་པས།ཁྱེད་ཀྱིས་དྲ་ཐོག་གི་མི་སྒེར་དང་སྒྲིག་ཆས་ལ་ངོས་འཛིན་དང་ཡིད་ཆེས་བྱེད་དགོས།. + + + Public(recommended) Your device can not be discovered on the network. In most cases, use this feature when connected to a network at home, work, or a public location. + སྤྱི་སྤྱོད་(འོས་སྦྱོར་)དྲ་རྒྱའི་ཐོག་ནས་ཁྱོད་ཀྱི་སྒྲིག་ཆས་རྙེད་མི་ཐུབ། གནས་ཚུལ་མང་ཆེ་བའི་འོག་ཏུ་ཁྱིམ་ཚང་དང་བྱ་བ་འམ་ཡང་ན་སྤྱི་པའི་གོ་གནས་སུ་དྲ་རྒྱའི་དུས་སུ་ནུས་པ་འདི་བཀོལ་སྤྱོད་བྱེད་དགོས།. + + + Private Your device can be discovered on the network. Select this if you require file sharing or use applications that communicate over this network. You should know and trust the people and devices on the network. + ཆེད་སྤྱོད་དྲ་རྒྱའི་སྟེང་ནས་ཁྱོད་ཀྱི་སྒྲིག་ཆས་རྙེད་ཐུབ། གལ་ཏེ་ཡིག་ཆ་མཉམ་སྤྱོད་བྱེད་དགོས་པའམ་ཡང་ན་དྲ་རྒྱའི་འཕྲིན་གཏོང་བཀོལ་སྤྱོད་བྱེད་པར་བརྟེན་ནས་རྣམ་གྲངས་འདི་འདེམས་རོགས་གནང། ཁྱོད་ཀྱིས་དྲ་རྒྱའི་སྟེང་གི་མི་སྣ་དང་སྒྲིག་ཆས་ལ་རྒྱུས་ལོན་དང་ཡིད་ཆེས་བྱེད་དགོས།. + + + + Config firewall and security settings + མེ་འགོག་གྱང་རྩིག་དང་བདེ་འཇགས་བཀོད་སྒྲིག་བྱ་དགོས། + + + + CopyButton + + Copied successfully + 复制成功 + + + Copied successfully! + 复制成功! + + + Copy all + 复制全部 + + + + CreatNetPage + + + Connection Name + འབྲེལ་མཐུད་ཀྱི་མིང་། + + + + IPv4Config + IPv4ཁུང་ཙི། + + + + Address + སྡོད་གནས། + + + + Netmask + དྲ་རྒྱའི་མ་ལག + + + + Default Gateway + ཁ་ཆད་བཞག་པའི་སྒོ་ཆེན། + + + + Prefs DNS + སྔོན་གྲབས་DNS + + + + Alternative DNS + ཚབ་བྱེད་རང་བཞིན་གྱི་DNS + + + + Auto(DHCP) + རང་འགུལ་(DHCP) + + + + Manual + ལག་དེབ། + + + + DetailPage + + + Auto Connection + རང་འགུལ་གྱིས་འབྲེལ་མཐུད་བྱེད + + + + + SSID: + SSID: + + + + Copied successfully! + འདྲ་བཟོ་བྱས་ནས་གྲུབ་འབྲས་ཐོབ་! + + + + Copy all + ཚང་མ་འདྲ་བཤུས་བྱེད་ + + + + Please input SSID: + SSID:ནང་འཇུག་གནང་རོགས།: + + + + + Protocol: + གྲོས་ཆོད་ནང་དུ།: + + + + + Security Type: + བདེ་འཇགས་ཀྱི་རིགས་དབྱིབས་ནི།: + + + + + Hz: + དྲ་རྒྱའི་འཕྲིན་ལམ།: + + + + + Chan: + དྲ་བའི་བགྲོད་ལམ།: + + + + + BandWidth: + ཞེང་ཆེ་བ།: + + + + + IPv6: + IPv6: + + + + + IPv4: + IPv4: + + + + + IPv4 Dns: + IPv4 Dns: + + + + + Mac: + ཨའོ་མོན་ནི།: + + + + DlgHideWifi + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapFast + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapLeap + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapPeap + + Domain + + + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapPwd + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapTTLS + + Domain + + + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapTls + + Identity + 匿名身份 + + + Domain + + + + User certificate + 用户证书 + + + User private key + 用户私钥 + + + User key password + 用户密钥密码 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiLeap + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiWep + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiWpa + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + EnterpriseWlanDialog + + Connect Enterprise WLAN + ཁེ་ལས་WLANས སྦྲེལ་མཐུད་བྱེད་པ། + + + Close + 关闭 + + + + Wi-Fi network requires authentication + Wi-Fiཡི་དྲ་རྒྱའི་བླང་བྱར་སྤྲོད་བྱ་རྒྱུའི་བླང་བྱ་བཏོན་ཡོད། + + + + Access to Wi-Fi network " + Wii-Fiབར་གྱི་དྲ་རྒྱར་འཚམས་འདྲི་གནང་བ་རེད། + + + + " requires a password or encryption key. + གསང་གྲངས་དང་གསང་བའི་ལྡེ་མིག་དགོས། + + + + Cancel + ཕྱིར་འཐེན། + + + + Connect + སྦྲེལ་མཐུད་བྱེད་པ + + + + FirewallDialog + + Allow your computer to be discovered by other computers and devices on this network? + ཁྱོད་ཀྱི་གློག་ཀླད་དེ་དྲ་རྒྱའི་སྟེང་གི་གློག་ཀླད་དང་སྒྲིག་ཆས་གཞན་དག་གིས་རྙེད་ཐུབ་བམ།? + + + It is recommended that you enable this feature on your home and work networks rather than public networks. + ཁྱེད་ཀྱིས་ཁྱིམ་ཚང་དང་བྱ་བའི་དྲ་རྒྱའི་སྟེང་ནས་སྤྱི་སྤྱོད་མིན་པའི་དྲ་རྒྱའི་སྟེང་ནས་བྱེད་ནུས་འདི་སྤྱོད་རྒྱུའི་གྲོས་འགོ་བཏོན།. + + + Yse + དེ་ནི་རེད། + + + No + དེ་ལྟར་མ་བྱས་ + + + + Allow other devices on this network to discover this computer? + དྲ་རྒྱའི་སྟེང་གི་སྒྲིག་ཆས་གཞན་པས་གློག་ཀླད་འདི་རྙེད་དུ་འཇུག་གམ།? + + + + It is not recommended to enable this feature on public networks + བསམ་འཆར་མེད་།སྤྱི་པའི་དྲ་རྒྱའི་སྟེང་ནས་ནུས་པ་འདི་མགོ་བརྩམས་། + + + + Not allowed (recommended) + མི་ཆོག་(འོས་སྦྱོར་)། + + + + Allowed + ཆོག་པ་ + + + + Ipv4Page + + + IPv4Config + IPv4ཁུང་ཙི། + + + + Address + སྡོད་གནས། + + + + Netmask + དྲ་རྒྱའི་མ་ལག + + + + Default Gateway + ཁ་ཆད་བཞག་པའི་སྒོ་ཆེན། + + + + Prefs DNS + སྔོན་གྲབས་DNS + + + + Alternative DNS + ཚབ་བྱེད་རང་བཞིན་གྱི་DNS + + + + Auto(DHCP) + རང་འགུལ་(DHCP) + + + + Manual + ལག་དེབ། + + + + Invalid address + རྩིས་འགྲོ་མེད་པའི་ས་གནས། + + + + Invalid subnet mask + རྩིས་འགྲོ་མེད་པའི་དྲ་བ་འགེབས་སྲུང་བྱེད་པ། + + + + + Required + ངེས་པར་དུ་སྐོང་དགོས། + + + + Address conflict + ཤག་གནས་གདོང་གཏུག་ + + + + Ipv6Page + + + IPv6Config + IPv6ཁུང་ཙི། + + + + Address + སྡོད་གནས། + + + + Subnet prefix Length + ཡན་ལག་དྲ་རྒྱའི་སྔོན་སྒྲིག་གི་རིང་ཚད། + + + + Default Gateway + ཁ་ཆད་བཞག་པའི་སྒོ་ཆེན། + + + + Prefs DNS + སྔོན་གྲབས་DNS + + + + Alternative DNS + ཚབ་བྱེད་རང་བཞིན་གྱི་DNS + + + + Auto(DHCP) + རང་འགུལ་(DHCP) + + + + Manual + ལག་དེབ། + + + + + + Required + ངེས་པར་དུ་སྐོང་དགོས། + + + + Invalid address + རྩིས་འགྲོ་མེད་པའི་ས་གནས། + + + + Invalid gateway + རྩིས་འགྲོ་མེད་པའི་དྲ་བའི་འགག་སྒོ། + + + + Address conflict + ཤག་གནས་གདོང་གཏུག་ + + + + JoinHiddenWiFiPage + + + Please enter the network name and security type + ཁྱེད་རང་དྲ་རྒྱའི་ནང་དུ་ཞུགས་འདོད་པའི་མིང་དང་བདེ་འཇགས་རིགས་ནང་འཇུག་བྱེད་རོགས། + + + + Network name(SSID) + དྲ་རྒྱའི་མིང་། (SID) + + + Remember the Network + དྲ་རྒྱ་དེ་སེམས་ལ་འཛིན་དགོས། + + + + Show Network List + དྲ་རྒྱའི་རེའུ་མིག་གསལ་པོར་མངོན་པ། + + + + Cancel + མེད་པར་བཟོ་དགོས། + + + + Join + དེའི་ནང་དུ་ཞུགས་པ། + + + + Required + ངེས་པར་དུ་སྐོང་དགོས། + + + + Find and Join Wi-Fi + འཚོལ་ཞིབ་བྱས་པ་མ་ཟད་WI-FIལ་ཞུགས་པ་རེད། + + + + LanListItem + + + Not connected + འབྲེལ་མཐུད་མི་བྱེད་པ། + + + + Wired Device not carried + སྐུད་ཡོད་སྒྲིག་ཆས་འཁྱེར་མེད་པ། + + + + + Disconnect + འབྲེལ་ཐག་ཆད་པ། + + + + + Connect + སྦྲེལ་མཐུད་བྱེད་པ + + + Property + ངོ་བོ། + + + Delete + དྲ་རྒྱ་དེ་བསུབ་དགོས། + + + + LanPage + + + No ethernet device avaliable + ཨེ་ཙི་དྲ་རྒྱའི་སྒྲིག་ཆས་ལ་བཙན་འཛུལ་བྱས་མི་ཆོག། + + + + LAN + སྐུད་ཡོད་དྲ་བ། + + + + Activated LAN + ངའི་དྲ་རྒྱ། + + + + Inactivated LAN + དྲ་བ་གཞན་དག + + + LAN Disconnected Successfully + སྐུད་ཡོད་དྲ་བ་ཆད་སོང་། + + + + Wired Device not carried + སྐུད་ཡོད་སྒྲིག་ཆས་འཁྱེར་མེད་པ། + + + LAN Connected Successfully + སྐུད་ཡོད་དྲ་བ་སྦྲེལ་ཡོད། + + + + ListItem + + + Kylin NM + དྲ་རྒྱའི་ཡོ་བྱད། + + + + kylin network applet desktop message + དྲ་རྒྱའི་གསལ་འདེབས་གནས་ཚུལ། + + + + MainWindow + + + kylin-nm + དྲ་རྒྱའི་ཡོ་བྱད། + + + + LAN + 有线网络 + སྐུད་ཡོད་དྲ་བ། + + + + WLAN + 无线局域网 + སྐུད་མེད་ཅུས་ཁོངས་ཀྱི་དྲ་བ། + + + + Show MainWindow + རླུང་གཙོ་བོ་མངོན་པར་བྱས་ཡོད། + + + + Settings + 设置网络项 + སྒྲིག་བཀོད། + + + + Network tool + དྲ་རྒྱའི་ལག་ཆ་ + + + + NetDetail + + + Kylin NM + ཅིན་ལིན་NM + + + + kylin network desktop message + དྲ་རྒྱའི་གསལ་འདེབས་གནས་ཚུལ། + + + + Detail + ཞིབ་ཕྲའི་གནས་ཚུལ། + + + + IPv4 + IPv4 + + + + IPv6 + IPv6 + + + + Security + བདེ་འཇགས། + + + Close + 关闭 + + + + + Config + བཀོད་སྒྲིག་བཅས་བྱ་དགོས། + + + + Confirm + གཏན་འཁེལ་བྱ་དགོས། + + + + Cancel + ཕྱིར་འཐེན། + + + + Forget this network + དྲ་རྒྱ་འདི་བརྗེད་སོང་། + + + Delete this network + དྲ་རྒྱ་དེ་བསུབ་དགོས། + + + + Add Lan Connect + སྐུད་ཡོད་དྲ་བ་ཁ་སྣོན་བྱ་དགོས། + + + + connect hiddin wlan + ཧའེ་ཏེན་ཝེ་ལན་དང་འབྲེལ་མཐུད་བྱེད་པ། + + + + + + None + གཅིག་ཀྱང་མེད། + + + + + + Auto + རང་འགུལ་གྱིས་རླངས་ + + + + start check ipv4 address conflict + ipv4ས་གནས་ཀྱི་འགལ་བ་ལ་ཞིབ་བཤེར་བྱེད་འགོ་ཚུགས། + + + + start check ipv6 address conflict + ipv6གནས་ཡུལ་དང་འགལ་བར་ཞིབ་བཤེར་བྱེད་འགོ་ཚུགས། + + + ipv4 address conflict! + ipv4ཐག་གཅོད་གདོང་གཏུག་བྱུང་བ་རེད།! + + + ipv6 address conflict! + ipv6ཐག་གཅོད་གདོང་གཏུག་བྱུང་བ་རེད།! + + + + this wifi no support enterprise type + wifiལ་རྒྱབ་སྐྱོར་མེད་པའི་ཁེ་ལས་ཀྱི་རིགས་དབྱིབས། + + + + this wifi no support None type + wifiལ་རྒྱབ་སྐྱོར་མི་བྱེད་པར་རིགས་དབྱིབས་གཅིག་ཀྱང་མེད། + + + + this wifi no support WPA2 type + wifiལ་རྒྱབ་སྐྱོར་མི་བྱེད་པའི་WPA2རིགས་དབྱིབས་ + + + + this wifi no support WPA3 type + wifiལ་རྒྱབ་སྐྱོར་མི་བྱེད་པའི་WPA3རིགས་དབྱིབས་ + + + SSID: + SSID: + + + Protocol: + 协议: + + + Hz: + 网络频带: + + + Chan: + 网络通道: + + + BandWidth: + 带宽: + + + IPv4: + IPv4地址: + + + IPv4 Dns: + IPv4 DNS服务器: + + + IPv6: + 本地链接IPv6地址: + + + Mac: + 物理地址: + + + + OldMainWindow + + kylin-nm + 网络工具 + + + Show MainWindow + 打开网络工具 + + + Not connected + 未连接 + + + + OneConnForm + + + Form + + + + Connect + 连接 + + + Disconnect + 断开 + + + Cancel + 取消 + + + Forget + 忘记此网络 + + + None + + + + + OneLancForm + + + Form + + + + Connect + 连接 + + + Disconnect + 断开 + + + Cancel + 取消 + + + Not connected + 未连接 + + + + SecurityPage + + + Remember the Network + དྲ་རྒྱ་དེ་སེམས་ལ་འཛིན་དགོས། + + + + Security + བདེ་འཇགས། + + + + + Password + གསང་གྲངས། + + + + EAP type + EAP རིགས་དབྱིབས། + + + + Identity + ཐོབ་ཐང་། + + + + Domain + ཁྱབ་ཁོངས། + + + + CA certficate + CA certficate + + + + no need for CA certificate + CAཡི་ལག་ཁྱེར་མི་དགོས། + + + + User certificate + སྤྱོད་མཁན་གྱི་ལག་ཁྱེར། + + + + User private key + སྤྱོད་མཁན་གྱི་སྒེར་གྱི་ལྡེ་མིག + + + + User key password + སྤྱོད་མཁན་གྱི་ལྡེ་མིག་གི་གསང་ + + + + Password options + གསང་བའི་ཐོག་ནས་རྣམ་གྲངས་བདམས་པ། + + + + + + Required + ངེས་པར་དུ་སྐོང་དགོས། + + + + Ineer authentication + དབྱིན་ཆས་ཀྱི་བདེན་དཔང་ར་སྤྲོད་ + + + + Usename + བཀོལ་སྤྱོད་ཀྱི་མིང་། + + + Username + Usename + 用户名 + + + + Ask pwd each query + འདྲི་རྩད་རེ་རེར་འདྲི་རྩད་བྱེད་པ། + + + + + + + + + + + + None + གཅིག་ཀྱང་མེད། + + + + WPA&WPA2 Personal + WPA&WPA2མི་སྒེར་གྱི་ངོས་ནས་བཤད་ན། + + + + WPA&WPA2 Enterprise + WPA&WPA2 ཁེ་ལས། + + + + WPA3 Personal + WPA3མི་སྒེར་ + + + + + + Choose from file... + ཡིག་ཆའི་ནང་ནས་གདམ་ག་རྒྱག་དགོས།... + + + + Store passwords only for this user + སྤྱོད་མཁན་དེ་ཁོ་ནའི་ཆེད་དུ་གསང་གྲངས་ཉར་ཚགས་བྱས་ཡོད། + + + + Store password only for this user + སྤྱོད་མཁན་དེ་ཁོ་ནའི་ཆེད་དུ་གསང་གྲངས་ཉར་ཚགས་བྱས་ཡོད། + + + + Store passwords for all users + སྤྱོད་མཁན་ཚང་མའི་གསང་བ་གསོག་ཉར་བྱེད་དགོས། + + + + Store password for all users + སྤྱོད་མཁན་ཚང་མའི་གསང་བ་གསོག་ཉར་བྱེད་དགོས། + + + + Ask this password every time + ཐེངས་རེར་གསང་བ་འདི་འདྲི་རྩད་བྱེད་ཐེངས་རེ་ཡིན། + + + + Ask password every time + ཐེངས་རེར་གསང་བ་འདི་འདྲི་རྩད་བྱེད་ཐེངས་རེ་ཡིན། + + + + + + Choose a CA certificate + CAཡི་དཔང་ཡིག་འདེམས་པ། + + + + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + CA དཔང་ཡིག (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + + + + + + + TabPage + + + Current Device + མིག་སྔའི་སྒྲིག་ཆས། + + + + Devices Closed! + སྒྲིག་ཆས་སྒོ་རྒྱག་པ།! + + + + Settings + སྒྲིག་བཀོད། + + + + Kylin NM + ཅིན་ལིན་NM + + + + kylin network applet desktop message + kylinདྲ་རྒྱའི་ཀུ་ཤུའི་ཅོག་ཙེའི་ཆ་འཕྲིན། + + + + VpnPage + + + Activated VPN + + + + + Inactivated VPN + + + + + Wired Device not carried + སྐུད་ཡོད་སྒྲིག་ཆས་འཁྱེར་མེད་པ། + + + + WiFiConfigDialog + + + Dialog + + + + + WLAN Authentication + སྐུད་མེད་བདེན་དཔང་ར་སྤྲོད། + + + + Input WLAN Information Please + སྐུད་མེད་ཆ་འཕྲིན་ནང་འཇུག་གནང་རོགས། + + + + WLAN ID: + WLAN ID: + + + + WLAN Name: + སྐུད་མེད་མིང་།: + + + + Password: + གསང་གྲངས་ནི།: + + + + Cancl + ཁན་ཁེ་ལན། + + + + Ok + འགྲིགས། + + + + WlanListItem + + + Not connected + འབྲེལ་མཐུད་མི་བྱེད་པ། + + + + + Disconnect + འབྲེལ་ཐག་ཆད་པ། + + + + + + Connect + སྦྲེལ་མཐུད་བྱེད་པ + + + + + Forget + བརྗེད་པ། + + + Property + ངོ་བོ། + + + + Auto Connect + རང་འགུལ་གྱིས་སྦྲེལ་མཐུད་ + + + + WlanMoreItem + + More... + 更多... + + + + Add Others... + གཞན་པ་ཁ་སྣོན་བྱས་ནས་... + + + + WlanPage + + + WLAN + སྐུད་མེད་ཅུས་ཁོངས་ཀྱི་དྲ་བ། + + + + No wireless network card detected + སྐུད་མེད་དྲ་རྒྱའི་བྱང་བུ་མ་རྙེད་པ། + + + + Activated WLAN + ངའི་དྲ་རྒྱ། + + + + Other WLAN + དྲ་བ་གཞན་དག + + + More... + 更多... + + + + WLAN Connected Successfully + སྐུད་མེད་དྲ་བ་སྦྲེལ་ཡོད། + + + + WLAN Disconnected Successfully + སྐུད་མེད་དྲ་རྒྱ་ཆད་སོང་། + + + + WpaWifiDialog + + EAP type + EAP方法 + + + Username + 用户名 + + + Password + 密钥 + + + Ask pwd each query + 每次询问密码 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + Choose from file... + 从文件选择... + + + Choose a CA certificate + 选择一个CA证书 + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + CA 证书 (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + Identity + 匿名身份 + + + Domain + + + + no need for CA certificate + 不需要CA证书 + + + + main + + + kylinnm + + + + + show kylin-nm wifi page + སྐུད་མེད་དྲ་རྒྱའི་ངོས་མངོན་པར་བྱས་ཡོད། + + + + show kylin-nm lan page + སྐུད་ཡོད་དྲ་རྒྱའི་ཤོག་ངོས་མངོན་པར་བྱས་ཡོད། + + + + vpnMainWindow + + + kylin-vpn + + + + + vpn tool + + + + diff --git a/translations/kylin-nm_tr.qm b/translations/kylin-nm_tr.qm new file mode 100644 index 0000000000000000000000000000000000000000..67ee71e84e40a9877474ba9e57722ceff1c227d1 GIT binary patch literal 2010 zcmc&!&ubGw6n@)owrQIFP+IX&aD@sL8fc+Z5e3t1YeUnd&}xu^IwsR}%w{)aCk-k3 zA6W3BsCW^7oCGhTy%c-tK~eCcH=%bGZ}rfkzL^c1wn?Scg9*EDXL#@XzBlvDoL)*F ze*68w?e|B!Utf8+{COAv)&P7n_-ufB^Ep7nS5QAK0yNH5;w|u97{T#bH>y40Te*aJ z_uZ(yg8r@>I9^p2?{onu%Wm`)m3PKH#D_{WEAc}^Xyq}^F1S&1)Tgl@h~KHcJn<9b zlJDfqbu2qmiBH_9H2cPnm5|2>kc~mCA9SPE7g&7}#ky}TkM6DlsEOdmu{YRHXZx2{ z&YV^)z*| z+|KJc>NvRbLWzG{C%q6x0R%xO5!8Ydz6 zlP!9+h;7ZXOr2Z}F5>CQRx#tYC6{OirV1elRkKFzf|S^juqa|%Vl27;kcS3Jd3kMk zUTwL-V)IXV$eLm2a9M@Y;1o?23yhaNkGG*;7#0b~WVaOgqiJe!%&cFwYmc=IeaIlZ zCyxd?FD2dQNJDUBot4b4E32YA&O5ZAr)Yt*S(YMPE?_PAP+f3w1_{iet#QW$opM#pS80<>{}>vknW0Xo`cjgR#osHj*!}d2B*Qruqx|-_C8* zG`Z@zApq0Zintkao_!h;Ss}S2$wry$d4mzt&PZ?m)x8%?n*V(9)nfQz*UP~#2xXJM E0d&EWGynhq literal 0 HcmV?d00001 diff --git a/translations/kylin-nm_tr.ts b/translations/kylin-nm_tr.ts new file mode 100644 index 00000000..bca72f95 --- /dev/null +++ b/translations/kylin-nm_tr.ts @@ -0,0 +1,2324 @@ + + + + + BackThread + + Confirm your WLAN password + WLAN parolasını doğrula + + + + ConfForm + + edit network + Ağı düzenle + + + LAN name: + LAN adı: + + + Method: + Yöntem: + + + Address: + Adres: + + + Netmask: + Netmask: + + + DNS 1: + DNS 1: + + + DNS 2: + DNS 2: + + + Edit Conn + Bağ. Düzenle + + + Auto(DHCP) + Oto(DHCP) + + + Manual + Elle + + + Cancel + İptal + + + Save + Kaydet + + + Ok + Tamam + + + Can not create new wired network for without wired card + Kablolu kart olmadan yeni kablolu ağ oluşturulamıyor + + + New network already created + Yeni ağ zaten oluşturuldu + + + New network settings already finished + Yeni ağ ayarları zaten tamamlandı + + + kylin network applet desktop message + Kylin ağ uygulaması masaüstü mesajı + + + Edit Network + Ağı Düzenle + + + Add Wired Network + Kablolu Ağ Ekle + + + create wired network successfully + Başarıyla kablolu ağ oluşturuldu + + + change configuration of wired network successfully + Kablolu ağın yapılandırmasını başarıyla değiştirildi + + + New settings already effective + Yeni ayarlar zaten etkili + + + + ConfigPage + + + Network profile type + + + + + Public(recommended) Devices on the network cannot discover this computer. Generally, it is suitable for networks in public places, such as airports or coffee shops, etc. + + + + + Devices on the network can discover this computer. Generally applicable to a network at home or work where you know and trust the individuals and devices on the network. + + + + + Config firewall and security settings + + + + + CreatNetPage + + + Connection Name + + + + + Ipv4Config + + + + + Address + + + + + Netmask + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + Oto(DHCP) + + + + Manual + Elle + + + + DetailPage + + + Auto Connection + + + + + + SSID: + + + + + Copied successfully! + + + + + Copy all + + + + + Please input SSID: + + + + + + Protocol: + + + + + + Security Type: + + + + + + Hz: + + + + + + Chan: + + + + + + BandWidth: + + + + + + IPV6: + + + + + + IPV4: + + + + + + IPV4 Dns: + + + + + + Mac: + + + + + DlgHideWifi + + Add Hidden WLAN + Gizli WLAN Ekle + + + Connection + Bağlantı + + + WLAN name + WLAN adı + + + WLAN security + WLAN güvenlik + + + Cancel + İptal + + + Connect + Bağlantı + + + C_reate… + Oluştur... + + + None + Yok + + + Conn WLAN Success + WLAN Bağlantısı Başarılı + + + Confirm your WLAN password or usable of wireless card + Kablosuz şifrenizi veya kablosuz kart kullanılabilirliğini onaylayın + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + + DlgHideWifiEapFast + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN Ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı + + + WLAN security + WLAN güvenliği + + + Authentication + Kimlik Doğrulama + + + Anonymous identity + Anonim kimlik + + + Allow automatic PAC pro_visioning + Otomatik PAC pro_visioning'e izin ver + + + PAC file + PAC dosyası + + + Inner authentication + İç kimlik doğrulama: + + + Username + Kullanıcı adı + + + Password + Parola + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + Anonymous + Anonim + + + Authenticated + Doğrulanmış + + + Both + Her ikisi de + + + + DlgHideWifiEapLeap + + Connect to Hidden WLAN Network + Gizli WLAN ağına bağlan + + + Add hidden WLAN + Gizli WLAN ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN güvenliği: + + + Authentication + Kimlik Doğrulama: + + + Username + Kullanıcı adı: + + + Password + Parola: + + + Cancel + 取消 + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + + DlgHideWifiEapPeap + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN güvenliği: + + + Authentication + Kimlik Doğrulama: + + + Anonymous identity + Anonim kimlik: + + + Domain + Domain: + + + CA certificate + CA sertifikası: + + + CA certificate password + CA sertifika şifresi: + + + No CA certificate is required + CA sertifikası gerekmez + + + PEAP version + PEAP sürümü: + + + Inner authentication + İç kimlik doğrulama: + + + Username + Kullanıcı adı: + + + Password + Parola: + + + Cancel + İptal + + + Connect + Bağlan + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + Choose from file + Dosyadan seçin... + + + Automatic + Otomatik + + + Version 0 + Sürüm 0 + + + Version 1 + Sürüm 1 + + + + DlgHideWifiEapPwd + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN güvenliği: + + + Authentication + Kimlik Doğrulama: + + + Username + Kullanıcı adı: + + + Password + Parola: + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + + DlgHideWifiEapTTLS + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN Güvenliği: + + + Authentication + Kimlik Doğrulama: + + + Anonymous identity + Anonim kimlik: + + + Domain + Domain: + + + CA certificate + CA Sertifikası: + + + CA certificate password + CA sertifika şifresi: + + + No CA certificate is required + CA sertifikası gerekmez + + + Inner authentication + İç kimlik doğrulama: + + + Username + Kullanıcı adı: + + + Password + Parola: + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + Choose from file + Dosyadan seçiniz... + + + + DlgHideWifiEapTls + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN güvenliği: + + + Authentication + Kimlik Doğrulama: + + + Identity + Kimlik: + + + Domain + Domain: + + + CA certificate + CA sertifikası: + + + CA certificate password + CA sertifika şifresi: + + + No CA certificate is required + CA sertifikası gerekmez + + + User certificate + Kullanıcı sertifikası: + + + User certificate password + Kullanıcı sertifikası şifresi: + + + User private key + Kullanıcı özel anahtarı: + + + User key password + Kullanıcı anahtarı şifresi: + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + Tunneled TLS + Tünelli TLS + + + Protected EAP (PEAP) + Korumalı EAP (PEAP) + + + Choose from file + Dosyadan seç... + + + + DlgHideWifiLeap + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN Ekle + + + Connection + Bağlantı + + + Network name + Ağ adı + + + WLAN security + WLAN Güvenlik + + + Username + Kullanıcı adı + + + Password + Parola + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1X) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + + DlgHideWifiWep + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add hidden WLAN + Gizli WLAN Ekle + + + Connection + Bağlantı: + + + Network name + Ağ adı: + + + WLAN security + WLAN Güvenliği: + + + Key + Anahtar + + + WEP index + WEP index + + + Authentication + Kimlik Doğrulama: + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + WEP 128-bit Passphrase + WEP 128-bit Passphrase + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + 1(default) + 1(default) + + + Open System + Sistemi aç + + + Shared Key + Paylaşılan Anahtar + + + + DlgHideWifiWpa + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Add Hidden WLAN + Gizli WLAN Ekle + + + Connection + Bağlantı: + + + WLAN name + WLAN adı: + + + WLAN security + WLAN güvenlik: + + + Password + Parola: + + + Cancel + İptal + + + Connect + Bağlan + + + C_reate… + Oluştur... + + + None + Yok + + + Conn WLAN Success + WLAN Bağlantısı Başarılı + + + Confirm your WLAN password or usable of wireless card + Kablosuz şifrenizi veya kablosuz kart kullanılabilirliğini onaylayın + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + WPA & WPA2 Enterprise + WPA & WPA2 Enterprise + + + WEP 40/128-bit Key (Hex or ASCII) + WEP 40/128-bit Key (Hex veya ASCII) + + + Dynamic WEP (802.1X) + Dinamik WEP (802.1x) + + + + DlgHotspotCreate + + Create Hotspot + Etkin Nokta Oluştur + + + Network name + Ağ adı: + + + WLAN security + WLAN Güvenlik: + + + Password + Parola: + + + Cancel + İptal + + + Ok + Tamam + + + None + Yok + + + WPA & WPA2 Personal + WPA & WPA2 Kişisel + + + + EnterpriseWlanDialog + + + Wi-Fi network requires authentication + + + + + Access to Wi-Fi network " + + + + + " requires a password or encryption key. + + + + + Cancel + + + + + Connect + + + + + FirewallDialog + + + Allow other devices on this network to discover this computer? + + + + + It is not recommended to enable this feature on public networks + + + + + Not allowed (recommended) + + + + + Allowed + + + + + Ipv4Page + + + Ipv4Config + + + + + Address + + + + + Netmask + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + Oto(DHCP) + + + + Manual + Elle + + + + Invalid address + + + + + Invalid subnet mask + + + + + + Required + + + + + Address conflict + + + + + Ipv6Page + + + Ipv6Config + + + + + Address + + + + + Subnet prefix Length + + + + + Default Gateway + + + + + Prefs DNS + + + + + Alternative DNS + + + + + Auto(DHCP) + Oto(DHCP) + + + + Manual + Elle + + + + + + Required + + + + + Invalid address + + + + + Invalid gateway + + + + + Address conflict + + + + + JoinHiddenWiFiPage + + + Please enter the network name and security type + + + + + Network name(SSID) + + + + + Show Network List + + + + + Cancel + + + + + Join + + + + + Required + + + + + Find and Join Wi-Fi + + + + + KylinDBus + + kylin network applet desktop message + Kylin ağ uygulaması masaüstü mesajı + + + + LanListItem + + + Not connected + Bağlanamadı + + + + Wired Device not carried + + + + + + Disconnect + Bağlantıyı Kes + + + + + Connect + + + + + LanPage + + + No ethernet device avaliable + + + + + LAN + + + + + Activated LAN + + + + + Inactivated LAN + + + + + Wired Device not carried + + + + + ListItem + + + Kylin NM + + + + + kylin network applet desktop message + Kylin ağ uygulaması masaüstü mesajı + + + + MainWindow + + + kylin-nm + + + + Network + + + + Advanced + Gelişmiş + + + Ethernet + Kablolu Ağ + + + Connect Hide Network + Gizli Ağı Bağlan + + + + LAN + + + + + WLAN + WLAN + + + + Settings + + + + + Network tool + + + + Enabled + Aktif + + + Disabled + Pasif + + + HotSpot + HotSpot + + + + Show MainWindow + Ana Pencereyi Göster + + + Not connected + Bağlanamadı + + + Disconnected + Bağlantı Kesildi + + + No Other Wired Network Scheme + Başka Kablolu Ağ Düzeni Yok + + + No Other Wireless Network Scheme + Başka Kablosuz Ağ Düzeni Yok + + + Wired net is disconnected + Kablolu ağ bağlantısı kesildi + + + WLAN is disconnected + Kablosuz bağlantı kesildi + + + Confirm your WLAN password or usable of wireless card + Kablosuz şifrenizi veya kablosuz kart kullanılabilirliğini onaylayın + + + Confirm your WLAN password + WLAN parolasını doğrula + + + Ethernet Networks + Ethernet Ağları + + + New LAN + Yeni LAN + + + Hide WLAN + Gizli WLAN + + + No usable network in the list + Listede kullanılabilir ağ yok + + + WLAN Networks + WLAN Ağları + + + None + Yok + + + keep wired network switch is on before turning on wireless switch + Kablosuz anahtarı açmadan önce kablolu ağ anahtarını açık tut + + + please insert the wireless network adapter + Lütfen kablosuz ağ adaptörünü takın + + + Abnormal connection exist, program will delete it + Anormal bağlantı var, program onu ​​silecek + + + update WLAN list now, click again + Kablosuz listesini şimdi güncelle, tekrar tıkla + + + update WLAN list now + Kablosuz listesini şimdi güncelle + + + Conn Ethernet Success + Ethernet Bağlantısı Başarılı + + + Conn Ethernet Fail + Ethernet Bağlantısı Hatası + + + Conn WLAN Success + WLAN Bağlantısı Başarılı + + + + NetDetail + + + Kylin NM + + + + + kylin network desktop message + + + + + Detail + + + + + Ipv4 + + + + + Ipv6 + + + + + Security + + + + + + Config + Ayar + + + + Confirm + + + + + Cancel + + + + + Forget this network + + + + + Add Lan Connect + + + + + connect hiddin wlan + + + + + + + None + Yok + + + + + + Auto + Oto + + + + start check ipv4 address conflict + + + + + start check ipv6 address conflict + + + + + this wifi no support enterprise type + + + + + this wifi no support None type + + + + + this wifi no support WPA2 type + + + + + this wifi no support WPA3 type + + + + + NotifySend + + Form + -- + + + + OldMainWindow + + Ethernet Networks + Ethernet Ağları + + + New LAN + Yeni LAN + + + WLAN Networks + WLAN Ağları + + + Hide WLAN + Gizli WLAN + + + No usable network in the list + Listede kullanılabilir ağ yok + + + Ethernet + Kablolu Ağ + + + HotSpot + HotSpot + + + Advanced + Gelişmiş + + + Show MainWindow + Ana Pencereyi Göster + + + Wired net is disconnected + Kablolu ağ bağlantısı kesildi + + + Not connected + Bağlanamadı + + + Disconnected + Bağlantı Kesildi + + + No Other Wired Network Scheme + Başka Kablolu Ağ Düzeni Yok + + + No Other Wireless Network Scheme + Başka Kablosuz Ağ Düzeni Yok + + + WLAN is disconnected + Kablosuz bağlantı kesildi + + + Conn Ethernet Success + Ethernet Bağlantısı Başarılı + + + Conn WLAN Success + WLAN Bağlantısı Başarılı + + + Confirm your WLAN password or usable of wireless card + Kablosuz şifrenizi veya kablosuz kart kullanılabilirliğini onaylayın + + + Confirm your WLAN password + WLAN parolasını doğrula + + + + OneConnForm + + + Form + -- + + + Input password + Parola gir + + + Config + Ayar + + + Connect + Bağlan + + + Disconnect + Bağlantıyı Kes + + + Input Password... + Parola gir... + + + Connect to Hidden WLAN Network + Gizli WLAN Ağına Bağlan + + + Public + Halka açık + + + Safe + Güvenli + + + Rate + Oran + + + None + Yok + + + WLAN Security: + WLAN güvenliği: + + + Sifnal: + Sinyal gücü: + + + MAC: + Fiziksel adres: + + + Conn WLAN Success + WLAN Bağlantısı Başarılı + + + Confirm your WLAN password or usable of wireless card + Kablosuz şifrenizi veya kablosuz kart kullanılabilirliğini onaylayın + + + Conn WLAN Failed + WLAN Bağlantısı Başarısız + + + + OneLancForm + + + Form + -- + + + Config + Ayar + + + Connect + Bağlan + + + Disconnect + Bağlantıyı Kes + + + Not connected + Bağlanamadı + + + Disconnected + Bağlantı Kesildi + + + Ethernet + Kablolu Ağ + + + No Configuration + Yapılandırma Yok + + + IPv4: + IPv4 adresi: + + + IPv6: + IPv6 adresi: + + + BandWidth: + Bant genişliği: + + + MAC: + Fiziksel adres: + + + Auto + Oto + + + + SecurityPage + + + Remember the Network + + + + + Security + + + + + + Password + + + + + EAP type + + + + + Identity + Kimlik: + + + + Domain + Domain: + + + + CA certficate + + + + + no need for CA certificate + + + + + User certificate + Kullanıcı sertifikası: + + + + User private key + Kullanıcı özel anahtarı: + + + + User key password + Kullanıcı anahtarı şifresi: + + + + Password options + + + + + + + Required + + + + + Ineer authentication + + + + + Usename + + + + + Ask pwd each query + + + + + + + + + + + + + None + Yok + + + + WPA&WPA2 Personal + + + + + WPA&WPA2 Enterprise + + + + + WPA3 Personal + + + + + + + Choose from file... + + + + + Store passwords only for this user + + + + + Store password only for this user + + + + + Store passwords for all users + + + + + Store password for all users + + + + + Ask this password every time + + + + + Ask password every time + + + + + + + Choose a CA certificate + + + + + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + + + + + + + + TabPage + + + Current Device + + + + + Devices Closed! + + + + + Settings + + + + + Kylin NM + + + + + kylin network applet desktop message + Kylin ağ uygulaması masaüstü mesajı + + + + Utils + + kylin network applet desktop message + Kylin ağ uygulaması masaüstü mesajı + + + + VpnPage + + + Activated VPN + + + + + Inactivated VPN + + + + + Wired Device not carried + + + + + WiFiConfigDialog + + + Dialog + + + + + WLAN Authentication + + + + + Input WLAN Information Please + + + + + WLAN ID: + + + + + WLAN Name: + + + + + Password: + + + + + Cancl + + + + + Ok + Tamam + + + + WlanListItem + + + Not connected + Bağlanamadı + + + + + Disconnect + Bağlantıyı Kes + + + + + + Connect + + + + + + Forget + + + + + Auto Connect + + + + + WlanMoreItem + + + Add Others... + + + + + WlanPage + + + WLAN + WLAN + + + + Activated WLAN + + + + + Other WLAN + + + + + No wireless network card detected + + + + + WLAN Connected Successfully + + + + + WLAN Disconnected Successfully + + + + + WpaWifiDialog + + Identity + Kimlik: + + + Domain + Domain: + + + None + Yok + + + + main + + + kylinnm + + + + + show kylin-nm wifi page + + + + + show kylin-nm lan page + + + + + vpnMainWindow + + + kylin-vpn + + + + + vpn tool + + + + diff --git a/translations/kylin-nm_zh_CN.qm b/translations/kylin-nm_zh_CN.qm new file mode 100644 index 0000000000000000000000000000000000000000..31d5632b8802371bff87ffdafbd5c689c6e3e3e7 GIT binary patch literal 11040 zcmbt43v?6Ll}}ifMzSP-G2q%{a4;Aja0n2mOLGdw#>EAX^>HFNCdMPpNSc*2qevqe zLy95LhO7v2n(%9L@@XIogaF%aavItO(o=HMlC&wiCW( z(nup?cEbr*w(jrUd*A&%Zuv1c{Z}77wCCknji-kn``N#&K*;zRLWoAFVG%<8zeA|} zpAm8nAyo4t71q9kjJr-CG<6v=zIrc0Gu~HWg991={XvB4?*zCP;1j5P>X!&ro#Eu7MXQ0=e^>t9h}^IWuW>bC&@ zHPm~#0rXmmn9)tZcR9fC0gR)y--4gbtI%D(V{n8|&<|U#L&$O?x>&sip;=!;AFsFx z&h;kx?17_zmok|CVHBaV*Hl;`s?dJIK!u-0$ni~s^Y9+{{t?5yd#8dvdsNtbx8d07 zT7+h9H@wt+0KVr`Ska|I`wqi}UAqyQeQ?TxGY1i>KCZ&qWo4_qPs925m8G8%5i*=B z+xL5r-|$e`2VSs4W1rEMmc)#)7SI>ce?@*yF z0`B_-e1E>&(eymnGgSW7!8_sm9u?YFs?f2ee09qR*gaMrY?^`4S6a)r{@o5Z-)rRu z9ss*EmYe4O;=cf%GObU1g3xtyOq;n~!0(Xh>GR-sbA#!ly0^jpe>T^8F2Q*R%;}?B z5Neufesb5l2u=Bm3auwqX!{TIi>E+e>SfBd73566iCP@}Pw?X@YKh}k;B$uh!IMGI zvr>f>KcF6esTurno;v#OzXIR8s6S!4X%{Uw-TpfG@k`4s=PeM25exSP#El7A0xyAm ztKU}P?3*ppv=8AtoFzH89OC?Umc19?TvbafPt5xx*!802JEAR@hZ&XRMuNn-Q{EtX+5i4e0Zp zmHlD~=&@CW*FSFc?RLYtYpmQWFN55tt^8^@4|PC=)h#N#e#EMr-~O)k=V#sld#9{t z|FIYB|AFW`;AmQzW*%H{k7uQo_S!W zHWkhssJKA?2<-Zp3T^vU=s09s{{C}7-(uTk2YqcXs?c#kg;mE@ICHM;-p22P{V&@N z%-;_1gzceKJjgj``-vd|@v}^Y&4acJtHAzr%=VE7es8&KZ<-H!*KD;nt;ew6zB3Hp zw~X1pKmQh>v)O-sC**~yx9xv5CL#V_b{O6PKh4Gui;!5Do;K&8~EE*Slg_^=6|aEqx~T0vq(T_j-w0+>hA9w z6ZbBPh1VV!*fn^ME0lh2Or$U?6a3%OC5ZtcNC$*CKf*>LG%Ip+g7+umf;^QTvwQHFp{IQHw_oaC@42po=nJ!NI~R; zl)xp~NJ9CB)77Y5&t6sdY}gn4-OOL^-0V%0bJa1KgT&%eK*0Kq#&|szK362!dWG^I z-tN3&DKtG}pV;`Wi0cmTQr~jyD%J4o?g}o2-_#H6y_Fr>x4Cz7Z=SJ_I+H%IS8JRH zV@7$AUD^YpBwyVL^Jzh*!9R(lAS<2-fYmc@OwfWz#}uJ-EW(1H=L4QUM6+OO zAs&#r!&L@<3wspmMRtD3P zh_>xLfp!(@0=e@Dy|ptbORe3j zx}5X$Nh$1$0sH93grpKKn#lWQ0m7VNqe>(ci=-ZYJ$-P@T`jL7siSQ+l} zsJ=X67#xa(*4pb#Em1GHKAF+C+I^UyoBCK0?tnfjHRv33`HyTg5OgzGIm#x&`uNrZ zdyC9&amM*TqO`#&Z1DRo`VSEqmDtd9&U9FowVRh&AwnE%8k#fsvnvgR#<~Ksomb%G z&{92gD|XFz!?-7pq`WJ{iu%~=?CuU)7@f1 zm)?=3$2TdDsvJ}4Qq%|Mdlx?VrT4l>$CAO<^MtC;CLqdTnKzlsB-MS1+p8oXlyc0ptNwVaZBD&btte`xK@{+u*xYFV* zpNH-6Wb5hxBzRpRb^Fjg+Xi3QXzlnoW;)K_k%UqWDUpt`i3C(E z4ktxk^v6eIO3DcHqe@1sTPZ^3ip7Nl?~Slxx4=fEpi;SO(x>-)h`dNZ3s4UdaFi3% z&FEAj6_-e_u%JiCW@ow?hiz$|M$fC!orH_2ixvI661o$RXzs5$b9E;cQ?FI~o^6p8 z&^$a(1h;6F&RHu74TC5{{l_+%SVn8$hJiV*&h(GN95xLD?T9PIysES}(A?bjhUa74 z-dwqkNd0nQh;%_&a3QLIbKwIBiug)pfV<*3xW!ismR$P zT}rxxv14ts%?Xh=g8@m9#iS8PgPLZd6enZJicR&#QcFlOr!b!Dhnuz$Syh?p4lRNh zfZj#MBD6%4E%90^Bd#_?OhHN4qE4lh{}#VWW2nkrF~vp%j%IT$j+VxT zX^LudZI&*P^nsJv$S0c5x2gXNbY{cYheZ@jcaWi5*gxZLSCPJ^l zNq@kOTCxiZD>L;;uy*M@mVat+rOfhlfA8XB*Z6vrg^6V~V;%(9Ewl zWZEq#u*v|Qo6NB^?M5Lx+Ln?$fn!UN*aBZ4U5XWSPum$H=BoCDpd@FHy+%kV)u0p) zW655mVht-|>Ry?TD&3RSP4DH@)_@2zb@LHkRwlI~d?WwV21GEe-FQ)<%y-zAMcAfb zn?@BouAdnKwe}a07}pOC&m{sVXkuf0Tvo=vB3x^*&3|5T=V?MQ-3zS;ml^G8+!^@U zcpSzST?Hv$wYonb^!84eRa1}vIC@PdgNe*wGjb;=+&p3T5CSMw?8GEN%a+p`k}^Hc zRl&BKHp8UOF0fEiu*?=&C zMoy)29doGo6ouMZ`M0*5UccP?hcOosW%On|Ux-|M6iTt)0x_z`+ZO%8{b-S$DxqVf zAy~6}159ZFi>P}8#bnyjZNys!J*-mWPa!u=g*N4?b0OYFaqxS@2zWMv1+8+h0z|!R zRI6qqbrqTkCOw_g|2BM<$bb}vcO^P_)(x+xVWo>*O0a8tq<9cwQ`xqb7C~iq2ZYdw zw+1>wvX~tj%nlvQN#3^tJ5Ax=%5i2SQMpD1I7U3P6D$aFbqlVeLk-T+?uC2Dzx^Ai z^J`EiVhCMrCR@`X=nvrfk3?9dY!?XA&j3x@48ZY4SHFPG^bKg;Ih+MynvZ4ootmj= zRzhaukkdoFKTHcSL1iZd&6so*w#o`;Lbe@~VOt;O&e3; z8m_Z-t)O&Q$~s4v_Z9e$#Gnzbr;;ry`b8d+hlqbRl$FMT9O&1fF3+-8c07nxC77BWlhB0jb(9}SNhg~td-^DM0Y???iV zYgMBWvrx=Pwq#e+)5W0NR+>g12{d(mn9Hlb~DM+GBi_ZfobDU53v$E`q=P5a{r?`kTN;^|heLVAh8h40Lh;Z?}}ZrsJ@2i|;)KF>RP0ACXW`>k3H{>`GZW!v-$j1bmoZ`s^56xwXk%C`O}D5NqZ#oUH+KSOW^Y?U zA$%3aEqUEmRhEF3lnt-?dQ}`6>688a=}Ve2UFYVbeAJhj$}+8pbjR9<(G|eK)6eXfAuBN0wmINUmuBw%M>Rq>~9gUgD%R%vok>`VwY_ z8Ee?hDqtsx@brs$D#-vdy>=Cwv^-%w`v23hxscyvl{Dca57xOC6S zmT*Ml;z&+g3-x-AQnOc*myJnt!vCOvaH=MpoDgJ^n0d*}1~Dmfj*KRY5v`%O1N~z9 zDzuCpzvUF=+XiTCAi;1-5KSiKQX4$5zjAq4qQ0Xm8IMC!%Z%*U2Ic|QN7ROqZJpVb z*z-Z&OJrsC<-RKd*`8A#AvHvkY^yai$_%FY=OmiRP=l-A?@oH+)$qFZf&I2vW+9~YF6$_bQt5l3!gKd=E^At1&c06PE<7G@D+Y(>{^g-4qJGJ7ak|VcN%5DHC zOh$s7EPwFQKyy82!SZJWR$9<% + + + + ConfForm + + Manual + 手动 + + + Cancel + 取消 + + + kylin-nm + 网络工具 + + + kylin network applet desktop message + 网络提示消息 + + + Will check the IP address conflict + 正在检测ip地址冲突 + + + IPv4 address conflict, Please change IP + ip地址冲突,请更改ip + + + IPv6 address conflict, Please change IP + ip地址冲突,请更改ip {6 ?} + + + + ConfigPage + + + Network profile type + 网络配置文件类型 + + + + Public(recommended) Devices on the network cannot discover this computer. Generally, it is suitable for networks in public places, such as airports or coffee shops, etc. + 公用(推荐) 网络中的设备不可发现此电脑。一般情况下适用于公共场所中的网络,如机场或咖啡店等等。 + + + + Devices on the network can discover this computer. Generally applicable to a network at home or work where you know and trust the individuals and devices on the network. + 专用 网络中的设备可发现此电脑。一般情况下适用于家庭或工作单位的网络,您认识并信任网络上的个人和设备。 + + + Public(recommended) Your device can not be discovered on the network. In most cases, use this feature when connected to a network at home, work, or a public location. + 公用(推荐)无法在网络上发现你的设备。在大多数情况下,在家庭、工作或公共位置连接到网络时使用此功能。 + + + Private Your device can be discovered on the network. Select this if you require file sharing or use applications that communicate over this network. You should know and trust the people and devices on the network. + 专用 可在网络上发现你的设备。如果需要文件共享或使用通过此网络通信的应用,请选择此项。你应该了解并信任网络上的人员和设备。 + + + + Config firewall and security settings + 配置防火墙和安全设置 + + + + CopyButton + + Copied successfully + 复制成功 + + + Copied successfully! + 复制成功! + + + Copy all + 复制全部 + + + + CreatNetPage + + + Connection Name + 网络名称 + + + + IPv4Config + IPv4配置 + + + + Address + IPv4地址 + + + + Netmask + 子网掩码 + + + + Default Gateway + 默认网关 + + + + Prefs DNS + 首选DNS + + + + Alternative DNS + 备选DNS + + + + Auto(DHCP) + 自动(DHCP) + + + + Manual + 手动 + + + + DetailPage + + + Auto Connection + 自动连接 + + + + + SSID: + SSID: + + + + Copied successfully! + 复制成功! + + + + Copy all + 复制全部 + + + + Please input SSID: + 请输入SSID: + + + + + Protocol: + 协议: + + + + + Security Type: + 安全类型: + + + + + Hz: + 网络频带: + + + + + Chan: + 网络通道: + + + + + BandWidth: + 带宽: + + + + + IPv6: + 本地链接IPv6地址: + + + + + IPv4: + IPv4地址: + + + + + IPv4 Dns: + IPv4 DNS服务器: + + + + + Mac: + 物理地址: + + + + DlgHideWifi + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapFast + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapLeap + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapPeap + + Domain + + + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapPwd + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapTTLS + + Domain + + + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiEapTls + + Identity + 匿名身份 + + + Domain + + + + User certificate + 用户证书 + + + User private key + 用户私钥 + + + User key password + 用户密钥密码 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiLeap + + Username + 用户名 + + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiWep + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + DlgHideWifiWpa + + Password + 密钥 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + + EnterpriseWlanDialog + + Connect Enterprise WLAN + 连接企业网 + + + Close + 关闭 + + + + Wi-Fi network requires authentication + Wi-Fi网络要求认证 + + + + Access to Wi-Fi network " + 访问Wi-Fi网络 + + + + " requires a password or encryption key. + 需要密码或加密密钥。 + + + + Cancel + 取消 + + + + Connect + 连接 + + + + FirewallDialog + + Allow your computer to be discovered by other computers and devices on this network? + 是否允许你的电脑被此网络上的其他电脑和设备发现? + + + It is recommended that you enable this feature on your home and work networks rather than public networks. + 建议你在家庭和工作网络上而非公共网络上启用此功能。 + + + Yse + + + + No + + + + + Allow other devices on this network to discover this computer? + 是否允许此网络上的其他设备发现这台电脑? + + + + It is not recommended to enable this feature on public networks + 不建议在公共网络上开启此功能 + + + + Not allowed (recommended) + 不允许(推荐) + + + + Allowed + 允许 + + + + Ipv4Page + + + IPv4Config + IPv4配置 + + + + Address + 地址 + + + + Netmask + 子网掩码 + + + + Default Gateway + 默认网关 + + + + Prefs DNS + 首选DNS + + + + Alternative DNS + 备选DNS + + + + Auto(DHCP) + 自动 + + + + Manual + 手动 + + + + Invalid address + 无效地址 + + + + Invalid subnet mask + 无效子网掩码 + + + + + Required + 必填 + + + + Address conflict + 地址冲突 + + + + Ipv6Page + + + IPv6Config + IPv6配置 + + + + Address + 地址 + + + + Subnet prefix Length + 子网前缀长度 + + + + Default Gateway + 默认网关 + + + + Prefs DNS + 首选DNS + + + + Alternative DNS + 备选DNS + + + + Auto(DHCP) + 自动 + + + + Manual + 手动 + + + + + + Required + 必填 + + + + Invalid address + 无效地址 + + + + Invalid gateway + 无效网关 + + + + Address conflict + 地址冲突 + + + + JoinHiddenWiFiPage + + + Please enter the network name and security type + 请输入您想要加入网络的名称和安全类型 + + + + Network name(SSID) + 网络名(SSID) + + + Remember the Network + 记住该网络 + + + + Show Network List + 显示网络列表 + + + + Cancel + 取消 + + + + Join + 加入 + + + + Required + 必填 + + + + Find and Join Wi-Fi + 查找并加入Wi-Fi + + + + LanListItem + + + Not connected + 未连接 + + + + Wired Device not carried + 未插入网线 + + + + + Disconnect + 断开 + + + + + Connect + 连接 + + + Property + 属性 + + + Delete + 删除此网络 + + + + LanPage + + + No ethernet device avaliable + 未检测到有线设备 + + + + LAN + 有线网络 + + + + Activated LAN + 我的网络 + + + + Inactivated LAN + 其他网络 + + + LAN Disconnected Successfully + 有线网络已断开 + + + + Wired Device not carried + 未插入网线 + + + LAN Connected Successfully + 有线网络已连接 + + + + ListItem + + + Kylin NM + 麒麟网络设置工具 + + + + kylin network applet desktop message + 网络提示消息 + + + + MainWindow + + + kylin-nm + 网络工具 + + + + LAN + 有线网络 + 有线网络 + + + + WLAN + 无线局域网 + 无线局域网 + + + + Show MainWindow + 打开网络工具 + + + + Settings + 设置网络项 + 设置网络项 + + + + Network tool + 网络工具 + + + + NetDetail + + + Kylin NM + 麒麟网络设置工具 + + + + kylin network desktop message + 网络提示消息 + + + + Detail + 详情 + + + + IPv4 + IPv4 + + + + IPv6 + IPv6 + + + + Security + 安全 + + + Close + 关闭 + + + + + Config + 配置 + + + + Confirm + 确定 + + + + Cancel + 取消 + + + + Forget this network + 忘记此网络 + + + Delete this network + 删除此网络 + + + + Add Lan Connect + 添加有线网络 + + + + connect hiddin wlan + 连接到隐藏WLAN + + + + + + None + + + + + + + Auto + 自动 + + + + start check ipv4 address conflict + 开始检测ipv4地址冲突 + + + + start check ipv6 address conflict + 开始检测ipv6地址冲突 + + + ipv4 address conflict! + ipv4地址冲突! + + + ipv6 address conflict! + ipv6地址冲突! + + + + this wifi no support enterprise type + 此wifi不支持企业网类型 + + + + this wifi no support None type + 此wifi不支持空类型 + + + + this wifi no support WPA2 type + 此wifi不支持WPA2类型 + + + + this wifi no support WPA3 type + 此wifi不支持WPA3类型 + + + SSID: + SSID: + + + Protocol: + 协议: + + + Hz: + 网络频带: + + + Chan: + 网络通道: + + + BandWidth: + 带宽: + + + IPv4: + IPv4地址: + + + IPv4 Dns: + IPv4 DNS服务器: + + + IPv6: + 本地链接IPv6地址: + + + Mac: + 物理地址: + + + + OldMainWindow + + kylin-nm + 网络工具 + + + Show MainWindow + 打开网络工具 + + + Not connected + 未连接 + + + + OneConnForm + + + Form + + + + Connect + 连接 + + + Disconnect + 断开 + + + Cancel + 取消 + + + Forget + 忘记此网络 + + + None + + + + + OneLancForm + + + Form + + + + Connect + 连接 + + + Disconnect + 断开 + + + Cancel + 取消 + + + Not connected + 未连接 + + + + SecurityPage + + + Remember the Network + 记住该网络 + + + + Security + 安全性 + + + + + Password + 密钥 + + + + EAP type + EAP方法 + + + + Identity + 匿名身份 + + + + Domain + + + + + CA certficate + CA 证书 + + + + no need for CA certificate + 不需要CA证书 + + + + User certificate + 用户证书 + + + + User private key + 用户私钥 + + + + User key password + 用户密钥密码 + + + + Password options + 密码选项 + + + + + + Required + 必填 + + + + Ineer authentication + 内部认证 + + + + Usename + 用户名 + + + Username + Usename + 用户名 + + + + Ask pwd each query + 每次询问密码 + + + + + + + + + + + + None + + + + + WPA&WPA2 Personal + WPA&WPA2 个人 + + + + WPA&WPA2 Enterprise + WPA&WPA2 企业 + + + + WPA3 Personal + WPA3 个人 + + + + + + Choose from file... + 从文件选择... + + + + Store passwords only for this user + 仅为该用户存储密码 + + + + Store password only for this user + 仅为该用户存储密码 + + + + Store passwords for all users + 存储所有用户的密码 + + + + Store password for all users + 存储所有用户的密码 + + + + Ask this password every time + 每次询问这个密码 + + + + Ask password every time + 每次询问这个密码 + + + + + + Choose a CA certificate + 选择一个CA证书 + + + + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + CA 证书 (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + + + + + + + TabPage + + + Current Device + 当前网卡 + + + + Devices Closed! + 设备关闭! + + + + Settings + 网络设置 + + + + Kylin NM + 麒麟网络设置工具 + + + + kylin network applet desktop message + 网络提示消息 + + + + VpnPage + + + Activated VPN + + + + + Inactivated VPN + + + + + Wired Device not carried + 未插入网线 + + + + WiFiConfigDialog + + + Dialog + + + + + WLAN Authentication + + + + + Input WLAN Information Please + + + + + WLAN ID: + + + + + WLAN Name: + + + + + Password: + + + + + Cancl + + + + + Ok + + + + + WlanListItem + + + Not connected + 未连接 + + + + + Disconnect + 断开 + + + + + + Connect + 连接 + + + + + Forget + 忘记此网络 + + + Property + 属性 + + + + Auto Connect + 自动加入该网络 + + + + WlanMoreItem + + More... + 更多... + + + + Add Others... + 加入其他网络... + + + + WlanPage + + + WLAN + 无线局域网 + + + + No wireless network card detected + 未检测到无线网卡 + + + + Activated WLAN + 我的网络 + + + + Other WLAN + 其他网络 + + + More... + 更多... + + + + WLAN Connected Successfully + 无线网络已连接 + + + + WLAN Disconnected Successfully + 无线网络已断开 + + + + WpaWifiDialog + + EAP type + EAP方法 + + + Username + 用户名 + + + Password + 密钥 + + + Ask pwd each query + 每次询问密码 + + + Cancel + 取消 + + + Connect + 连接 + + + None + + + + Choose from file... + 从文件选择... + + + Choose a CA certificate + 选择一个CA证书 + + + CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx) + CA 证书 (*.pem *.der *.p12 *.crt *.cer *.pfx) + + + Identity + 匿名身份 + + + Domain + + + + no need for CA certificate + 不需要CA证书 + + + + main + + + kylinnm + + + + + show kylin-nm wifi page + + + + + show kylin-nm lan page + + + + + vpnMainWindow + + + kylin-vpn + + + + + vpn tool + + + +