Verified Commit 575e9e91 authored by ivan tkachenko's avatar ivan tkachenko
Browse files

applet: Fix delayModelUpdates mode

The delayModelUpdates write-only property was a workaround, but it
didn't even work properly especially with multiple delegates
(writers) per single shared variable. This patch promotes the concept
into a model role, and turns the model's shared property into readonly
aggregated state. This should fix most of the cases when a connection
would suddenly teleport away or even replaced with another while typing
in password.

BUG: 389052
(cherry picked from commit 9e5cdc3e)
parent d83674e5
......@@ -229,7 +229,7 @@ PlasmaExtras.ExpandableListItem {
Component.onCompleted: {
passwordField.forceActiveFocus()
full.connectionModel.delayModelUpdates = true
setDelayModelUpdates(true)
}
}
}
......@@ -275,7 +275,7 @@ PlasmaExtras.ExpandableListItem {
handler.deactivateConnection(ConnectionPath, DevicePath)
}
} else if (predictableWirelessPassword) {
full.connectionModel.delayModelUpdates = true
setDelayModelUpdates(true)
connectionItem.customExpandedViewContent = passwordDialogComponent
connectionItem.expand()
}
......@@ -309,6 +309,10 @@ PlasmaExtras.ExpandableListItem {
return ""
}
function setDelayModelUpdates(delay: bool) {
appletProxyModel.setData(appletProxyModel.index(index, 0), delay, PlasmaNM.NetworkModel.DelayModelUpdatesRole);
}
onShowSpeedChanged: {
connectionModel.setDeviceStatisticsRefreshRateMs(DevicePath, showSpeed ? 2000 : 0)
}
......@@ -335,12 +339,6 @@ PlasmaExtras.ExpandableListItem {
onItemCollapsed: {
connectionItem.customExpandedViewContent = detailsComponent;
full.connectionModel.delayModelUpdates = false;
}
Component.onDestruction: {
if ( full != null && full.connectionModel != null) {
full.connectionModel.delayModelUpdates = false;
}
setDelayModelUpdates(false);
}
}
......@@ -16,6 +16,9 @@ Item {
readonly property string kcm: "kcm_networkmanagement"
readonly property bool kcmAuthorized: KCMShell.authorize("kcm_networkmanagement.desktop").length == 1
readonly property bool delayModelUpdates: Plasmoid.fullRepresentationItem !== null
&& Plasmoid.fullRepresentationItem.connectionModel !== null
&& Plasmoid.fullRepresentationItem.connectionModel.delayModelUpdates
Plasmoid.toolTipMainText: i18n("Networks")
Plasmoid.toolTipSubText: networkStatus.activeConnections
......@@ -66,7 +69,7 @@ Item {
id: scanTimer
interval: 10200
repeat: true
running: plasmoid.expanded && !PlasmaNM.Configuration.airplaneModeEnabled
running: plasmoid.expanded && !PlasmaNM.Configuration.airplaneModeEnabled && !mainWindow.delayModelUpdates
onTriggered: handler.requestScan()
}
......
......@@ -9,6 +9,8 @@
#include "networkmodelitem.h"
#include "plasma_nm_libs.h"
#include "uiutils.h"
#include <QVector>
#include <algorithm>
#if WITH_MODEMMANAGER_SUPPORT
#include <ModemManagerQt/Manager>
......@@ -93,6 +95,8 @@ QVariant NetworkModel::data(const QModelIndex &index, int role) const
return item->rxBytes();
case TxBytesRole:
return item->txBytes();
case DelayModelUpdatesRole:
return item->delayModelUpdates();
default:
break;
}
......@@ -101,6 +105,23 @@ QVariant NetworkModel::data(const QModelIndex &index, int role) const
return {};
}
bool NetworkModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
const int row = index.row();
const bool delay = value.toBool();
if (row >= 0 && row < m_list.count() && role == DelayModelUpdatesRole) {
NetworkModelItem *item = m_list.itemAt(row);
if (item->delayModelUpdates() != delay) {
item->setDelayModelUpdates(delay);
dataChanged(index, index, QVector<int>{DelayModelUpdatesRole});
updateDelayModelUpdates();
return true;
}
}
return false;
}
int NetworkModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
......@@ -138,25 +159,42 @@ QHash<int, QByteArray> NetworkModel::roleNames() const
roles[VpnType] = "VpnType";
roles[RxBytesRole] = "RxBytes";
roles[TxBytesRole] = "TxBytes";
roles[DelayModelUpdatesRole] = "DelayModelUpdates";
return roles;
}
void NetworkModel::setDelayModelUpdates(bool delayUpdates)
bool NetworkModel::delayModelUpdates() const
{
m_delayModelUpdates = delayUpdates;
// Process queue
if (!delayUpdates) {
while (!m_updateQueue.isEmpty()) {
QPair<NetworkModel::ModelChangeType, NetworkModelItem *> update = m_updateQueue.dequeue();
if (update.first == ItemAdded) {
insertItem(update.second);
} else if (update.first == ItemRemoved) {
removeItem(update.second);
} else if (update.first == ItemPropertyChanged) {
updateItem(update.second);
}
return m_delayModelUpdates;
}
void NetworkModel::updateDelayModelUpdates()
{
const QList<NetworkModelItem *> items = m_list.items();
const bool delay = std::any_of(items.begin(), items.end(), [](NetworkModelItem *item) -> bool {
return item->delayModelUpdates();
});
if (m_delayModelUpdates != delay) {
m_delayModelUpdates = delay;
Q_EMIT delayModelUpdatesChanged();
if (!m_delayModelUpdates) {
flushUpdateQueue();
}
}
}
void NetworkModel::flushUpdateQueue()
{
while (!m_updateQueue.isEmpty()) {
QPair<NetworkModel::ModelChangeType, NetworkModelItem *> update = m_updateQueue.dequeue();
if (update.first == ItemAdded) {
insertItem(update.second);
} else if (update.first == ItemRemoved) {
removeItem(update.second);
} else if (update.first == ItemPropertyChanged) {
updateItem(update.second);
}
}
}
......@@ -595,6 +633,7 @@ void NetworkModel::insertItem(NetworkModelItem *item)
beginInsertRows(QModelIndex(), index, index);
m_list.insertItem(item);
endInsertRows();
updateDelayModelUpdates();
}
void NetworkModel::removeItem(NetworkModelItem *item)
......@@ -605,11 +644,12 @@ void NetworkModel::removeItem(NetworkModelItem *item)
}
const int row = m_list.indexOf(item);
if (row >= 0) {
if (row != -1) {
beginRemoveRows(QModelIndex(), row, row);
m_list.removeItem(item);
item->deleteLater();
endRemoveRows();
updateDelayModelUpdates();
}
}
......@@ -621,12 +661,12 @@ void NetworkModel::updateItem(NetworkModelItem *item)
}
const int row = m_list.indexOf(item);
if (row >= 0) {
if (row != -1) {
item->invalidateDetails();
QModelIndex index = createIndex(row, 0);
Q_EMIT dataChanged(index, index, item->changedRoles());
item->clearChangedRoles();
updateDelayModelUpdates();
}
}
......
......@@ -25,9 +25,10 @@ class Q_DECL_EXPORT NetworkModel : public QAbstractListModel
{
Q_OBJECT
public:
// HACK: Delay model updates to prevent jumping password entry in the applet
// BUG: 435430
Q_PROPERTY(bool delayModelUpdates WRITE setDelayModelUpdates)
// Delay model updates to prevent jumping password entry in the applet.
// This is an aggregate property, which is true whenever any of model items is true.
// BUG: 435430, 389052
Q_PROPERTY(bool delayModelUpdates READ delayModelUpdates NOTIFY delayModelUpdatesChanged)
explicit NetworkModel(QObject *parent = nullptr);
~NetworkModel() override;
......@@ -61,6 +62,8 @@ public:
VpnType,
RxBytesRole,
TxBytesRole,
// writable roles
DelayModelUpdatesRole,
};
Q_ENUMS(ItemRole)
......@@ -68,8 +71,13 @@ public:
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
QHash<int, QByteArray> roleNames() const override;
void setDelayModelUpdates(bool delayUpdates);
bool delayModelUpdates() const;
Q_SIGNALS:
void delayModelUpdatesChanged();
public Q_SLOTS:
void onItemUpdated();
......@@ -122,6 +130,8 @@ private:
void initializeSignals(const NetworkManager::WirelessNetwork::Ptr &network);
void
updateFromWirelessNetwork(NetworkModelItem *item, const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device);
void updateDelayModelUpdates();
void flushUpdateQueue();
void insertItem(NetworkModelItem *item);
void removeItem(NetworkModelItem *item);
......
......@@ -39,6 +39,7 @@ NetworkModelItem::NetworkModelItem(QObject *parent)
, m_connectionState(NetworkManager::ActiveConnection::Deactivated)
, m_deviceState(NetworkManager::Device::UnknownState)
, m_detailsValid(false)
, m_delayModelUpdates(false)
, m_duplicate(false)
, m_mode(NetworkManager::WirelessSetting::Infrastructure)
, m_securityType(NetworkManager::NoneSecurity)
......@@ -56,6 +57,7 @@ NetworkModelItem::NetworkModelItem(const NetworkModelItem *item, QObject *parent
, m_connectionPath(item->connectionPath())
, m_connectionState(NetworkManager::ActiveConnection::Deactivated)
, m_detailsValid(false)
, m_delayModelUpdates(item->delayModelUpdates())
, m_duplicate(true)
, m_mode(item->mode())
, m_name(item->name())
......@@ -490,6 +492,17 @@ void NetworkModelItem::setTxBytes(qulonglong bytes)
}
}
bool NetworkModelItem::delayModelUpdates() const
{
return m_delayModelUpdates;
}
void NetworkModelItem::setDelayModelUpdates(bool delay)
{
// special case, does not need m_changedRoles
m_delayModelUpdates = delay;
}
bool NetworkModelItem::operator==(const NetworkModelItem *item) const
{
if (!item->uuid().isEmpty() && !uuid().isEmpty()) {
......
......@@ -103,6 +103,9 @@ public:
qulonglong txBytes() const;
void setTxBytes(qulonglong bytes);
bool delayModelUpdates() const;
void setDelayModelUpdates(bool delay);
bool operator==(const NetworkModelItem *item) const;
QVector<int> changedRoles() const
......@@ -130,6 +133,7 @@ private:
NetworkManager::Device::State m_deviceState;
mutable QStringList m_details;
mutable bool m_detailsValid;
bool m_delayModelUpdates;
bool m_duplicate;
NetworkManager::WirelessSetting::NetworkMode m_mode;
QString m_name;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment