diff --git a/src/vpnmodel.cpp b/src/vpnmodel.cpp index 0c0232b..06b6070 100644 --- a/src/vpnmodel.cpp +++ b/src/vpnmodel.cpp @@ -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(); qDBusRegisterMetaType(); @@ -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(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(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(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(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; diff --git a/src/vpnmodel.h b/src/vpnmodel.h index 2fa08a9..7c24d89 100644 --- a/src/vpnmodel.h +++ b/src/vpnmodel.h @@ -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 @@ 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); @@ -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(); @@ -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 { @@ -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 @@ -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 @@ 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(); @@ -228,6 +238,7 @@ class SYSTEMSETTINGS_EXPORT VpnConnection : public QObject void userRoutesChanged(); void serverRoutesChanged(); void providerPropertiesChanged(); + void connectedChanged(); private: template