Skip to content
Permalink
Browse files

Merge branch 'pr-userlist'

Integrate feature branch for filtered and improved registration list.
This merges pull request #148.
  • Loading branch information...
Kissaki committed Jun 28, 2013
2 parents de2e086 + ef8b3b9 commit c40b0b004557bb27b2bd13fd9f99afcb1736b53a
Showing with 453 additions and 59 deletions.
  1. +2 −0 src/Mumble.proto
  2. +12 −0 src/User.h
  3. +194 −31 src/mumble/UserEdit.cpp
  4. +20 −6 src/mumble/UserEdit.h
  5. +176 −15 src/mumble/UserEdit.ui
  6. +14 −7 src/murmur/Messages.cpp
  7. +2 −0 src/murmur/Server.h
  8. +33 −0 src/murmur/ServerDB.cpp
@@ -219,6 +219,8 @@ message UserList {
message User {
required uint32 user_id = 1;
optional string name = 2;
optional string last_seen = 3;
optional uint32 last_channel = 4;
}
repeated User users = 1;
}
@@ -33,6 +33,7 @@

#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <boost/optional.hpp>

class Channel;

@@ -60,4 +61,15 @@ class User {
static bool lessThan(const User *, const User *);
};

// for last seen
struct UserInfo {
int user_id;
QString name;
boost::optional<int> last_channel;
QDateTime last_active;

UserInfo() : user_id(-1) {}
UserInfo(int id, QString uname) : user_id(id), name(uname) {}
};

#endif
@@ -31,94 +31,257 @@
#include "mumble_pch.hpp"

#include "UserEdit.h"

#include "Channel.h"
#include "Global.h"
#include "ServerHandler.h"
#include "User.h"

UserEdit::UserEdit(const MumbleProto::UserList &msg, QWidget *p) : QDialog(p) {
setupUi(this);

qlwUserList->setContextMenuPolicy(Qt::CustomContextMenu);
qtwUserList->setFocus();
qtwUserList->setContextMenuPolicy(Qt::CustomContextMenu);

int n = msg.users_size();
setWindowTitle(tr("User List - %n Registered User(s)", "", n));


qtwUserList->header()->setResizeMode(0, QHeaderView::Stretch); // user name
qtwUserList->header()->setResizeMode(1, QHeaderView::ResizeToContents); // last seen
qtwUserList->header()->setResizeMode(2, QHeaderView::Stretch); // on channel
qtwUserList->sortByColumn(0, Qt::AscendingOrder); // sort by user name
qmUsers.clear();

for (int i=0;i<msg.users_size(); ++i) {
for (int i = 0; i < msg.users_size(); ++i) {
const MumbleProto::UserList_User &u = msg.users(i);
int id = u.user_id();
const QString &name = u8(u.name());
UserInfo uie;
protoUserToUserInfo(u, uie);
qmUsers.insert(uie.user_id, uie);
}
refreshUserList();
}

UserEditListItem *ueli = new UserEditListItem(name, id);
void UserEdit::protoUserToUserInfo(const MumbleProto::UserList_User & u, UserInfo & uie)
{
uie.user_id = u.user_id();
uie.name = u8(u.name());
if (u.has_last_channel()) {
uie.last_channel = u.last_channel();
}
if (u.has_last_seen()) {
uie.last_active = QDateTime::fromString(u8(u.last_seen()), Qt::ISODate);
uie.last_active.setTimeSpec(Qt::UTC);
}
}

void UserEdit::refreshUserList(int iGreaterInactiveDaysFilter) {
qtwUserList->clear();
QMapIterator<int, UserInfo> i(qmUsers);

while (i.hasNext()) {
i.next();
UserEditListItem *ueli = new UserEditListItem(i.key());
ueli->setText(0, i.value().name);

QString qsLastActive;
QDateTime qdtLastActive(i.value().last_active);
int iSeenDaysAgo = 0;
if (qdtLastActive.isValid()) {
iSeenDaysAgo = qdtLastActive.daysTo(QDateTime::currentDateTime().toUTC());
qsLastActive = tr("%1").arg(QString::number(iSeenDaysAgo));
}
ueli->setText(1, qsLastActive);
ueli->setToolTip(1, qdtLastActive.toLocalTime().toString(Qt::ISODate));

qlwUserList->addItem(ueli);
qmUsers.insert(id, name);
boost::optional<int> lastchanid = i.value().last_channel;
Channel *c = lastchanid ? Channel::get(*lastchanid) : NULL;
QString lastchantreestring = getChanneltreestring(c);
ueli->setText(2, lastchantreestring);

if (lastchanid) {
showExtendedGUI();
} else {
hideExtendedGUI();
}

if ((iGreaterInactiveDaysFilter > 0) && (iSeenDaysAgo < iGreaterInactiveDaysFilter)) {
delete ueli;
continue;
}

qtwUserList->addTopLevelItem(ueli);
}
}

QString UserEdit::getChanneltreestring(Channel* c) const
{
QString tree = QLatin1String("-");
if (c) {
QStringList channel_tree;
while (c->cParent != NULL) {
channel_tree.prepend(c->qsName);
c = c->cParent;
}

//TODO: This seems unnecessary
QStringList _channel_tree;
for (QStringList::iterator it = channel_tree.begin(); it != channel_tree.end(); ++it) {
_channel_tree.append(*it);
}

channel_tree.clear();
channel_tree.append(_channel_tree);

tree = QLatin1String("/ ") + channel_tree.join(QLatin1String(" / "));
}
return tree;
}

void UserEdit::showExtendedGUI()
{
qtwUserList->showColumn(1);
qtwUserList->showColumn(2);
qlInactive->show();
qsbInactive->show();
qcbInactive->show();
}

void UserEdit::hideExtendedGUI()
{
qtwUserList->hideColumn(1);
qtwUserList->hideColumn(2);
qlInactive->hide();
qsbInactive->hide();
qcbInactive->hide();
}

void UserEdit::accept() {
QList<QListWidgetItem *> ql = qlwUserList->findItems(QString(), Qt::MatchStartsWith);
foreach(QListWidgetItem * qlwi, ql) {
const QString &name = qlwi->text();
int id = qlwi->data(Qt::UserRole).toInt();
if (qmUsers.value(id) != name) {
QList<QTreeWidgetItem *> ql = qtwUserList->findItems(QString(), Qt::MatchStartsWith);
foreach(QTreeWidgetItem * qlwi, ql) {
const QString &name = qlwi->text(0);
int id = qlwi->data(0, Qt::UserRole).toInt();
if (qmUsers.value(id).name != name) {
qmChanged.insert(id, name);
}
}

if (! qmChanged.isEmpty()) {
MumbleProto::UserList mpul;
QMap<int, QString>::const_iterator i;
for (i=qmChanged.constBegin(); i!=qmChanged.constEnd(); ++i) {
for (i = qmChanged.constBegin(); i != qmChanged.constEnd(); ++i) {
MumbleProto::UserList_User *u = mpul.add_users();
u->set_user_id(i.key());
if (! i.value().isEmpty())
if (! i.value().isEmpty()) {
u->set_name(u8(i.value()));
}
}
g.sh->sendMessage(mpul);
}

QDialog::accept();
}

void UserEdit::on_qpbRemove_clicked() {
int idx = qlwUserList->currentRow();
void UserEdit::on_qpbRename_clicked() {
int idx = qtwUserList->currentIndex().row();
if (idx >= 0) {
QListWidgetItem *qlwi = qlwUserList->takeItem(idx);
int id = qlwi->data(Qt::UserRole).toInt();
QTreeWidgetItem *item = qtwUserList->currentItem();
if (item) {
qtwUserList->editItem(item);
}
}
}

void UserEdit::on_qpbRemove_clicked() {
while (qtwUserList->selectedItems().count() > 0) {
QTreeWidgetItem *qlwi = qtwUserList->selectedItems().takeAt(0);
int id = qlwi->data(0, Qt::UserRole).toInt();
qmChanged.insert(id, QString());
delete qlwi;
}
}

void UserEdit::on_qlwUserList_customContextMenuRequested(const QPoint &point) {
void UserEdit::on_qtwUserList_customContextMenuRequested(const QPoint &point) {
QMenu *menu = new QMenu(this);

QAction *action = menu->addAction(tr("Rename"));
connect(action, SIGNAL(triggered()), this, SLOT(renameTriggered()));
QAction *action;

menu->addSeparator();
if (!(qtwUserList->selectedItems().count() > 1))
{
action = menu->addAction(tr("Rename"));
connect(action, SIGNAL(triggered()), this, SLOT(renameTriggered()));
menu->addSeparator();
}

action = menu->addAction(tr("Remove"));
connect(action, SIGNAL(triggered()), this, SLOT(on_qpbRemove_clicked()));

menu->exec(qlwUserList->mapToGlobal(point));
menu->exec(qtwUserList->mapToGlobal(point));
delete menu;
}

void UserEdit::renameTriggered() {
QListWidgetItem *item = qlwUserList->currentItem();
QTreeWidgetItem *item = qtwUserList->currentItem();
if (item) {
qlwUserList->editItem(item);
qtwUserList->editItem(item, 0);
}
}

UserEditListItem::UserEditListItem(const QString &username, const int userid) : QListWidgetItem(username) {
UserEditListItem::UserEditListItem(const int userid) : QTreeWidgetItem() {
setFlags(flags() | Qt::ItemIsEditable);
setData(Qt::UserRole, userid);
setData(0, Qt::UserRole, userid);
}

bool UserEditListItem::operator<(const QListWidgetItem &other) const {
bool UserEditListItem::operator<(const QTreeWidgetItem &other) const {
// Avoid duplicating the User sorting code for a little more complexity
User first, second;
first.qsName = text();
second.qsName = other.text();
first.qsName = text(0);
second.qsName = other.text(0);
return User::lessThan(&first, &second);
}

void UserEdit::on_qlSearch_textChanged(QString) {
qtwUserList->clearSelection();
for (int i=0; i < qtwUserList->topLevelItemCount(); ++i) {
const QString name = qtwUserList->topLevelItem(i)->text(0);
const QString last_channel = qtwUserList->topLevelItem(i)->text(2);
if (!name.contains(qlSearch->text(), Qt::CaseInsensitive) && !last_channel.contains(qlSearch->text(), Qt::CaseInsensitive)) {
qtwUserList->setItemHidden(qtwUserList->topLevelItem(i), true);
} else {
qtwUserList->setItemHidden(qtwUserList->topLevelItem(i), false);
}
}
}

void UserEdit::on_qtwUserList_itemSelectionChanged() {
qpbRename->setEnabled(qtwUserList->selectedItems().count() == 1);
qpbRemove->setEnabled(qtwUserList->selectedItems().count() > 0);
}

void UserEdit::on_qsbInactive_valueChanged(int ) {
qtwUserList->clearSelection();

const int iTimespanUnit = qcbInactive->currentIndex();
const int iTimespanCount = qsbInactive->value();
int iInactiveForDays = 0;
switch (iTimespanUnit) {
case 0:
iInactiveForDays = iTimespanCount;
break;
case 1:
iInactiveForDays = iTimespanCount * 7;
break;
case 2:
iInactiveForDays = iTimespanCount * 30;
break;
case 3:
iInactiveForDays = iTimespanCount * 365;
break;
default:
break;
}
refreshUserList(iInactiveForDays);
}

void UserEdit::on_qcbInactive_currentIndexChanged(int index) {
on_qsbInactive_valueChanged(index);
}
@@ -32,34 +32,48 @@
#define MUMBLE_MUMBLE_USEREDIT_H_

#include "Message.h"

#include "User.h"
#include "mumble_pch.hpp"
#include "ui_UserEdit.h"

namespace MumbleProto {
class UserList;
}
namespace MumbleProto { class UserList_User; }

class UserEditListItem : public QListWidgetItem {
class UserEditListItem : public QTreeWidgetItem {
public:
UserEditListItem(const QString &username, const int userid);
bool operator<(const QListWidgetItem & other) const;
UserEditListItem(const int userid);
bool operator<(const QTreeWidgetItem & other) const;
};

class UserEdit : public QDialog, public Ui::UserEdit {
private:
Q_OBJECT
Q_DISABLE_COPY(UserEdit)

void protoUserToUserInfo(const MumbleProto::UserList_User & u, UserInfo & uie);
void showExtendedGUI();
void hideExtendedGUI();
QString getChanneltreestring(Channel* c) const;

protected:
QMap<int, QString> qmUsers;
QMap<int, UserInfo> qmUsers;
QMap<int, QString> qmChanged;
public:
UserEdit(const MumbleProto::UserList &mpul, QWidget *p = NULL);
public slots:
void accept();
void on_qlSearch_textChanged(QString );
public slots:
void on_qpbRemove_clicked();
void on_qlwUserList_customContextMenuRequested(const QPoint&);
void on_qpbRename_clicked();
void on_qtwUserList_customContextMenuRequested(const QPoint&);
void renameTriggered();
void refreshUserList(int iGreaterInactiveDaysFilter = 0);
void on_qtwUserList_itemSelectionChanged();
void on_qsbInactive_valueChanged(int );
void on_qcbInactive_currentIndexChanged(int index);
};

#endif

0 comments on commit c40b0b0

Please sign in to comment.
You can’t perform that action at this time.