Commit aff8fe1a authored by flypig's avatar flypig

[nemo-qml-plugin-systemsettings] Support VPN ordering by connected status. Contributes to JB#45380

This change adds the `orderByConnected` flag to VpnModel which, when
set, will order VPN connections in the model first by the connection
status (connected first, followed by not connected), then by the name
alphabetially ascending (case-sensitive).

When not set, the previous case-sensitive alphabetic name ordering is
used.

The new ordering is used when the MDM policy is set to prevent the user
from manually connecting or disconnecting the VPNs. In this case, the
list of VPNs is presented differently with headers indicating connection
status, rather than indicating it using a TextSwitch glassitem.
parent 72f3ec0e
......@@ -320,6 +320,7 @@ VpnModel::VpnModel(QObject *parent)
, provisioningOutputPath_(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/system/privileged/vpn-provisioning"))
, bestState_(VpnModel::Idle)
, autoConnect_(false)
, orderByConnected_(false)
{
qDBusRegisterMetaType<PathProperties>();
qDBusRegisterMetaType<PathPropertiesArray>();
......@@ -400,6 +401,30 @@ bool VpnModel::autoConnect() const
return autoConnect_;
}
bool VpnModel::orderByConnected() const
{
return orderByConnected_;
}
void VpnModel::setOrderByConnected(bool orderByConnected)
{
if (orderByConnected != orderByConnected_) {
orderByConnected_ = orderByConnected;
// Update the ordering; only the connected connections need to move
// In practice only one VPN can be connected, so full sort is overkill
const int itemCount(count());
for (int index = 0; index < itemCount; ++index) {
VpnConnection *conn = get<VpnConnection>(index);
if (conn->connected()) {
reorderConnection(conn);
}
}
emit orderByConnectedChanged();
}
}
void VpnModel::createConnection(const QVariantMap &createProperties)
{
const QString path(createProperties.value(QString("path")).toString());
......@@ -851,6 +876,7 @@ void VpnModel::updateConnection(VpnConnection *conn, const QVariantMap &updatePr
}
int oldState(conn->state());
bool connectionChanged = false;
if (updateItem(conn, properties)) {
itemChanged(conn);
......@@ -859,6 +885,10 @@ void VpnModel::updateConnection(VpnConnection *conn, const QVariantMap &updatePr
if (conn->state() != oldState) {
emit connectionStateChanged(conn->path(), static_cast<int>(conn->state()));
if ((conn->state() == VpnModel::Ready) != (oldState == VpnModel::Ready)) {
emit conn->connectedChanged();
connectionChanged = true;
}
// Check to see if the best state has changed
ConnectionState maxState = Idle;
......@@ -874,23 +904,14 @@ void VpnModel::updateConnection(VpnConnection *conn, const QVariantMap &updatePr
}
}
// Keep the items sorted by name. So sort only when updateProperties map contains
// a name e.i. not when "autoConnect" changes. In practice this means that sorting
// is only allowed when a VPN is created. When modifying name of a VPN, the VPN
// Keep the items sorted by name and possibly connected status. So sort
// only when the connection status has changed, or the updateProperties
// map contains a name i.e. not when "autoConnect" changes. In practice
// this means that if orderByConnected_ is false then sorting is only
// allowed when a VPN is created. When modifying name of a VPN, the VPN
// will be first removed and then recreated.
if (itemCount > 1 && updateProperties.contains(QStringLiteral("name"))) {
int index = 0;
for ( ; index < itemCount; ++index) {
const VpnConnection *existing = get<VpnConnection>(index);
if (existing->name() > conn->name()) {
break;
}
}
const int currentIndex = indexOf(conn);
if (index != currentIndex && (index - 1) != currentIndex) {
moveItem(currentIndex, (currentIndex < index ? (index - 1) : index));
}
if (updateProperties.contains(QStringLiteral("name")) || (orderByConnected_ && connectionChanged)) {
reorderConnection(conn);
}
}
......@@ -905,6 +926,29 @@ void VpnModel::updateConnection(VpnConnection *conn, const QVariantMap &updatePr
}
}
void VpnModel::reorderConnection(VpnConnection * conn)
{
const int itemCount(count());
if (itemCount > 1) {
int index = 0;
for ( ; index < itemCount; ++index) {
const VpnConnection *existing = get<VpnConnection>(index);
// Scenario 1 orderByConnected == true: order first by connected, second by name
// Scenario 2 orderByConnected == false: order only by name
if ((orderByConnected_ && (existing->connected() < conn->connected()))
|| ((!orderByConnected_ || (existing->connected() == conn->connected()))
&& (existing->name() > conn->name()))) {
break;
}
}
const int currentIndex = indexOf(conn);
if (index != currentIndex && (index - 1) != currentIndex) {
moveItem(currentIndex, (currentIndex < index ? (index - 1) : index));
}
}
}
QVariantMap VpnModel::processOpenVpnProvisioningFile(QFile &provisioningFile)
{
QVariantMap rv;
......
......@@ -52,6 +52,7 @@ class SYSTEMSETTINGS_EXPORT VpnModel : public ObjectListModel
Q_PROPERTY(int bestState READ bestState NOTIFY bestStateChanged)
Q_PROPERTY(bool autoConnect READ autoConnect NOTIFY autoConnectChanged)
Q_PROPERTY(bool orderByConnected READ orderByConnected WRITE setOrderByConnected NOTIFY orderByConnectedChanged)
public:
enum ConnectionState {
......@@ -69,6 +70,9 @@ public:
int bestState() const;
bool autoConnect() const;
bool orderByConnected() const;
void setOrderByConnected(bool orderByConnected);
Q_INVOKABLE void createConnection(const QVariantMap &properties);
Q_INVOKABLE void modifyConnection(const QString &path, const QVariantMap &properties);
Q_INVOKABLE void deleteConnection(const QString &path);
......@@ -92,6 +96,7 @@ signals:
void bestStateChanged();
void autoConnectChanged();
void connectionStateChanged(const QString &path, int state);
void orderByConnectedChanged();
private:
void fetchVpnList();
......@@ -104,6 +109,7 @@ private:
bool domainInUse(const QString &domain) const;
QString createDefaultDomain() const;
bool isDefaultDomain(const QString &domain) const;
void reorderConnection(VpnConnection * conn);
class CredentialsRepository
{
......@@ -135,6 +141,7 @@ private:
ConnectionState bestState_;
// True if there's one VPN that has autoConnect true
bool autoConnect_;
bool orderByConnected_;
};
class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject
......@@ -157,6 +164,7 @@ class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject
Q_PROPERTY(QVariantList userRoutes READ userRoutes WRITE setUserRoutes NOTIFY userRoutesChanged)
Q_PROPERTY(QVariantList serverRoutes READ serverRoutes WRITE setServerRoutes NOTIFY serverRoutesChanged)
Q_PROPERTY(QVariantMap providerProperties READ providerProperties WRITE setProviderProperties NOTIFY providerPropertiesChanged)
Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
public:
VpnConnection(const QString &path);
......@@ -211,6 +219,8 @@ public:
QVariantMap providerProperties() const { return providerProperties_; }
void setProviderProperties(const QVariantMap providerProperties) { updateMember(&VpnConnection::providerProperties_, providerProperties, &VpnConnection::providerPropertiesChanged); }
int connected() const { return state_ == VpnModel::Ready; }
signals:
void nameChanged();
void stateChanged();
......@@ -228,6 +238,7 @@ signals:
void userRoutesChanged();
void serverRoutesChanged();
void providerPropertiesChanged();
void connectedChanged();
private:
template<typename T, typename V>
......
Markdown is supported
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