Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[nemo-qml-plugin-systemsettings] Support VPN ordering by connected st…
…atus. 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.
  • Loading branch information
llewelld committed Jun 3, 2019
1 parent 72f3ec0 commit aff8fe1
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 16 deletions.
76 changes: 60 additions & 16 deletions src/vpnmodel.cpp
Expand Up @@ -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>();
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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);
}
}

Expand All @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions src/vpnmodel.h
Expand Up @@ -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 {
Expand All @@ -69,6 +70,9 @@ class SYSTEMSETTINGS_EXPORT VpnModel : public ObjectListModel
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);
Expand All @@ -92,6 +96,7 @@ class SYSTEMSETTINGS_EXPORT VpnModel : public ObjectListModel
void bestStateChanged();
void autoConnectChanged();
void connectionStateChanged(const QString &path, int state);
void orderByConnectedChanged();

private:
void fetchVpnList();
Expand All @@ -104,6 +109,7 @@ class SYSTEMSETTINGS_EXPORT VpnModel : public ObjectListModel
bool domainInUse(const QString &domain) const;
QString createDefaultDomain() const;
bool isDefaultDomain(const QString &domain) const;
void reorderConnection(VpnConnection * conn);

class CredentialsRepository
{
Expand Down Expand Up @@ -135,6 +141,7 @@ class SYSTEMSETTINGS_EXPORT VpnModel : public ObjectListModel
ConnectionState bestState_;
// True if there's one VPN that has autoConnect true
bool autoConnect_;
bool orderByConnected_;
};

class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject
Expand All @@ -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);
Expand Down Expand Up @@ -211,6 +219,8 @@ class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject
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();
Expand All @@ -228,6 +238,7 @@ class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject
void userRoutesChanged();
void serverRoutesChanged();
void providerPropertiesChanged();
void connectedChanged();

private:
template<typename T, typename V>
Expand Down

0 comments on commit aff8fe1

Please sign in to comment.