dde-dock/plugins/network/item/applet/wirelesslist.cpp

454 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
*
* 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
* 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 <http://www.gnu.org/licenses/>.
*/
#include "wirelesslist.h"
#include "accesspointwidget.h"
#include <QJsonDocument>
#include <QScreen>
#include <QDebug>
#include <QGuiApplication>
#include <dinputdialog.h>
#include <QScrollBar>
#include <DDBusSender>
DWIDGET_USE_NAMESPACE
using namespace dde::network;
#define WIDTH 300
#define MAX_HEIGHT 300
#define ITEM_HEIGHT 30
WirelessList::WirelessList(WirelessDevice *deviceIter, QWidget *parent)
: QScrollArea(parent),
m_device(deviceIter),
m_activeAP(),
m_updateAPTimer(new QTimer(this)),
m_centralLayout(new QVBoxLayout),
m_centralWidget(new QWidget),
m_controlPanel(new DeviceControlWidget)
{
setFixedHeight(WIDTH);
const auto ratio = qApp->devicePixelRatio();
QPixmap iconPix = QIcon::fromTheme("notification-network-wireless-full").pixmap(QSize(48, 48) * ratio);
iconPix.setDevicePixelRatio(ratio);
m_updateAPTimer->setSingleShot(true);
m_updateAPTimer->setInterval(100);
m_centralWidget->setFixedWidth(WIDTH);
m_centralWidget->setLayout(m_centralLayout);
m_centralLayout->addWidget(m_controlPanel);
m_centralLayout->setSpacing(0);
m_centralLayout->setMargin(0);
setWidget(m_centralWidget);
setFrameStyle(QFrame::NoFrame);
setFixedWidth(300);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setStyleSheet("background-color:transparent;");
m_indicator = new DPictureSequenceView(this);
m_indicator->setPictureSequence(":/wireless/indicator/resources/wireless/spinner14/Spinner%1.png", QPair<int, int>(1, 91), 2);
m_indicator->setFixedSize(QSize(14, 14) * ratio);
m_indicator->setVisible(false);
connect(m_device, &WirelessDevice::apAdded, this, &WirelessList::APAdded);
connect(m_device, &WirelessDevice::apRemoved, this, &WirelessList::APRemoved);
connect(m_device, &WirelessDevice::apInfoChanged, this, &WirelessList::APPropertiesChanged);
connect(m_device, &WirelessDevice::enableChanged, this, &WirelessList::onDeviceEnableChanged);
connect(m_device, &WirelessDevice::activateAccessPointFailed, this, &WirelessList::onActivateApFailed);
connect(m_controlPanel, &DeviceControlWidget::enableButtonToggled, this, &WirelessList::onEnableButtonToggle);
connect(m_controlPanel, &DeviceControlWidget::requestRefresh, this, &WirelessList::requestWirelessScan);
connect(m_updateAPTimer, &QTimer::timeout, this, &WirelessList::updateAPList);
connect(m_device, &WirelessDevice::activeWirelessConnectionInfoChanged, this, &WirelessList::onActiveConnectionInfoChanged);
connect(m_device, static_cast<void (WirelessDevice:: *) (NetworkDevice::DeviceStatus stat) const>(&WirelessDevice::statusChanged), m_updateAPTimer, static_cast<void (QTimer::*)()>(&QTimer::start));
connect(m_device, &WirelessDevice::activeConnectionsChanged, this, &WirelessList::updateIndicatorPos, Qt::QueuedConnection);
connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, [=] {
auto apw = accessPointWidgetByAp(m_activatingAP);
if (!apw) return;
const int h = -(apw->height() - m_indicator->height()) / 2;
m_indicator->move(apw->mapTo(this, apw->rect().topRight()) - QPoint(35, h));
});
QMetaObject::invokeMethod(this, "loadAPList", Qt::QueuedConnection);
}
WirelessList::~WirelessList()
{
}
QWidget *WirelessList::controlPanel()
{
return m_controlPanel;
}
void WirelessList::APAdded(const QJsonObject &apInfo)
{
AccessPoint ap(apInfo);
const auto mIndex = m_apList.indexOf(ap);
if (mIndex != -1) {
if (ap > m_apList.at(mIndex)) {
m_apList.replace(mIndex, ap);
} else {
return;
}
} else {
m_apList.append(ap);
}
m_updateAPTimer->start();
}
void WirelessList::APRemoved(const QJsonObject &apInfo)
{
AccessPoint ap(apInfo);
const auto mIndex = m_apList.indexOf(ap);
if (mIndex != -1) {
if (ap.path() == m_apList.at(mIndex).path()) {
m_apList.removeAt(mIndex);
m_updateAPTimer->start();
}
}
}
void WirelessList::setDeviceInfo(const int index)
{
if (m_device.isNull()) {
return;
}
// set device enable state
m_controlPanel->setDeviceEnabled(m_device->enabled());
// set device name
if (index == -1)
m_controlPanel->setDeviceName(tr("Wireless Network"));
else
m_controlPanel->setDeviceName(tr("Wireless Network %1").arg(index));
}
void WirelessList::loadAPList()
{
if (m_device.isNull()) {
return;
}
for (auto item : m_device->apList()) {
AccessPoint ap(item.toObject());
const auto mIndex = m_apList.indexOf(ap);
if (mIndex != -1) {
// indexOf() will use AccessPoint reimplemented function "operator==" as comparison condition
// this means that the ssid of the AP is a comparison condition
if (ap > m_apList.at(mIndex)) {
m_apList.replace(mIndex, ap);
}
} else {
m_apList.append(ap);
}
}
m_updateAPTimer->start();
}
void WirelessList::APPropertiesChanged(const QJsonObject &apInfo)
{
AccessPoint ap(apInfo);
const auto mIndex = m_apList.indexOf(ap);
if (mIndex != -1) {
if (ap > m_apList.at(mIndex)) {
m_apList.replace(mIndex, ap);
m_updateAPTimer->start();
}
}
}
void WirelessList::updateAPList()
{
Q_ASSERT(sender() == m_updateAPTimer);
if (m_device.isNull()) {
return;
}
int avaliableAPCount = 0;
//if (m_networkInter->IsDeviceEnabled(m_device.dbusPath()))
if (m_device->enabled())
{
// sort ap list by strength
// std::sort(m_apList.begin(), m_apList.end(), std::greater<AccessPoint>());
// const bool wirelessActived = m_device.state() == NetworkDevice::Activated;
// NOTE: Keep the amount consistent
if(m_apList.size() > m_apwList.size()) {
int i = m_apList.size() - m_apwList.size();
for (int index = 0; index != i; index++) {
AccessPointWidget *apw = new AccessPointWidget;
apw->setFixedHeight(ITEM_HEIGHT);
m_apwList << apw;
m_centralLayout->addWidget(apw);
connect(apw, &AccessPointWidget::requestActiveAP, this, &WirelessList::activateAP);
connect(apw, &AccessPointWidget::requestDeactiveAP, this, &WirelessList::deactiveAP);
connect(apw, &AccessPointWidget::requestActiveAP, this, [=] {
m_clickedAPW = apw;
}, Qt::UniqueConnection);
}
} else if (m_apList.size() < m_apwList.size()) {
if (!m_apwList.isEmpty()) {
int i = m_apwList.size() - m_apList.size();
for (int index = 0; index != i; index++) {
AccessPointWidget *apw = m_apwList.last();
m_apwList.removeLast();
m_centralLayout->removeWidget(apw);
apw->deleteLater();
}
}
}
std::sort(m_apList.begin(), m_apList.end(), [&] (const AccessPoint &ap1, const AccessPoint &ap2) {
if (ap1 == m_activeAP)
return true;
if (ap2 == m_activeAP)
return false;
return ap1.strength() > ap2.strength();
});
// update the content of AccessPointWidget by the order of ApList
for (int i = 0; i != m_apList.size(); i++) {
m_apwList[i]->updateAP(m_apList[i]);
++avaliableAPCount;
}
// update active AP state
NetworkDevice::DeviceStatus deviceStatus = m_device->status();
if (!m_apwList.isEmpty()) {
AccessPointWidget *apw = m_apwList.first();
apw->setActiveState(deviceStatus);
}
// If the order of item changes
if (m_indicator->isVisible() && !m_activatingAP.isEmpty() && m_apList.contains(m_activatingAP)) {
AccessPointWidget *apw = accessPointWidgetByAp(m_activatingAP);
if (apw) {
const int h = -(apw->height() - m_indicator->height()) / 2;
m_indicator->move(apw->mapTo(this, apw->rect().topRight()) - QPoint(35, h));
}
}
if (deviceStatus <= NetworkDevice::Disconnected || deviceStatus >= NetworkDevice::Activated) {
m_indicator->stop();
m_indicator->hide();
}
}
const int contentHeight = avaliableAPCount * ITEM_HEIGHT;
m_centralWidget->setFixedHeight(contentHeight);
setFixedHeight(std::min(contentHeight, MAX_HEIGHT));
}
void WirelessList::onEnableButtonToggle(const bool enable)
{
if (m_device.isNull()) {
return;
}
Q_EMIT requestSetDeviceEnable(m_device->path(), enable);
m_updateAPTimer->start();
}
void WirelessList::onDeviceEnableChanged(const bool enable)
{
m_controlPanel->setDeviceEnabled(enable);
m_updateAPTimer->start();
}
void WirelessList::activateAP(const QString &apPath, const QString &ssid)
{
if (m_device.isNull()) {
return;
}
QString uuid;
QList<QJsonObject> connections = m_device->connections();
for (auto item : connections) {
if (item.value("Ssid").toString() != ssid)
continue;
uuid = item.value("Uuid").toString();
if (!uuid.isEmpty())
break;
}
Q_EMIT requestActiveAP(m_device->path(), apPath, uuid);
}
void WirelessList::deactiveAP()
{
if (m_device.isNull()) {
return;
}
Q_EMIT requestDeactiveAP(m_device->path());
}
void WirelessList::updateIndicatorPos()
{
QString activeSsid;
for (auto activeConnObj : m_device->activeConnections()) {
if (activeConnObj.value("Vpn").toBool(false)) {
continue;
}
// the State of Active Connection
// 0:Unknow, 1:Activating, 2:Activated, 3:Deactivating, 4:Deactivated
if (activeConnObj.value("State").toInt(0) != 1) {
break;
}
activeSsid = activeConnObj.value("Id").toString();
break;
}
// if current is not activating wireless this will make m_activatingAP empty
m_activatingAP = accessPointBySsid(activeSsid);
AccessPointWidget *apw = accessPointWidgetByAp(m_activatingAP);
if (activeSsid.isEmpty() || m_activatingAP.isEmpty() || !apw) {
m_indicator->hide();
return;
}
const int h = -(apw->height() - m_indicator->height()) / 2;
m_indicator->move(apw->mapTo(this, apw->rect().topRight()) - QPoint(35, h));
m_indicator->show();
m_indicator->play();
}
void WirelessList::onActiveConnectionInfoChanged()
{
if (m_device.isNull()) {
return;
}
// 在这个方法中需要通过m_device->activeApSsid()的信息设置m_activeAP的值
// m_activeAP的值应该从m_apList中拿到但在程序第一次启动后当后端扫描无线网的数据还没有发过来
// 这时m_device中的ap list为空导致本类初始化时调用loadAPList()后m_apList也是空的
// 那么也就无法给m_activeAP正确的值所以在这里使用timer等待一下后端的数据再执行遍历m_apList给m_activeAP赋值的操作
if (m_device->enabled() && m_device->status() == NetworkDevice::Activated
&& m_apList.size() == 0) {
QTimer::singleShot(1000, [=]{onActiveConnectionInfoChanged();});
return;
}
for (int i = 0; i < m_apList.size(); ++i) {
if (m_apList.at(i).ssid() == m_device->activeApSsid()) {
m_activeAP = m_apList.at(i);
m_updateAPTimer->start();
break;
}
}
}
void WirelessList::onActivateApFailed(const QString &apPath, const QString &uuid)
{
if (m_device.isNull() && !m_clickedAPW) {
return;
}
AccessPoint clickedAP = m_clickedAPW->ap();
if (clickedAP.isEmpty()) {
return;
}
if (clickedAP.path() == apPath) {
qDebug() << "wireless connect failed and may require more configuration,"
<< "path:" << clickedAP.path() << "ssid" << clickedAP.ssid()
<< "secret:" << clickedAP.secured() << "strength" << clickedAP.strength();
m_updateAPTimer->start();
m_editConnectionData = {};
m_editConnectionData.insert("conn-type", "wireless");
m_editConnectionData.insert("device-path", QJsonValue(m_device->path()));
m_editConnectionData.insert("conn-uuid", QJsonValue(uuid));
m_editConnectionData.insert("ap-path", QJsonValue(apPath));
DDBusSender()
.service("com.deepin.dde.ControlCenter")
.interface("com.deepin.dde.ControlCenter")
.path("/com/deepin/dde/ControlCenter")
.method("ShowPage")
.arg(QString("network"))
.arg(QString(QJsonDocument(m_editConnectionData).toJson()))
.call();
Q_EMIT requestSetAppletVisible(false);
}
}
AccessPoint WirelessList::accessPointBySsid(const QString &ssid)
{
if (ssid.isEmpty()) {
return AccessPoint();
}
for (auto ap : m_apList) {
if (ap.ssid() == ssid) {
return ap;
}
}
return AccessPoint();
}
AccessPointWidget *WirelessList::accessPointWidgetByAp(const AccessPoint ap)
{
if (ap.isEmpty()) {
return nullptr;
}
for (auto apw : m_apwList) {
if (apw->ap().path() == ap.path()) {
return apw;
}
}
return nullptr;
}