Skip to content

Commit

Permalink
Merge branch 'jb49822_intermediate_states' into 'master'
Browse files Browse the repository at this point in the history
[nemo-systemsettings] Add transitioning property to UserModel. JB#49822

See merge request mer-core/nemo-qml-plugin-systemsettings!145
  • Loading branch information
Tomin1 committed May 27, 2020
2 parents c6e14bf + 5d8fc0a commit 829e7fc
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 40 deletions.
120 changes: 86 additions & 34 deletions src/usermodel.cpp
Expand Up @@ -57,6 +57,7 @@ const QHash<const QString, int> errorTypeMap = {
{ QStringLiteral(SailfishUserManagerErrorHomeRemoveFailed), UserModel::HomeRemoveFailed },
{ QStringLiteral(SailfishUserManagerErrorGroupCreateFailed), UserModel::GroupCreateFailed },
{ QStringLiteral(SailfishUserManagerErrorUserAddFailed), UserModel::UserAddFailed },
{ QStringLiteral(SailfishUserManagerErrorMaxUsersReached), UserModel::MaximumNumberOfUsersReached },
{ QStringLiteral(SailfishUserManagerErrorUserModifyFailed), UserModel::UserModifyFailed },
{ QStringLiteral(SailfishUserManagerErrorUserRemoveFailed), UserModel::UserRemoveFailed },
{ QStringLiteral(SailfishUserManagerErrorGetUidFailed), UserModel::GetUidFailed },
Expand Down Expand Up @@ -106,7 +107,7 @@ UserModel::~UserModel()
{
}

bool UserModel::placeholder()
bool UserModel::placeholder() const
{
// Placeholder is always last and the only item that can be invalid
if (m_users.count() == 0)
Expand All @@ -133,6 +134,27 @@ void UserModel::setPlaceholder(bool value)
emit placeholderChanged();
}

/*
* Number of existing users
*
* If placeholder = false, then this is the same as rowCount.
*/
int UserModel::count() const
{
return (placeholder()) ? m_users.count()-1 : m_users.count();
}

/*
* Maximum number of users that can be created
*
* If more users are created after count reaches this,
* MaximumNumberOfUsersReached may be thrown and user creation fails.
*/
int UserModel::maximumCount() const
{
return SAILFISH_USERMANAGER_MAX_USERS;
}

QHash<int, QByteArray> UserModel::roleNames() const
{
static const QHash<int, QByteArray> roles = {
Expand All @@ -143,6 +165,7 @@ QHash<int, QByteArray> UserModel::roleNames() const
{ UidRole, "uid" },
{ CurrentRole, "current" },
{ PlaceholderRole, "placeholder" },
{ TransitioningRole, "transitioning" },
};
return roles;
}
Expand Down Expand Up @@ -174,6 +197,8 @@ QVariant UserModel::data(const QModelIndex &index, int role) const
return user.current();
case PlaceholderRole:
return !user.isValid();
case TransitioningRole:
return m_transitioning.contains(user.uid());
default:
return QVariant();
}
Expand All @@ -196,7 +221,7 @@ bool UserModel::setData(const QModelIndex &index, const QVariant &value, int rol
auto call = m_dBusInterface->asyncCall(QStringLiteral("modifyUser"), (uint)user.uid(), name);
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, std::bind(&UserModel::userModifyFinished, this, std::placeholders::_1, index.row()));
this, std::bind(&UserModel::userModifyFinished, this, std::placeholders::_1, user.uid()));
}
emit dataChanged(index, index, QVector<int>() << role);
return true;
Expand All @@ -207,6 +232,7 @@ bool UserModel::setData(const QModelIndex &index, const QVariant &value, int rol
case UidRole:
case CurrentRole:
case PlaceholderRole:
case TransitioningRole:
default:
return false;
}
Expand All @@ -218,7 +244,6 @@ QModelIndex UserModel::index(int row, int column, const QModelIndex &parent) con
if (row < 0 || row >= m_users.count() || column != 0)
return QModelIndex();

// create index
return createIndex(row, 0, row);
}

Expand All @@ -236,6 +261,9 @@ void UserModel::createUser()
if (user.name().isEmpty())
return;

m_transitioning.insert(user.uid());
auto idx = index(m_users.count()-1, 0);
emit dataChanged(idx, idx, QVector<int>() << TransitioningRole);
createInterface();
auto call = m_dBusInterface->asyncCall(QStringLiteral("addUser"), user.name());
auto *watcher = new QDBusPendingCallWatcher(call, this);
Expand All @@ -252,11 +280,14 @@ void UserModel::removeUser(int row)
if (!user.isValid())
return;

m_transitioning.insert(user.uid());
auto idx = index(row, 0);
emit dataChanged(idx, idx, QVector<int>() << TransitioningRole);
createInterface();
auto call = m_dBusInterface->asyncCall(QStringLiteral("removeUser"), (uint)user.uid());
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, std::bind(&UserModel::userRemoveFinished, this, std::placeholders::_1, row));
this, std::bind(&UserModel::userRemoveFinished, this, std::placeholders::_1, user.uid()));
}

void UserModel::setCurrentUser(int row)
Expand All @@ -272,7 +303,7 @@ void UserModel::setCurrentUser(int row)
auto call = m_dBusInterface->asyncCall(QStringLiteral("setCurrentUser"), (uint)user.uid());
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, std::bind(&UserModel::setCurrentUserFinished, this, std::placeholders::_1, row));
this, std::bind(&UserModel::setCurrentUserFinished, this, std::placeholders::_1, user.uid()));
}

void UserModel::reset(int row)
Expand Down Expand Up @@ -315,7 +346,7 @@ void UserModel::addGroups(int row, const QStringList &groups)
auto call = m_dBusInterface->asyncCall(QStringLiteral("addToGroups"), (uint)user.uid(), groups);
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, std::bind(&UserModel::addToGroupsFinished, this, std::placeholders::_1, row));
this, std::bind(&UserModel::addToGroupsFinished, this, std::placeholders::_1, user.uid()));
}

void UserModel::removeGroups(int row, const QStringList &groups)
Expand All @@ -331,7 +362,7 @@ void UserModel::removeGroups(int row, const QStringList &groups)
auto call = m_dBusInterface->asyncCall(QStringLiteral("removeFromGroups"), (uint)user.uid(), groups);
auto *watcher = new QDBusPendingCallWatcher(call, this);
connect(watcher, &QDBusPendingCallWatcher::finished,
this, std::bind(&UserModel::removeFromGroupsFinished, this, std::placeholders::_1, row));
this, std::bind(&UserModel::removeFromGroupsFinished, this, std::placeholders::_1, user.uid()));
}

void UserModel::onUserAdded(const SailfishUserManagerEntry &entry)
Expand All @@ -341,13 +372,8 @@ void UserModel::onUserAdded(const SailfishUserManagerEntry &entry)

// Not found already, appending
auto user = UserInfo(entry.uid);
if (user.isValid()) {
int row = placeholder() ? m_users.count()-1 : m_users.count();
beginInsertRows(QModelIndex(), row, row);
m_users.insert(row, user);
m_uidsToRows.insert(entry.uid, row);
endInsertRows();
}
if (user.isValid())
add(user);
}

void UserModel::onUserModified(uint uid, const QString &newName)
Expand All @@ -371,6 +397,7 @@ void UserModel::onUserRemoved(uint uid)

int row = m_uidsToRows.value(uid);
beginRemoveRows(QModelIndex(), row, row);
m_transitioning.remove(uid);
m_users.remove(row);
// It is slightly costly to remove users since some row numbers may need to be updated
m_uidsToRows.remove(uid);
Expand All @@ -379,6 +406,7 @@ void UserModel::onUserRemoved(uint uid)
iter.value() -= 1;
}
endRemoveRows();
emit countChanged();
}

void UserModel::onCurrentUserChanged(uint uid)
Expand All @@ -400,8 +428,7 @@ void UserModel::onCurrentUserChanged(uint uid)
void UserModel::onCurrentUserChangeFailed(uint uid)
{
if (m_uidsToRows.contains(uid)) {
int row = m_uidsToRows.value(uid);
emit setCurrentUserFailed(row, Failure);
emit setCurrentUserFailed(m_uidsToRows.value(uid), Failure);
}
}

Expand All @@ -416,23 +443,18 @@ void UserModel::userAddFinished(QDBusPendingCallWatcher *call)
uint uid = reply.value();
// Check that this was not just added to the list by onUserAdded
if (!m_uidsToRows.contains(uid)) {
// Add to the end
int row = m_users.count()-1;
beginInsertRows(QModelIndex(), row, row);
m_users.insert(row, UserInfo(uid));
m_uidsToRows.insert(uid, row);
endInsertRows();
UserInfo user(uid);
add(user);
}
// Reset placeholder
reset(m_users.count()-1);
}
call->deleteLater();
}

void UserModel::userModifyFinished(QDBusPendingCallWatcher *call, int row)
void UserModel::userModifyFinished(QDBusPendingCallWatcher *call, uint uid)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
int row = m_uidsToRows.value(uid);
auto error = reply.error();
emit userModifyFailed(row, getErrorType(error));
qCWarning(lcUsersLog) << "Modifying user with usermanager failed:" << error;
Expand All @@ -441,50 +463,54 @@ void UserModel::userModifyFinished(QDBusPendingCallWatcher *call, int row)
call->deleteLater();
}

void UserModel::userRemoveFinished(QDBusPendingCallWatcher *call, int row)
void UserModel::userRemoveFinished(QDBusPendingCallWatcher *call, uint uid)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
int row = m_uidsToRows.value(uid);
auto error = reply.error();
emit userRemoveFailed(row, getErrorType(error));
qCWarning(lcUsersLog) << "Removing user with usermanager failed:" << error;
m_transitioning.remove(uid);
auto idx = index(row, 0);
emit dataChanged(idx, idx, QVector<int>() << TransitioningRole);
} // else awesome! (waiting for signal to alter data)
call->deleteLater();
}

void UserModel::setCurrentUserFinished(QDBusPendingCallWatcher *call, int row)
void UserModel::setCurrentUserFinished(QDBusPendingCallWatcher *call, uint uid)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
auto error = reply.error();
emit setCurrentUserFailed(row, getErrorType(error));
emit setCurrentUserFailed(m_uidsToRows.value(uid), getErrorType(error));
qCWarning(lcUsersLog) << "Switching user with usermanager failed:" << error;
} // else user switching was initiated successfully
call->deleteLater();
}

void UserModel::addToGroupsFinished(QDBusPendingCallWatcher *call, int row)
void UserModel::addToGroupsFinished(QDBusPendingCallWatcher *call, uint uid)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
auto error = reply.error();
emit addGroupsFailed(row, getErrorType(error));
emit addGroupsFailed(m_uidsToRows.value(uid), getErrorType(error));
qCWarning(lcUsersLog) << "Adding user to groups failed:" << error;
} else {
emit userGroupsChanged(row);
emit userGroupsChanged(m_uidsToRows.value(uid));
}
call->deleteLater();
}

void UserModel::removeFromGroupsFinished(QDBusPendingCallWatcher *call, int row)
void UserModel::removeFromGroupsFinished(QDBusPendingCallWatcher *call, uint uid)
{
QDBusPendingReply<void> reply = *call;
if (reply.isError()) {
auto error = reply.error();
emit removeGroupsFailed(row, getErrorType(error));
emit removeGroupsFailed(m_uidsToRows.value(uid), getErrorType(error));
qCWarning(lcUsersLog) << "Adding user to groups failed:" << error;
} else {
emit userGroupsChanged(row);
emit userGroupsChanged(m_uidsToRows.value(uid));
}
call->deleteLater();
}
Expand Down Expand Up @@ -516,3 +542,29 @@ void UserModel::destroyInterface() {
m_dBusInterface = nullptr;
}
}

void UserModel::add(UserInfo &user)
{
if (placeholder() && m_transitioning.contains(m_users.last().uid())
&& m_users.last().name() == user.name()) {
// This is the placeholder we were adding, "change" that
int row = m_users.count()-1;
m_users.insert(row, user);
m_uidsToRows.insert(user.uid(), row);
auto idx = index(row, 0);
emit dataChanged(idx, idx, QVector<int>());
// And then "add" the placeholder back to its position
beginInsertRows(QModelIndex(), row+1, row+1);
m_users[row+1].reset();
m_transitioning.remove(m_users[row+1].uid());
endInsertRows();
} else {
// Find the last position that's not placeholder and insert there
int row = placeholder() ? m_users.count()-1 : m_users.count();
beginInsertRows(QModelIndex(), row, row);
m_users.insert(row, user);
m_uidsToRows.insert(user.uid(), row);
endInsertRows();
}
emit countChanged();
}
23 changes: 17 additions & 6 deletions src/usermodel.h
Expand Up @@ -35,6 +35,7 @@
#include <QAbstractListModel>
#include <QDBusError>
#include <QHash>
#include <QSet>
#include <QVector>

#include "systemsettingsglobal.h"
Expand All @@ -49,6 +50,8 @@ class SYSTEMSETTINGS_EXPORT UserModel: public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool placeholder READ placeholder WRITE setPlaceholder NOTIFY placeholderChanged)
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(int maximumCount READ maximumCount CONSTANT)

public:
enum Roles {
Expand All @@ -58,6 +61,7 @@ class SYSTEMSETTINGS_EXPORT UserModel: public QAbstractListModel
UidRole,
CurrentRole,
PlaceholderRole,
TransitioningRole,
};
Q_ENUM(Roles)

Expand All @@ -82,14 +86,17 @@ class SYSTEMSETTINGS_EXPORT UserModel: public QAbstractListModel
UserNotFound,
AddToGroupFailed,
RemoveFromGroupFailed,
MaximumNumberOfUsersReached,
};
Q_ENUM(ErrorType)

explicit UserModel(QObject *parent = 0);
~UserModel();

bool placeholder();
bool placeholder() const;
void setPlaceholder(bool value);
int count() const;
int maximumCount() const;

QHash<int, QByteArray> roleNames() const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
Expand All @@ -111,6 +118,7 @@ class SYSTEMSETTINGS_EXPORT UserModel: public QAbstractListModel

signals:
void placeholderChanged();
void countChanged();
void userGroupsChanged(int row);
void userAddFailed(int error);
void userModifyFailed(int row, int error);
Expand All @@ -127,18 +135,21 @@ private slots:
void onCurrentUserChangeFailed(uint uid);

void userAddFinished(QDBusPendingCallWatcher *call);
void userModifyFinished(QDBusPendingCallWatcher *call, int row);
void userRemoveFinished(QDBusPendingCallWatcher *call, int row);
void setCurrentUserFinished(QDBusPendingCallWatcher *call, int row);
void addToGroupsFinished(QDBusPendingCallWatcher *call, int row);
void removeFromGroupsFinished(QDBusPendingCallWatcher *call, int row);
void userModifyFinished(QDBusPendingCallWatcher *call, uint uid);
void userRemoveFinished(QDBusPendingCallWatcher *call, uint uid);
void setCurrentUserFinished(QDBusPendingCallWatcher *call, uint uid);
void addToGroupsFinished(QDBusPendingCallWatcher *call, uint uid);
void removeFromGroupsFinished(QDBusPendingCallWatcher *call, uint uid);

void createInterface();
void destroyInterface();

private:
void add(UserInfo &user);

QVector<UserInfo> m_users;
QHash<uint, int> m_uidsToRows;
QSet<uint> m_transitioning;
QDBusInterface *m_dBusInterface;
QDBusServiceWatcher *m_dBusWatcher;
};
Expand Down

0 comments on commit 829e7fc

Please sign in to comment.