summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <matthias@gamezock.de>2009-09-24 21:50:11 +0200
committerMatthias Schiffer <matthias@gamezock.de>2009-09-24 21:50:11 +0200
commit9f962123be30da94add3f966bb46962f8bfdea88 (patch)
treeed1a210da3d5ba5d8d7d0807dd4e6ed4de4172f4
parent1cf531a5949cad1f68575188cf00d147478e029c (diff)
downloadmad-9f962123be30da94add3f966bb46962f8bfdea88.tar
mad-9f962123be30da94add3f966bb46962f8bfdea88.zip
UserList: Encapsulate list
-rw-r--r--src/Client/UserListCommands.cpp87
-rw-r--r--src/Client/UserListCommands.h3
-rw-r--r--src/Common/CMakeLists.txt2
-rw-r--r--src/Common/UserLists/UserList.cpp129
-rw-r--r--src/Common/UserLists/UserList.h125
-rw-r--r--src/Common/UserLists/Util.cpp4
-rw-r--r--src/Server/UserListManager.cpp2
7 files changed, 344 insertions, 8 deletions
diff --git a/src/Client/UserListCommands.cpp b/src/Client/UserListCommands.cpp
index eb4aee1..420202e 100644
--- a/src/Client/UserListCommands.cpp
+++ b/src/Client/UserListCommands.cpp
@@ -162,10 +162,79 @@ void UserListCommands::showListCommand(CommandParser *commandParser, const std::
boost::shared_ptr<Common::UserLists::UserList> userList = Common::UserLists::Util::deserializeUserList(result.first.get());
- std::cout << "User list '" << args[2] << "':" << std::endl;
+ std::cout << "User list '" << args[2];
- for(Common::UserLists::UserList::iterator user = userList->begin(); user != userList->end(); ++user) {
- std::cout << " " << user->getName() << std::endl;
+ if(userList->isEmpty()) {
+ std::cout << " is empty." << std::endl;
+ }
+ else {
+ std::cout << "' contains " << userList->getLength() << " user";
+ if(userList->getLength() > 1)
+ std::cout << "s";
+ std::cout << "." << std::endl << std::endl;
+
+ std::map<std::string, unsigned> lengths;
+
+ static const std::string USER_NAME("User name");
+ lengths.insert(std::make_pair(USER_NAME, USER_NAME.length()));
+ static const std::string GROUP_NAME("Group name");
+ lengths.insert(std::make_pair(GROUP_NAME, GROUP_NAME.length()));
+
+ std::set<std::string> details = userList->getDetails();
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ lengths.insert(std::make_pair(*detail, detail->length()));
+ }
+
+ for(Common::UserLists::UserList::iterator user = userList->begin(); user != userList->end(); ++user) {
+ std::map<std::string, unsigned>::iterator it = lengths.find(USER_NAME);
+ if(user->getName().length() > it->second)
+ it->second = user->getName().length();
+
+ it = lengths.find(GROUP_NAME);
+ if(user->getGroup().length() > it->second)
+ it->second = user->getGroup().length();
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ it = lengths.find(*detail);
+ std::string detailStr = user->getDetail(*detail);
+ if(detailStr.length() > it->second)
+ it->second = detailStr.length();
+ }
+ }
+
+ printPadded(USER_NAME, lengths.find(USER_NAME)->second);
+ printPadded(GROUP_NAME, lengths.find(GROUP_NAME)->second);
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ printPadded(*detail, lengths.find(*detail)->second);
+ }
+ std::cout << std::endl;
+
+ printDelimiter(lengths.find(USER_NAME)->second);
+ printDelimiter(lengths.find(GROUP_NAME)->second);
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ printDelimiter(lengths.find(*detail)->second);
+ }
+ std::cout << std::endl;
+
+ for(Common::UserLists::UserList::iterator user = userList->begin(); user != userList->end(); ++user) {
+ static const std::string UNSET("<unset>");
+
+ if(!user->getName().empty())
+ printPadded(user->getName(), lengths.find(USER_NAME)->second);
+ else
+ printPadded(UNSET, lengths.find(USER_NAME)->second);
+
+ if(!user->getGroup().empty())
+ printPadded(user->getGroup(), lengths.find(GROUP_NAME)->second);
+ else
+ printPadded(UNSET, lengths.find(GROUP_NAME)->second);
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ printPadded(user->getDetail(*detail), lengths.find(*detail)->second);
+ }
+
+ std::cout << std::endl;
+ }
}
std::cout << std::endl;
@@ -177,6 +246,18 @@ void UserListCommands::showListCommand(CommandParser *commandParser, const std::
}
}
+void UserListCommands::printPadded(const std::string &str, unsigned length) {
+ static const int EXTRA_PADDING = 3;
+
+ std::cout << str;
+ if(str.length() < length + EXTRA_PADDING)
+ std::cout << std::string(length-str.length()+EXTRA_PADDING, ' ');
+}
+
+void UserListCommands::printDelimiter(unsigned length) {
+ printPadded(std::string(length, '-'), length);
+}
+
void UserListCommands::userListCommand(CommandParser *commandParser, const std::vector<std::string> &args) {
std::string cmd;
diff --git a/src/Client/UserListCommands.h b/src/Client/UserListCommands.h
index 17fcb4e..51a714b 100644
--- a/src/Client/UserListCommands.h
+++ b/src/Client/UserListCommands.h
@@ -42,6 +42,9 @@ class MAD_CLIENT_EXPORT UserListCommands {
static void listCommand(CommandParser *commandParser, const std::vector<std::string> &args);
static void showListCommand(CommandParser *commandParser, const std::vector<std::string> &args);
+ static void printPadded(const std::string &str, unsigned length);
+ static void printDelimiter(unsigned length);
+
public:
static void userListCommand(CommandParser *commandParser, const std::vector<std::string> &args);
};
diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt
index a99f9be..d82c0d9 100644
--- a/src/Common/CMakeLists.txt
+++ b/src/Common/CMakeLists.txt
@@ -18,7 +18,7 @@ mad_library(Common
Requests/SimpleRequest.cpp Requests/SimpleRequest.h
Requests/StatusRequest.h
- UserLists/UserList.h
+ UserLists/UserList.cpp UserLists/UserList.h
UserLists/UserListDiff.cpp UserLists/UserListDiff.h
UserLists/UserListEntry.h
UserLists/Util.cpp UserLists/Util.h
diff --git a/src/Common/UserLists/UserList.cpp b/src/Common/UserLists/UserList.cpp
new file mode 100644
index 0000000..a14111d
--- /dev/null
+++ b/src/Common/UserLists/UserList.cpp
@@ -0,0 +1,129 @@
+/*
+ * UserList.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "UserList.h"
+
+namespace Mad {
+namespace Common {
+namespace UserLists {
+
+std::list<UserListEntry>::iterator UserList::findEntry(const std::string &name) {
+ for(std::list<UserListEntry>::iterator it = list.begin(); it != list.end(); ++it) {
+ if(it->getName() == name) {
+ return it;
+ }
+ }
+
+ return list.end();
+}
+
+std::list<UserListEntry>::const_iterator UserList::findEntry(const std::string &name) const {
+ for(std::list<UserListEntry>::const_iterator it = list.begin(); it != list.end(); ++it) {
+ if(it->getName() == name) {
+ return it;
+ }
+ }
+
+ return list.end();
+}
+
+UserList::iterator UserList::find(const std::string &name) {
+ if(!names.count(name))
+ return end();
+
+ return iterator(findEntry(name));
+}
+
+UserList::const_iterator UserList::find(const std::string &name) const {
+ if(!names.count(name))
+ return end();
+
+ return const_iterator(findEntry(name));
+}
+
+void UserList::registerEntry(const UserListEntry &entry) {
+ std::set<std::string> details = entry.getDetailList();
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ std::map<std::string, unsigned>::iterator it = detailCounts.find(*detail);
+ if(it == detailCounts.end())
+ detailCounts.insert(make_pair(*detail, 1));
+ else
+ ++it->second;
+ }
+}
+
+void UserList::unregisterEntry(const UserListEntry &entry) {
+ std::set<std::string> details = entry.getDetailList();
+
+ for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
+ std::map<std::string, unsigned>::iterator it = detailCounts.find(*detail);
+ // TODO Assert
+ if(it == detailCounts.end())
+ continue;
+
+ if(it->second > 1)
+ --it->second;
+ else
+ detailCounts.erase(it);
+ }
+}
+
+
+bool UserList::addUser(const UserListEntry &entry) {
+ return insertUser(entry, end());
+}
+
+bool UserList::insertUser(const UserListEntry &entry, iterator after) {
+ if(!names.insert(entry.getName()).second)
+ return false;
+
+ list.insert(after.it, entry);
+ registerEntry(entry);
+ return true;
+}
+
+bool UserList::removeUser(const std::string &name) {
+ if(!names.erase(name))
+ return false;
+
+ std::list<UserListEntry>::iterator it = findEntry(name);
+ // TODO Assert
+
+ unregisterEntry(*it);
+ list.erase(it);
+ return true;
+}
+
+bool UserList::updateUser(const UserListEntry &entry) {
+ if(!names.count(entry.getName()))
+ return false;
+
+ std::list<UserListEntry>::iterator it = findEntry(entry.getName());
+ // TODO Assert
+
+ unregisterEntry(*it);
+ *it = entry;
+ registerEntry(entry);
+ return true;
+}
+
+}
+}
+}
diff --git a/src/Common/UserLists/UserList.h b/src/Common/UserLists/UserList.h
index e80abaf..9c5985d 100644
--- a/src/Common/UserLists/UserList.h
+++ b/src/Common/UserLists/UserList.h
@@ -20,16 +20,139 @@
#ifndef MAD_COMMON_USERLISTS_USERLIST_H_
#define MAD_COMMON_USERLISTS_USERLIST_H_
+#include "../export.h"
+
#include "UserListEntry.h"
#include <list>
+#include <map>
+#include <set>
namespace Mad {
namespace Common {
namespace UserLists {
-class UserList : public std::list<UserListEntry> {
+class MAD_COMMON_EXPORT UserList {
+ private:
+ template <typename Type, typename IteratorType>
+ class iterator_base {
+ public:
+ friend class UserList;
+
+ typedef Type value_type;
+
+ typedef value_type &reference;
+ typedef value_type *pointer;
+
+ typedef long difference_type;
+
+ private:
+ IteratorType it;
+
+ iterator_base(IteratorType it0) : it(it0) {}
+
+ public:
+ iterator_base() {}
+
+ reference operator*() const {
+ return *it;
+ }
+
+ iterator_base operator++(int) {
+ return iterator(it++);
+ }
+
+ iterator_base& operator++() {
+ ++it;
+ return *this;
+ }
+
+ iterator_base operator--(int) {
+ return iterator(it--);
+ }
+
+ iterator_base& operator--() {
+ --it;
+ return *this;
+ }
+
+ bool operator==(const iterator_base &it2) {
+ return it2.it == it;
+ }
+
+ bool operator!=(const iterator_base &it2) {
+ return it2.it != it;
+ }
+
+ pointer operator->() const {
+ return &*it;
+ }
+ };
+
+ std::set<std::string> names;
+ std::list<UserListEntry> list;
+
+ std::map<std::string, unsigned> detailCounts;
+
+ void registerEntry(const UserListEntry &entry);
+ void unregisterEntry(const UserListEntry &entry);
+
+ std::list<UserListEntry>::iterator findEntry(const std::string &name);
+ std::list<UserListEntry>::const_iterator findEntry(const std::string &name) const;
+
public:
+ typedef iterator_base<const UserListEntry, std::list<UserListEntry>::iterator> iterator;
+ typedef iterator_base<const UserListEntry, std::list<UserListEntry>::const_iterator> const_iterator;
+
+ iterator find(const std::string &name);
+ const_iterator find(const std::string &name) const;
+
+ iterator begin() {
+ return iterator(list.begin());
+ }
+
+ const_iterator begin() const {
+ return const_iterator(list.begin());
+ }
+
+ iterator end() {
+ return list.end();
+ }
+
+ const_iterator end() const {
+ return const_iterator(list.end());
+ }
+
+ bool isEmpty() const {
+ return list.empty();
+ }
+
+ size_t getLength() const {
+ return list.size();
+ }
+
+ std::set<std::string> getDetails() const {
+ std::set<std::string> ret;
+
+ for(std::map<std::string, unsigned>::const_iterator it = detailCounts.begin(); it != detailCounts.end(); ++it)
+ ret.insert(it->first);
+
+ return ret;
+ }
+
+ unsigned getDetailUsage(const std::string &detail) const {
+ std::map<std::string, unsigned>::const_iterator it = detailCounts.find(detail);
+ if(it == detailCounts.end())
+ return 0;
+ else
+ return it->second;
+ }
+
+ bool addUser(const UserListEntry &entry);
+ bool insertUser(const UserListEntry &entry, iterator after);
+ bool removeUser(const std::string &name);
+ bool updateUser(const UserListEntry &entry);
+
UserList() {}
};
diff --git a/src/Common/UserLists/Util.cpp b/src/Common/UserLists/Util.cpp
index 812c2c7..3c15956 100644
--- a/src/Common/UserLists/Util.cpp
+++ b/src/Common/UserLists/Util.cpp
@@ -39,7 +39,7 @@ UserListEntry Util::deserializeUserListEntry(XmlData::List::const_iterator entry
std::set<std::string> details = entry->getChildren();
for(std::set<std::string>::iterator detail = details.begin(); detail != details.end(); ++detail) {
- if(*detail == "user" || *detail == "group")
+ if(*detail == "name" || *detail == "group")
continue;
user.setDetail(*detail, entry->get<const std::string&>(*detail));
@@ -62,7 +62,7 @@ boost::shared_ptr<UserList> Util::deserializeUserList(const XmlData *data) {
if(userList) {
for(XmlData::List::const_iterator user = userList->begin(); user != userList->end(); ++user)
- users->push_back(deserializeUserListEntry(user));
+ users->addUser(deserializeUserListEntry(user));
}
return users;
diff --git a/src/Server/UserListManager.cpp b/src/Server/UserListManager.cpp
index d1a6e31..d520c96 100644
--- a/src/Server/UserListManager.cpp
+++ b/src/Server/UserListManager.cpp
@@ -141,7 +141,7 @@ boost::shared_ptr<Common::UserLists::UserList> UserListManager::getCurrentUserLi
Common::UserLists::UserListEntry entry(user->second.getUsername(), groupname);
entry.setDetail("Full name", user->second.getFullName());
- list->push_back(entry);
+ list->addUser(entry);
}
return list;