Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

UserList Improvements #148

Closed
wants to merge 1 commit into from

2 participants

@Zuko

-- This is my latest and last attempt with this.

Changes:

  • Better GUI
  • Added "Search Box"
  • Added Multi-Select
  • Added "Last Seen"

  • If server does not support "last seen function" empty columns are hidden

Known bugs:

  • Date and Time are not in UTC
  • Deleting ~4000 "inactive accounts" can take a while (but this is not my fault)
  • Windows title should be changed to "User List (1337 items)"

More important, my programming skills are not that good as I wanted, so if something is wrong in this patch - simply fix it, commit and move forward - if not leave it and use old ugly User List for another two years.

Preview:
User_List_-_2948_-_Registered_Users_2013-03-02_08-53-24
User_List_-_2948_-_Registered_Users_2013-03-02_08-53-40

@Kissaki
Owner

Awesome!

Is the “search box” a search or a filter?

I don’t quite know how to take your closing paragraph. Are you not willing to implement suggestions, and we should implement them ourselves?

@Zuko

It's a "filter", it just hides rows.
And yes, I did as much as I could, if you need to change something, please do it.

@Kissaki
Owner

Ok, thank you very much. :)

@Kissaki
Owner

This PR has previously been submitted as a patch in the patch tracker:
https://sourceforge.net/p/mumble/patches/335/

The last (unreplied, unsolved) comment from slicer states some issues that should be verified here as well, to make sure they were addressed:

This patch modifies the wording and/or whitespace of the license. It cannot be accepted as is.

While I'm not sure, I think tr() can specialcase zero of a plural form, so you don't need the logic at all. Please test this?

Adding 'days ago' to every single entry seems a bit excessive, especially since they are all identical. Either make the column simply be "Inactive Days" (or some shorter formulation) or do the full days/weeks/months/years analysis (which means custom sort order to maintain the relationships).

Dates need to be ISO format and in UTC.

This will break on servers that have third-party authentication. Either modify Server::getRegisteredUsers to return what you need, or at the very least base your returned data on the output from Server::getRegisteredUsers.

Channel IDs are not unsigned, please update your proto definiton.

If the server does not support the updated info, the columns should be removed. Since the data is either always there, or never there, simply check whether or not any of the received entries have last on fields.

I'm not sure where the UserInfo struct belongs, but I don't think Net.h is the right place. It's probably better to put it in User.h (and add a comment to it). Also, please use QDateTime for the storage of a in-memory date instead of a string.

I understand that 'last channel' is what you use on your server, and that a highly hierarchical structure with a high correlation between social group association and channel structure makes this handy. However, this is not universally true for all servers, and hence will feel rather strange on a server that does not use strong channel hierarchies, but instead uses e.g. strong ACL group hierarchies. Please see if there is a method of differentiation that is slightly less instance-specific.

@Kissaki
Owner

For reference: Currently, on 1.2.4, the dialog looks like this:
Registered Users_2013-03-22_20-28-43

@Zuko

I tried to fix all the things mentioned by slicer.
I didn't know how how to "fix" dates to "UTC" and " third-party authentication", the rest is "fixed/corrected" (I hope :) )

@Zuko

ehm, any progress? :)

@Kissaki
Owner

Thank you @bendem for looking at the code and providing some feedback!

Based on this pull request I created a pr-userlist branch, and fixed the indentation issues, and changed the string.

@Kissaki
Owner

When I launch compiled murmur and mumble I somehow don’t see the two new columns.

@Kissaki Kissaki commented on the diff
src/murmur/ServerDB.cpp
((10 lines not shown))
+ SQLPREP("SELECT `user_id`, `name`, `lastchannel`, `last_active` FROM `%1users` WHERE `server_id` = ?");
+ query.addBindValue(iServerNum);
+ SQLEXEC();
+
+ while (query.next()) {
+ UserInfo userinfo;
+ userinfo.user_id = query.value(0).toInt();
+ userinfo.name = query.value(1).toString();
+ userinfo.last_channel = query.value(2).toInt();
+ userinfo.last_active = query.value(3).toString();
+
+ m << userinfo;
+ }
+
+ return m;
+}
@Kissaki Owner
Kissaki added a note

The implementation of getRegisteredUsersEx() is currently missing the signal for RPCs (dbus, ice, rpc). See getRegisteredUsers()
emit getRegisteredUsersSig(filter, m);
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Kissaki
Owner

Going over slicers comments:

This patch modifies the wording and/or whitespace of the license. It cannot be accepted as is.

This has been fixed in this PR. No license text is touched.

Adding 'days ago' to every single entry seems a bit excessive, especially since they are all identical. Either make the column simply be "Inactive Days" (or some shorter formulation) or do the full days/weeks/months/years analysis (which means custom sort order to maintain the relationships).

From the screenshot, it seems to have been fixed for this PR. I can not verify currently as my build does not show these columns when there are registrations.

Dates need to be ISO format and in UTC.

I don’t see what this refers to!? I do not see any dates, just time-spans (“days”).

This will break on servers that have third-party authentication. Either modify Server::getRegisteredUsers to return what you need, or at the very least base your returned data on the output from Server::getRegisteredUsers.

The missing RPC thing I mentioned in an earlier comment.

Channel IDs are not unsigned, please update your proto definiton.

Not sure about this. In the Mumble.proto I only see uint32s for channel ids. So why would it be different here? Did this change?

While I'm not sure, I think tr() can specialcase zero of a plural form, so you don't need the logic at all. Please test this?

Probably refers to setWindowTitle(tr("User List - %n - Registered Users", "", n));, which was not fixed.
https://github.com/mumble-voip/mumble/pull/148/files#L2R46

If the server does not support the updated info, the columns should be removed. Since the data is either always there, or never there, simply check whether or not any of the received entries have last on fields.

Could not verify.

I'm not sure where the UserInfo struct belongs, but I don't think Net.h is the right place. It's probably better to put it in User.h (and add a comment to it). Also, please use QDateTime for the storage of a in-memory date instead of a string.

Was moved to User.h.
Comment should be changed to a more general one.
Dates are still strings, which should be changed.

I understand that 'last channel' is what you use on your server, and that a highly hierarchical structure with a high correlation between social group association and channel structure makes this handy. However, this is not universally true for all servers, and hence will feel rather strange on a server that does not use strong channel hierarchies, but instead uses e.g. strong ACL group hierarchies. Please see if there is a method of differentiation that is slightly less instance-specific.

Should be evaluated and discussed still.

@Zuko

Don't look at old slicers comment, it's not valid after 2 years.

@Kissaki
Owner

As I pointed out it is.
You can’t say it’s invalid without evaluating it.

@Zuko

nvm then, do it your way. I just want to see this in official release. (soon) btw. dunno why it's not working on your build.

@Kissaki
Owner

I noticed an nmake did not generate the Mumble.pb.h from the proto file. Removing it it was created with the new fields.
But apparently that did not fix it yet. Issue for another day.

@Kissaki Kissaki was assigned
@Kissaki Kissaki commented on the diff
src/mumble/UserEdit.cpp
((40 lines not shown))
+void UserEdit::refreshUserList(int inactive) {
+ 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 last_active;
+ QDateTime qdtLastActive;
+ int last_seen;
+ if (!i.value().last_active.isEmpty()) {
+ qdtLastActive = QDateTime::fromString(i.value().last_active, QLatin1String("yyyy-MM-dd hh:mm:ss"));
+ if (!qdtLastActive.isValid())
+ qdtLastActive = QDateTime::fromString(i.value().last_active, QLatin1String("yyyy-MM-ddThh:mm:ss"));
@Kissaki Owner
Kissaki added a note

Why do we have two parse-formats here?
Shouldn't the format we save to into the DB always be the same?

@Zuko
Zuko added a note

Don't ask me ;)
It's different on Win / Linux, check yourself.

@Kissaki Owner
Kissaki added a note

I switched to the appropriate Qt QDateTime and QDateFormats Qt::ISO<...>, which works on windows as well - where sqlitebrowser indeed shows me the date without a T.
As it works in this off-case which Qt does not explicitly mention/document (as it's not valid ISO) it should work in any case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Kissaki
Owner

The time displayed as a tooltip is in UTC and ISO.
Still not sure this is what slicer meant.

I implemented the RPC callback.

The plural form has been added to the window title - untested.
reference

Fixed datetime to be displayed as local time - after being transmitted as UTC.

I noticed one can edit the inactive days and last channel columns. This should be disabled.
Looking at QTreeWidget, it seems I can not disable columns or cells.
See Stackoverflow: Making only one column of a QTreeWidgetItem editable

So the remaining issues are:

  • Handle datetime as QDateTime in UserInfo

And the nonblockers:

  • Columns two and three are editable, which they should not be (effectively do not set/save anything).
  • Test the plural form in the title
  • Discuss what slicer meant with channel id should not be unsigned
  • Discuss channel hierarchy display
@Kissaki Kissaki referenced this pull request from a commit
@Kissaki Kissaki Merge branch 'pr-userlist'
Integrate feature branch for filtered and improved registration list.
This merges pull request #148.
c40b0b0
@Kissaki
Owner

Fixed: * Handle datetime as QDateTime in UserInfo

The feature branch with these changes has been merged into master.

Points open for discussion, which should be handled in further and individual issue tickets:

  • Columns two and three are editable, which they should not be (effectively do not set/save anything).
  • Test the plural form in the title
  • Discuss what slicer meant with channel id should not be unsigned
  • Discuss channel hierarchy display

Again, thank you very much Zuko for your work!

@Kissaki Kissaki closed this
@Zuko

thanks, it's working ;D

2013-06-29_15-39-12

@Zuko

"* Discuss channel hierarchy display"

There is nothing to discuss right now, slicer had doubts about this: (red rectangle) but I removed this functionality.

2013-06-29_16-02-18

Kissaki, thanks for your work ;)

@Kissaki
Owner

Ah, ok. Thank you for clarifying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 1, 2013
  1. @Zuko

    UserList improvements

    Zuko authored
This page is out of date. Refresh to see the latest.
View
2  src/Mumble.proto
@@ -218,6 +218,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;
}
View
8 src/User.h
@@ -60,4 +60,12 @@ class User {
static bool lessThan(const User *, const User *);
};
+// for last seen
+struct UserInfo {
+ int user_id;
+ QString name;
+ int last_channel;
+ QString last_active;
+};
+
#endif
View
193 src/mumble/UserEdit.cpp
@@ -31,7 +31,7 @@
#include "mumble_pch.hpp"
#include "UserEdit.h"
-
+#include "Channel.h"
#include "Global.h"
#include "ServerHandler.h"
#include "User.h"
@@ -39,27 +39,100 @@
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 Users", "", n));
- 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());
- UserEditListItem *ueli = new UserEditListItem(name, id);
+ 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) {
+ const MumbleProto::UserList_User &u = msg.users(i);
+ UserInfo uie;
+ uie.user_id = u.user_id();
+ uie.name = u8(u.name());
+ uie.last_channel = u.last_channel();
+ if (u.has_last_seen())
+ uie.last_active = u8(u.last_seen());
+ else
+ uie.last_active = QString();
+ qmUsers.insert(uie.user_id, uie);
+ }
+ refreshUserList();
+}
- qlwUserList->addItem(ueli);
- qmUsers.insert(id, name);
+void UserEdit::refreshUserList(int inactive) {
+ 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 last_active;
+ QDateTime qdtLastActive;
+ int last_seen;
+ if (!i.value().last_active.isEmpty()) {
+ qdtLastActive = QDateTime::fromString(i.value().last_active, QLatin1String("yyyy-MM-dd hh:mm:ss"));
+ if (!qdtLastActive.isValid())
+ qdtLastActive = QDateTime::fromString(i.value().last_active, QLatin1String("yyyy-MM-ddThh:mm:ss"));
@Kissaki Owner
Kissaki added a note

Why do we have two parse-formats here?
Shouldn't the format we save to into the DB always be the same?

@Zuko
Zuko added a note

Don't ask me ;)
It's different on Win / Linux, check yourself.

@Kissaki Owner
Kissaki added a note

I switched to the appropriate Qt QDateTime and QDateFormats Qt::ISO<...>, which works on windows as well - where sqlitebrowser indeed shows me the date without a T.
As it works in this off-case which Qt does not explicitly mention/document (as it's not valid ISO) it should work in any case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ last_seen = qdtLastActive.daysTo(QDateTime::currentDateTime());
+ last_active = tr("%1").arg(QString::number(last_seen));
+ } else
+ last_active.clear();
+
+ if ((inactive > 0) && (last_seen < inactive))
+ continue;
+
+ if (!last_active.isEmpty()) {
+ ueli->setText(1, last_active);
+ ueli->setToolTip(1, qdtLastActive.toString(QLatin1String("yyyy-MM-dd hh:mm:ss")));
+
+ Channel *c = Channel::get(i.value().last_channel);
+ QString tree;
+ if (c) {
+ QStringList channel_tree;
+ while (c->cParent != NULL) {
+ channel_tree.prepend(c->qsName);
+ c = c->cParent;
+ }
+ 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(" / "));
+ ueli->setText(2, tree);
+ } else {
+ tree = QLatin1String("-");
+ }
+ } else {
+ //Hide columns and other gui stuff
+ qtwUserList->hideColumn(1);
+ qtwUserList->hideColumn(2);
+ qlInactive->hide();
+ qsbInactive->hide();
+ qcbInactive->hide();
+ }
+ qtwUserList->addTopLevelItem(ueli);
}
}
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) {
- qmChanged.insert(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);
}
}
@@ -78,47 +151,105 @@ void UserEdit::accept() {
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();
+ int cbvalue = qcbInactive->currentIndex();
+ int sbvalue;
+ switch (cbvalue) {
+ case 0:
+ sbvalue = qsbInactive->value();
+ break;
+ case 1:
+ sbvalue = qsbInactive->value() * 7;
+ break;
+ case 2:
+ sbvalue = qsbInactive->value() * 30;
+ break;
+ case 3:
+ sbvalue = qsbInactive->value() * 365;
+ break;
+ default:
+ sbvalue = 0;
+ }
+ refreshUserList(sbvalue);
+}
+
+void UserEdit::on_qcbInactive_currentIndexChanged(int index) {
+ on_qsbInactive_valueChanged(index);
+}
View
19 src/mumble/UserEdit.h
@@ -32,17 +32,18 @@
#define USEREDIT_H_
#include "Message.h"
-
+#include "User.h"
+#include "mumble_pch.hpp"
#include "ui_UserEdit.h"
namespace MumbleProto {
class UserList;
}
-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 {
@@ -50,16 +51,22 @@ class UserEdit : public QDialog, public Ui::UserEdit {
Q_OBJECT
Q_DISABLE_COPY(UserEdit)
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 inactive = 0);
+ void on_qtwUserList_itemSelectionChanged();
+ void on_qsbInactive_valueChanged(int );
+ void on_qcbInactive_currentIndexChanged(int index);
};
#endif
View
191 src/mumble/UserEdit.ui
@@ -6,39 +6,205 @@
<rect>
<x>0</x>
<y>0</y>
- <width>471</width>
- <height>401</height>
+ <width>542</width>
+ <height>470</height>
</rect>
</property>
+ <property name="minimumSize">
+ <size>
+ <width>381</width>
+ <height>470</height>
+ </size>
+ </property>
<property name="windowTitle">
- <string>Registered Users</string>
+ <string/>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
<widget class="QGroupBox" name="qgbUserList">
<property name="title">
<string>Registered Users</string>
</property>
<layout class="QGridLayout" name="gridLayout">
- <item row="0" column="1">
+ <item row="0" column="0" colspan="6">
+ <widget class="QTreeWidget" name="qtwUserList">
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>false</bool>
+ </property>
+ <property name="columnCount">
+ <number>3</number>
+ </property>
+ <attribute name="headerShowSortIndicator" stdset="0">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Nick</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Inactive days</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>On Channel</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="6">
+ <widget class="QLineEdit" name="qlSearch">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="placeholderText">
+ <string>Who are you looking for?</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QPushButton" name="qpbRename">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
<widget class="QPushButton" name="qpbRemove">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="text">
<string>Remove</string>
</property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QListWidget" name="qlwUserList">
- <property name="sortingEnabled">
+ <item row="2" column="3">
+ <widget class="QLabel" name="qlInactive">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Inactive for</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="4">
+ <widget class="QSpinBox" name="qsbInactive">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>48</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="frame">
<bool>true</bool>
</property>
+ <property name="maximum">
+ <number>9999</number>
+ </property>
</widget>
</item>
+ <item row="2" column="5">
+ <widget class="QComboBox" name="qcbInactive">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <item>
+ <property name="text">
+ <string>Days</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Weeks</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Months</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Years</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</item>
- <item>
+ <item row="1" column="0">
<widget class="QDialogButtonBox" name="qbbButtons">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -49,11 +215,6 @@
</item>
</layout>
</widget>
- <tabstops>
- <tabstop>qlwUserList</tabstop>
- <tabstop>qpbRemove</tabstop>
- <tabstop>qbbButtons</tabstop>
- </tabstops>
<resources/>
<connections>
<connection>
View
15 src/murmur/Messages.cpp
@@ -1438,14 +1438,13 @@ void Server::msgUserList(ServerUser *uSource, MumbleProto::UserList &msg) {
if (msg.users_size() == 0) {
// Query mode.
- QMap<int, QString> users = getRegisteredUsers();
- QMap<int, QString>::const_iterator i;
- for (i = users.constBegin(); i != users.constEnd(); ++i) {
- if (i.key() > 0) {
- ::MumbleProto::UserList_User *u = msg.add_users();
- u->set_user_id(i.key());
- u->set_name(u8(i.value()));
- }
+ QList<UserInfo> users = getRegisteredUsersEx();
+ for (int i = 1; i < users.count(); ++i) {
+ ::MumbleProto::UserList_User *u = msg.add_users();
+ u->set_user_id(users.at(i).user_id);
+ u->set_name(u8(users.at(i).name));
+ u->set_last_channel(users.at(i).last_channel);
+ u->set_last_seen(u8(users.at(i).last_active));
}
sendMessage(uSource, msg);
} else {
View
2  src/murmur/Server.h
@@ -54,6 +54,7 @@
#include "Message.h"
#include "Mumble.pb.h"
#include "Net.h"
+#include "User.h"
#include "Timer.h"
class BonjourServer;
@@ -333,6 +334,7 @@ class Server : public QThread {
QMap<int, QString> getRegistration(int id);
int registerUser(const QMap<int, QString> &info);
bool unregisterUserDB(int id);
+ QList<UserInfo> getRegisteredUsersEx();
QMap<int, QString > getRegisteredUsers(const QString &filter = QString());
bool setInfo(int id, const QMap<int, QString> &info);
bool setTexture(int id, const QByteArray &texture);
View
23 src/murmur/ServerDB.cpp
@@ -722,6 +722,29 @@ bool Server::unregisterUserDB(int id) {
return true;
}
+QList<UserInfo> Server::getRegisteredUsersEx() {
+ QList<UserInfo> m;
+
+ TransactionHolder th;
+
+ QSqlQuery &query = *th.qsqQuery;
+ SQLPREP("SELECT `user_id`, `name`, `lastchannel`, `last_active` FROM `%1users` WHERE `server_id` = ?");
+ query.addBindValue(iServerNum);
+ SQLEXEC();
+
+ while (query.next()) {
+ UserInfo userinfo;
+ userinfo.user_id = query.value(0).toInt();
+ userinfo.name = query.value(1).toString();
+ userinfo.last_channel = query.value(2).toInt();
+ userinfo.last_active = query.value(3).toString();
+
+ m << userinfo;
+ }
+
+ return m;
+}
@Kissaki Owner
Kissaki added a note

The implementation of getRegisteredUsersEx() is currently missing the signal for RPCs (dbus, ice, rpc). See getRegisteredUsers()
emit getRegisteredUsersSig(filter, m);
.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
QMap<int, QString > Server::getRegisteredUsers(const QString &filter) {
QMap<int, QString > m;
Something went wrong with that request. Please try again.