Rewrote the player model, should be more "in tune" with Qts method of referencing items now.

Made the iconlist in the config dialog resizable.
Updated "reg" to "auth" in a few places.


git-svn-id: https://mumble.svn.sourceforge.net/svnroot/mumble/trunk@220 05730e5d-ab1b-0410-a4ac-84af385074fa
This commit is contained in:
Thorvald Natvig 2005-09-27 18:28:04 +00:00
parent d43f59ecf6
commit cb84309bf4
11 changed files with 420 additions and 237 deletions

View File

@ -353,7 +353,7 @@ void ACLEditor::addToolTipsWhatsThis() {
"even if he doesn't belong to the <i>admin</i> group in the channel where the ACL originated.<br />"
"A few special predefined groups are:<br />"
"<b>all</b> - Everyone will match.<br />"
"<b>reg</b> - All registered users will match.<br />"
"<b>auth</b> - All authenticated users will match.<br />"
"<b>in</b> - Users currently in the channel will match.<br />"
"<b>out</b> - Users outside the channel will match.<br />"
"Note that an entry applies to either a user or a group, not both."));
@ -739,7 +739,7 @@ void ACLEditor::ACLEnableCheck() {
qcbACLGroup->clear();
qcbACLGroup->addItem(QString());
qcbACLGroup->addItem("all");
qcbACLGroup->addItem("reg");
qcbACLGroup->addItem("auth");
qcbACLGroup->addItem("in");
qcbACLGroup->addItem("out");
foreach(gs, groups)

View File

@ -89,10 +89,6 @@ ConfigDialog::ConfigDialog(QWidget *p) : QDialog(p) {
addPage(new LogConfig());
addPage(new PluginConfig());
QHBoxLayout *top = new QHBoxLayout;
top->addWidget(qlwIcons);
top->addWidget(qswPages, 1);
QHBoxLayout *buttons = new QHBoxLayout;
buttons->addStretch(1);
buttons->addWidget(applyButton);
@ -100,15 +96,19 @@ ConfigDialog::ConfigDialog(QWidget *p) : QDialog(p) {
buttons->addWidget(cancelButton);
QVBoxLayout *l = new QVBoxLayout;
l->addLayout(top);
l->addStretch(1);
l->addWidget(qswPages, 1);
l->addSpacing(12);
l->addLayout(buttons);
setLayout(l);
QHBoxLayout *top = new QHBoxLayout;
top->addWidget(qlwIcons);
top->addLayout(l);
setLayout(top);
qlwIcons->scrollTo(qlwIcons->currentIndex(), QAbstractItemView::PositionAtTop);
QMetaObject::connectSlotsByName(this);
qlwIcons->setCurrentRow(0);

View File

@ -167,7 +167,7 @@ bool DXAudioOutputPlayer::playFrames() {
dwLastPlayPos = 0;
dwTotalPlayPos = 0;
iLastwriteblock = NBLOCKS - 1;
iLastwriteblock = (NBLOCKS - 1 + g.s.iDXOutputDelay) % NBLOCKS;
bPlaying = true;
}

View File

@ -128,7 +128,7 @@ bool Group::isMember(Channel *c, QString name, int id) {
if (name == "all")
return true;
if (name == "reg")
if (name == "auth")
return (id >= 0);
if (name == "in") {

View File

@ -51,5 +51,9 @@ To build murmur, type
qmake murmur.pro
make
Note that you need to set up and configure murmur.pl as a CGI on your
webserver for user registration to work.
To enable user registration, copy murmur.pl to murmur.cgi and put it
somewhere accessible by your webserver. Make sure your webserver is
configured to execute it as a CGI, and make sure you edit it to reflect
the configuration parameters. Note that the user the CGI will run as needs
write permissions to both the database file and the directory the database
file resides in.

View File

@ -175,20 +175,20 @@ void MainWindow::createActions() {
}
void MainWindow::setupGui() {
QMenu *qmServer, *qmPlayer, *qmChannel, *qmAudio, *qmConfig, *qmHelp;
setWindowTitle(tr("Mumble -- %1").arg(QString(MUMBLE_RELEASE)));
pmModel = new PlayerModel(this);
QTreeView *view = new QTreeView(this);
qtvPlayers = view;
pmModel = new PlayerModel(this);
view->setModel(pmModel);
view->setItemDelegate(new PlayerDelegate(view));
view->setDragEnabled(true);
view->setDropIndicatorShown(true);
view->setAcceptDrops(true);
view->setIndentation(10);
qtvPlayers->setObjectName("Players");
qtvPlayers->setContextMenuPolicy(Qt::CustomContextMenu);
qtvPlayers->setModel(pmModel);
qtvPlayers->setItemDelegate(new PlayerDelegate(view));
qtvPlayers->setDragEnabled(true);
qtvPlayers->setAcceptDrops(true);
qtvPlayers->setDropIndicatorShown(true);
qtvPlayers->setIndentation(10);
qteLog = new QTextEdit(this);
qteLog->setReadOnly(true);
@ -307,6 +307,20 @@ void MainWindow::appendLog(QString entry)
qteLog->ensureCursorVisible();
}
void MainWindow::on_Players_customContextMenuRequested(const QPoint &mpos) {
QModelIndex idx = qtvPlayers->indexAt(mpos);
if (! idx.isValid())
idx = qtvPlayers->currentIndex();
Player *p = pmModel->getPlayer(idx);
if (p) {
qmPlayer->popup(qtvPlayers->mapToGlobal(mpos), qaPlayerMute);
} else {
qmChannel->popup(qtvPlayers->mapToGlobal(mpos), qaChannelACL);
}
}
void MainWindow::on_ServerConnect_triggered()
{
ConnectDialog *cd = new ConnectDialog(this);
@ -384,11 +398,12 @@ void MainWindow::on_PlayerKick_triggered()
void MainWindow::on_ChannelMenu_aboutToShow()
{
Channel *c = pmModel->getChannel(qtvPlayers->currentIndex());
QModelIndex idx = qtvPlayers->currentIndex();
Channel *c = pmModel->getChannel(idx);
if (! c) {
qaChannelAdd->setEnabled(false);
qaChannelAdd->setEnabled(g.sId != 0);
qaChannelRemove->setEnabled(false);
qaChannelACL->setEnabled(false);
qaChannelACL->setEnabled(g.sId != 0);
} else {
qaChannelAdd->setEnabled(true);
qaChannelRemove->setEnabled(true);
@ -400,13 +415,12 @@ void MainWindow::on_ChannelAdd_triggered()
{
bool ok;
Channel *c = pmModel->getChannel(qtvPlayers->currentIndex());
if (! c)
return;
int iParent = c ? c->iId : 0;
QString name = QInputDialog::getText(this, tr("Mumble"), tr("Channel Name"), QLineEdit::Normal, "", &ok);
if (ok) {
MessageChannelAdd mca;
mca.qsName = name;
mca.iParent = c->iId;
mca.iParent = iParent;
g.sh->sendMessage(&mca);
}
}
@ -430,11 +444,10 @@ void MainWindow::on_ChannelRemove_triggered()
void MainWindow::on_ChannelACL_triggered()
{
Channel *c = pmModel->getChannel(qtvPlayers->currentIndex());
if (! c)
return;
int id = c ? c->iId : 0;
MessageEditACL mea;
mea.iId = c->iId;
mea.iId = id;
mea.bQuery = true;
g.sh->sendMessage(&mea);

View File

@ -37,7 +37,8 @@
#include <QSettings>
#include <QTextEdit>
#include <QSplitter>
#include <QAbstractItemView>
#include <QTreeView>
#include <QMenu>
#include "Audio.h"
#include "TrayIcon.h"
#include "ACLEditor.h"
@ -50,9 +51,11 @@ class TextToSpeech;
class PlayerModel;
class MainWindow : public QMainWindow {
friend class PlayerModel;
Q_OBJECT
public:
PlayerModel *pmModel;
QMenu *qmServer, *qmPlayer, *qmChannel, *qmAudio, *qmConfig, *qmHelp;
QAction *qaServerConnect, *qaServerDisconnect;
QAction *qaPlayerKick, *qaPlayerMute, *qaPlayerDeaf;
QAction *qaAudioReset, *qaAudioMute, *qaAudioDeaf, *qaAudioTTS, *qaAudioStats, *qaAudioUnlink;
@ -72,12 +75,13 @@ class MainWindow : public QMainWindow {
void appendLog(QString entry);
protected:
QTextEdit *qteLog;
QAbstractItemView *qtvPlayers;
QTreeView *qtvPlayers;
void createActions();
void setupGui();
void customEvent(QEvent *evt);
virtual void closeEvent(QCloseEvent *e);
public slots:
void on_Players_customContextMenuRequested(const QPoint &pos);
void on_ServerConnect_triggered();
void on_ServerDisconnect_triggered();
void on_PlayerMenu_aboutToShow();

View File

@ -30,29 +30,153 @@
#include <QPainter>
#include <QMimeData>
#include <QTreeView>
#include <QItemSelectionModel>
#include <QStack>
#include "PlayerModel.h"
#include "MainWindow.h"
#include "Message.h"
#include "ServerHandler.h"
#include "Global.h"
ChannelItem::ChannelItem(ChannelItem *p, Channel *cptr) {
ciParent = p;
c = cptr;
QHash <Channel *, ModelItem *> ModelItem::c_qhChannels;
QHash <Player *, ModelItem *> ModelItem::c_qhPlayers;
ModelItem::ModelItem(Channel *c) {
this->cChan = c;
this->pPlayer = NULL;
c_qhChannels[c] = this;
}
void ChannelItem::dump() {
Channel *subc;
qWarning("ChannelItem %p", this);
qWarning("Parent %p", ciParent);
qWarning("Channel %p (%s)", c, qPrintable(c->qsName));
qWarning("Channels: %d", qlChannels.count());
qWarning("Players: %d", qlPlayers.count());
foreach (subc, qlChannels)
qWarning("SubChannel %d", subc->iId);
qWarning("--");
foreach (subc, qlChannels)
g.mw->pmModel->qhChannelItems[subc]->dump();
ModelItem::ModelItem(Player *p) {
this->cChan = NULL;
this->pPlayer = p;
c_qhPlayers[p] = this;
}
ModelItem::~ModelItem() {
Q_ASSERT(qlPlayers.count() == 0);
Q_ASSERT(qlChannels.count() == 0);
if (cChan)
c_qhChannels.remove(cChan);
if (pPlayer)
c_qhPlayers.remove(pPlayer);
}
ModelItem *ModelItem::parent() const {
Channel *p;
if (cChan)
p = cChan->cParent;
else
p = pPlayer->cChannel;
return c_qhChannels.value(p);
}
ModelItem *ModelItem::child(int idx) const {
if (! validRow(idx))
return NULL;
if (idx < qlChannels.count())
return c_qhChannels.value(channelAt(idx));
else
return c_qhPlayers.value(playerAt(idx));
}
bool ModelItem::validRow(int idx) const {
return ((idx >= 0) && (idx < (qlPlayers.count() + qlChannels.count())));
}
Player *ModelItem::playerAt(int idx) const {
idx -= qlChannels.count();
if ((idx>= 0) && (idx < qlPlayers.count()))
return qlPlayers.at(idx);
return NULL;
}
Channel *ModelItem::channelAt(int idx) const {
if ((idx>= 0) && (idx < qlChannels.count()))
return qlChannels.at(idx);
return NULL;
}
int ModelItem::rowOf(Channel *c) const {
return qlChannels.lastIndexOf(c);
}
int ModelItem::rowOf(Player *p) const {
int v = qlPlayers.lastIndexOf(p);
if (v != -1)
v += qlChannels.count();
return v;
}
int ModelItem::rowOfSelf() const {
ModelItem *p = parent();
Q_ASSERT(p);
if (pPlayer)
return p->rowOf(pPlayer);
else
return p->rowOf(cChan);
}
int ModelItem::rows() const {
return qlPlayers.count() + qlChannels.count();
}
int ModelItem::insertIndex(Channel *c) const {
QList<QString> qls;
Channel *cp;
foreach(cp, qlChannels)
qls << cp->qsName;
qls << c->qsName;
qSort(qls);
return qls.lastIndexOf(c->qsName);
}
int ModelItem::insertIndex(Player *p) const {
QList<QString> qls;
Player *pp;
foreach(pp, qlPlayers)
qls << pp->qsName;
qls << p->qsName;
qSort(qls);
return qls.lastIndexOf(p->qsName);
}
void ModelItem::insertChannel(Channel *c) {
int idx = insertIndex(c);
qlChannels.insert(idx, c);
}
void ModelItem::insertPlayer(Player *p) {
int idx = insertIndex(p);
qlPlayers.insert(idx, p);
}
bool ModelItem::isValid() const {
if (pPlayer && cChan)
qFatal("ModelItem: Both Player and Channel");
if (!pPlayer && !cChan)
qFatal("ModelItem: Neither Player nor Channel");
if (pPlayer)
return true;
if (cChan->qlChannels.toSet() != qlChannels.toSet())
qFatal("ModelItem: Channel mismatch");
if (cChan->qlPlayers.toSet() != qlPlayers.toSet())
qFatal("ModelItem: Player mistmatch");
return true;
}
PlayerModel::PlayerModel(QObject *p) : QAbstractItemModel(p) {
@ -63,14 +187,15 @@ PlayerModel::PlayerModel(QObject *p) : QAbstractItemModel(p) {
qiDeafenedSelf=QIcon(":/icons/deafened_self.png");
qiDeafenedServer=QIcon(":/icons/deafened_server.png");
qiAuthenticated=QIcon(":/icons/authenticated.png");
qiChannel=QIcon(":/icons/channel.png");
Channel *c = Channel::get(0);
ciRoot = new ChannelItem(NULL, c);
qhChannelItems[c] = ciRoot;
miRoot = new ModelItem(Channel::get(0));
}
PlayerModel::~PlayerModel() {
removeAll();
Q_ASSERT(ModelItem::c_qhPlayers.count() == 0);
Q_ASSERT(ModelItem::c_qhChannels.count() == 1);
}
@ -81,103 +206,102 @@ int PlayerModel::columnCount(const QModelIndex &) const
QModelIndex PlayerModel::index(int row, int column, const QModelIndex &p) const
{
ChannelItem *item;
ModelItem *item;
QModelIndex idx = QModelIndex();
qDebug("index(%d,%d,%s)",row,column,qPrintable(stringIndex(p)));
if (row == -1) {
return QModelIndex();
}
if ( ! p.isValid()) {
item = ciRoot;
item = miRoot;
} else {
item = static_cast<ChannelItem *>(p.internalPointer());
if (p.row() < 0 || p.row() >= item->qlChannels.count()) {
return idx;
}
item = qhChannelItems.value(item->qlChannels[p.row()]);
item = static_cast<ModelItem *>(p.internalPointer());
}
if (row >= (item->qlPlayers.count() + item->qlChannels.count()))
item->isValid();
if (! item->validRow(row))
return idx;
idx = createIndex(row, column, item);
Q_ASSERT(item->child(row));
idx = createIndex(row, column, item->child(row));
qDebug(" => %s",qPrintable(stringIndex(idx)));
return idx;
}
QModelIndex PlayerModel::index(Player *p, int column) const
{
ChannelItem *item = qhChannelItems.value(p->cChannel);
QModelIndex idx=createIndex(item->qlChannels.count() + item->qlPlayers.indexOf(p), column, item);
ModelItem *item = ModelItem::c_qhPlayers.value(p);
Q_ASSERT(p);
Q_ASSERT(item);
QModelIndex idx=createIndex(item->rowOfSelf(), 0, item);
return idx;
}
QModelIndex PlayerModel::index(Channel *c) const
{
ChannelItem *item = qhChannelItems.value(c->cParent);
if (! item)
ModelItem *item = ModelItem::c_qhChannels.value(c);
Q_ASSERT(c);
Q_ASSERT(item);
if (!c || ! c->parent())
return QModelIndex();
QModelIndex idx=createIndex(item->qlChannels.indexOf(c), 0, item);
QModelIndex idx=createIndex(item->rowOfSelf(), 0, item);
return idx;
}
QModelIndex PlayerModel::index(ChannelItem *ci) const
{
return index(ci->c);
}
QModelIndex PlayerModel::parent(const QModelIndex &idx) const
{
qDebug("parent(%s)",qPrintable(stringIndex(idx)));
if (! idx.isValid())
return QModelIndex();
ChannelItem *item = static_cast<ChannelItem *>(idx.internalPointer());
ModelItem *item = static_cast<ModelItem *>(idx.internalPointer());
ModelItem *pitem = item->parent();
ModelItem *gpitem = (pitem) ? pitem->parent() : NULL;
if (! item || ! item->ciParent)
return QModelIndex();
if (! pitem || ! gpitem)
return QModelIndex();
if (idx.row() >= (item->qlPlayers.count() + item->qlChannels.count()))
return QModelIndex();
QModelIndex pidx = createIndex(pitem->rowOfSelf(), 0, pitem);
QModelIndex pidx = createIndex(item->ciParent->qlChannels.indexOf(item->c), 0, item->ciParent);
qDebug(" => %s",qPrintable(stringIndex(pidx)));
return pidx;
}
int PlayerModel::rowCount(const QModelIndex &p) const
{
ChannelItem *item;
ModelItem *item;
int val = 0;
if (!p.isValid())
item = ciRoot;
item = miRoot;
else
item = static_cast<ChannelItem *>(p.internalPointer());
item = static_cast<ModelItem *>(p.internalPointer());
if (p.row() == -1) {
// Catch when it's asking for "this" item
val = item->qlPlayers.count() + item->qlChannels.count();
} else if (p.row() >= item->qlChannels.count()) {
val = 0;
} else {
item = qhChannelItems.value(item->qlChannels[p.row()]);
val = item->qlPlayers.count() + item->qlChannels.count();
}
val = item->rows();
qDebug("rowcount(%s) => %d",qPrintable(stringIndex(p)),val);
return val;
}
QString PlayerModel::stringIndex(const QModelIndex &idx) const
{
ChannelItem *item = static_cast<ChannelItem *>(idx.internalPointer());
ModelItem *item = static_cast<ModelItem *>(idx.internalPointer());
if (!idx.isValid())
return QString("invIdx");
if (!item)
return QString("invPtr");
return QString("[%1(%2,%3 %4 %5)]").arg(item->c->qsName).arg(idx.row()).arg(idx.column()).arg(item->qlChannels.count()).arg(item->qlPlayers.count());
if (item->pPlayer)
return QString("P:%1 [%2,%3]").arg(item->pPlayer->qsName).arg(idx.row()).arg(idx.column());
else
return QString("C:%1 [%2,%3]").arg(item->cChan->qsName).arg(idx.row()).arg(idx.column());
}
QVariant PlayerModel::data(const QModelIndex &idx, int role) const
@ -185,55 +309,62 @@ QVariant PlayerModel::data(const QModelIndex &idx, int role) const
if (!idx.isValid())
return QVariant();
QVariant v = otherRoles(idx.column(), role);
ModelItem *item = static_cast<ModelItem *>(idx.internalPointer());
item->isValid();
Channel *c = item->cChan;
Player *p = item->pPlayer;
if (!c && !p)
return QVariant();
QVariant v = otherRoles(idx.column(), role, (p != NULL));
if (v.isValid())
return v;
int row = idx.row();
QList<QVariant> l;
ChannelItem *item = static_cast<ChannelItem *>(idx.internalPointer());
if (row < item->qlChannels.count()) {
if (role != Qt::DisplayRole)
return QVariant();
return item->qlChannels[row]->qsName;
if (p) {
switch (role) {
case Qt::DecorationRole:
if (idx.column() == 0)
return (p->bTalking) ? qiTalkingOn : qiTalkingOff;
break;
case Qt::FontRole:
if ((idx.column() == 0) && (p->sId == g.sId)) {
QFont f = g.mw->font();
f.setBold(true);
return f;
}
break;
case Qt::DisplayRole:
if (idx.column() == 0)
return p->qsName;
if (p->iId >= 0)
l << qiAuthenticated;
if (p->bMute)
l << qiMutedServer;
if (p->bDeaf)
l << qiDeafenedServer;
if (p->bSelfMute)
l << qiMutedSelf;
if (p->bSelfDeaf)
l << qiDeafenedSelf;
return l;
default:
break;
}
} else {
row -= item->qlChannels.count();
}
if (row >= item->qlPlayers.count())
return QVariant();
Player *p = item->qlPlayers[row];
if ((role == Qt::DecorationRole) && (idx.column() == 0))
return (p->bTalking) ? qiTalkingOn : qiTalkingOff;
if ((role == Qt::FontRole) && (idx.column() == 0) && (p->sId == g.sId)) {
QFont f = g.mw->font();
f.setBold(true);
return f;
}
if (role != Qt::DisplayRole)
return QVariant();
switch(idx.column()) {
case 0:
return p->qsName;
case 1:
QList<QVariant> l;
if (p->iId >= 0)
l << qiAuthenticated;
if (p->bMute)
l << qiMutedServer;
if (p->bDeaf)
l << qiDeafenedServer;
if (p->bSelfMute)
l << qiMutedSelf;
if (p->bSelfDeaf)
l << qiDeafenedSelf;
return l;
switch (role) {
case Qt::DecorationRole:
if (idx.column() == 0)
return qiChannel;
case Qt::DisplayRole:
if (idx.column() == 0)
return c->qsName;
default:
break;
}
}
return QVariant();
}
@ -249,25 +380,28 @@ Qt::ItemFlags PlayerModel::flags(const QModelIndex &idx) const
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
QVariant PlayerModel::otherRoles(int section, int role) const
QVariant PlayerModel::otherRoles(int section, int role, bool isPlayer) const
{
switch(role) {
case Qt::ToolTipRole:
switch(section) {
case 0:
return tr("Name of player");
return isPlayer ? tr("Name of player") : tr("Name of channel");
case 1:
return tr("Player flags");
return isPlayer ? tr("Player flags") : QVariant();
}
break;
case Qt::WhatsThisRole:
switch(section) {
case 0:
return tr("This list shows all the players connected to the server. The icon to the left of the player indicates "
"whether or not they are talking:<br />"
"<img src=\":/icons/talking_on.png\" /> Talking<br />"
"<img src=\":/icons/talking_off.png\" /> Not talking"
);
if (isPlayer)
return tr("This is a player connected to the server. The icon to the left of the player indicates "
"whether or not they are talking:<br />"
"<img src=\":/icons/talking_on.png\" /> Talking<br />"
"<img src=\":/icons/talking_off.png\" /> Not talking"
);
else
return tr("This is a channel on the server. Only players in the same channel can hear each other.");
case 1:
return tr("This shows the flags the player has on the server, if any:<br />"
"<img src=\":/icons/authenticated.png\" />Authenticated user<br />"
@ -290,11 +424,6 @@ QVariant PlayerModel::headerData(int section, Qt::Orientation orientation,
if (orientation != Qt::Horizontal)
return QVariant();
QVariant v = otherRoles(section, role);
if (v.isValid())
return v;
switch(role) {
case Qt::DisplayRole:
switch(section) {
@ -308,44 +437,74 @@ QVariant PlayerModel::headerData(int section, Qt::Orientation orientation,
return QVariant();
}
void PlayerModel::unbugHide(const QModelIndex &idx) {
QAbstractItemView *v=g.mw->qtvPlayers;
QItemSelectionModel *sel=v->selectionModel();
// If we hide the current item and re-show it as a child
// an item that is nonexpanded, and then expand
// that item, we get "interresting results".
//
// A permanent fix for this would be to let the private
// pointer of the index be a struct with channel/player,
// and recalculate the correct (sorted) position for each and
// every use.
if (sel->isSelected(idx) || (idx == v->currentIndex())) {
v->clearSelection();
v->setCurrentIndex(QModelIndex());
}
}
void PlayerModel::hidePlayer(Player *p) {
Channel *c = p->cChannel;
ChannelItem *item = qhChannelItems.value(c);
ModelItem *item = ModelItem::c_qhChannels.value(c);
int row = item->qlPlayers.indexOf(p);
int rowidx = row + item->qlChannels.count();
int row = item->rowOf(p);
beginRemoveRows(index(item), rowidx, rowidx);
unbugHide(index(p));
beginRemoveRows(index(c), row, row);
c->removePlayer(p);
item->qlPlayers.removeAt(row);
item->qlPlayers.removeAll(p);
endRemoveRows();
p->cChannel = NULL;
}
void PlayerModel::showPlayer(Player *p, Channel *c) {
ChannelItem *item = qhChannelItems.value(c);
ModelItem *item = ModelItem::c_qhChannels.value(c);
QStringList names;
foreach(Player *chanp, item->qlPlayers) {
names << chanp->qsName;
}
names << p->qsName;
qSort(names);
Q_ASSERT(p);
Q_ASSERT(c);
Q_ASSERT(item);
int rows = names.indexOf(p->qsName);
int rowidx = rows + item->qlChannels.count();
int row = item->insertIndex(p);
beginInsertRows(index(item), rowidx, rowidx);
beginInsertRows(index(c), row, row);
c->addPlayer(p);
item->qlPlayers.insert(rows, p);
item->insertPlayer(p);
endInsertRows();
if (p->sId == g.sId) {
QStack<Channel *> chans;
while (c) {
chans.push(c);
c = c->cParent;
}
while (! chans.isEmpty()) {
c = chans.pop();
g.mw->qtvPlayers->setExpanded(index(c), true);
}
}
}
Player *PlayerModel::addPlayer(short id, QString name) {
Player *p = Player::add(id, this);
p->qsName = name;
new ModelItem(p);
connect(p, SIGNAL(talkingChanged(bool)), this, SLOT(playerTalkingChanged(bool)));
connect(p, SIGNAL(muteDeafChanged()), this, SLOT(playerMuteDeafChanged()));
@ -355,10 +514,13 @@ Player *PlayerModel::addPlayer(short id, QString name) {
}
void PlayerModel::removePlayer(Player *p) {
ModelItem *item = ModelItem::c_qhPlayers.value(p);
hidePlayer(p);
Player::remove(p);
delete p;
delete item;
}
void PlayerModel::movePlayer(Player *p, int id) {
@ -368,71 +530,61 @@ void PlayerModel::movePlayer(Player *p, int id) {
}
void PlayerModel::showChannel(Channel *c, Channel *p) {
ChannelItem *pitem = p ? qhChannelItems.value(p) : ciRoot;
ChannelItem *item = qhChannelItems.value(c);
ModelItem *item = ModelItem::c_qhChannels.value(p);
QStringList names;
foreach(Channel *subc, pitem->qlChannels) {
names << subc->qsName;
}
names << c->qsName;
qSort(names);
Q_ASSERT(p);
Q_ASSERT(c);
Q_ASSERT(item);
int rows = names.indexOf(c->qsName);
int row = item->insertIndex(c);
QModelIndex pidx = (pitem==ciRoot) ? QModelIndex() : index(p);
beginInsertRows(pidx, rows, rows);
pitem->qlChannels.insert(rows, c);
item->ciParent = pitem;
beginInsertRows(index(p), row, row);
p->addChannel(c);
item->insertChannel(c);
endInsertRows();
}
void PlayerModel::hideChannel(Channel *c) {
ChannelItem *myitem, *pitem;
Channel *p;
Channel *p = c->cParent;
ModelItem *item = ModelItem::c_qhChannels.value(p);
p = Channel::get(c->iParent);
int row = item->rowOf(c);
myitem=qhChannelItems.value(c);
pitem=qhChannelItems.value(p);
unbugHide(index(c));
int row = pitem->qlChannels.indexOf(c);
beginRemoveRows(parent(index(myitem)), row, row);
pitem->qlChannels.removeAt(row);
beginRemoveRows(index(p), row, row);
p->removeChannel(c);
myitem->ciParent = NULL;
item->qlChannels.removeAll(c);
endRemoveRows();
}
Channel *PlayerModel::addChannel(int id, Channel *p, QString name) {
Channel *c = Channel::add(id, name, p);
ChannelItem *ci = new ChannelItem(NULL, c);
qhChannelItems[c] = ci;
new ModelItem(c);
showChannel(c, p);
return c;
}
void PlayerModel::removeChannel(Channel *c) {
ChannelItem *myitem;
ModelItem *item;
Player *pl;
Channel *subc;
myitem=qhChannelItems.value(c);
item=ModelItem::c_qhChannels.value(c);
foreach(subc, myitem->qlChannels)
foreach(subc, item->qlChannels)
removeChannel(subc);
foreach(pl, myitem->qlPlayers)
foreach(pl, item->qlPlayers)
removePlayer(pl);
hideChannel(c);
Channel::remove(c);
delete myitem;
delete item;
delete c;
qhChannelItems.remove(c);
}
void PlayerModel::moveChannel(Channel *c, int id) {
@ -442,14 +594,13 @@ void PlayerModel::moveChannel(Channel *c, int id) {
}
void PlayerModel::removeAll() {
ChannelItem *item = ciRoot;
Player *p;
ModelItem *item = miRoot;
while (item->qlChannels.count() > 0)
removeChannel(item->qlChannels[0]);
foreach(p, item->qlPlayers)
removePlayer(p);
while (item->qlPlayers.count() > 0)
removePlayer(item->qlPlayers[0]);
}
Player *PlayerModel::getPlayer(const QModelIndex &idx) const
@ -457,16 +608,10 @@ Player *PlayerModel::getPlayer(const QModelIndex &idx) const
if (! idx.isValid())
return NULL;
ChannelItem *item;
item = static_cast<ChannelItem *>(idx.internalPointer());
ModelItem *item;
item = static_cast<ModelItem *>(idx.internalPointer());
int row = idx.row();
if (row < item->qlChannels.count())
return NULL;
row-=item->qlChannels.count();
return item->qlPlayers[row];
return item->pPlayer;
}
Channel *PlayerModel::getChannel(const QModelIndex &idx) const
@ -474,15 +619,13 @@ Channel *PlayerModel::getChannel(const QModelIndex &idx) const
if (! idx.isValid())
return NULL;
ChannelItem *item;
item = static_cast<ChannelItem *>(idx.internalPointer());
ModelItem *item;
item = static_cast<ModelItem *>(idx.internalPointer());
int row = idx.row();
if (row < item->qlChannels.count())
return item->qlChannels[row];
return item->c;
if (item->pPlayer)
return item->pPlayer->cChannel;
else
return item->cChan;
}
void PlayerModel::playerTalkingChanged(bool bTalking)
@ -551,12 +694,7 @@ bool PlayerModel::dropMimeData (const QMimeData *md, Qt::DropAction action, int
if ( ! p.isValid()) {
c = Channel::get(0);
} else {
ChannelItem *item;
item = static_cast<ChannelItem *>(p.internalPointer());
if (p.row() >= 0 && p.row() < item->qlChannels.count())
c = item->qlChannels[p.row()];
else
c = item->c;
c = getChannel(p);
}
if (! isChannel) {

View File

@ -44,16 +44,37 @@ class PlayerDelegate : public QItemDelegate {
void paint(QPainter * painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
class ChannelItem {
struct ModelItem {
friend class PlayerModel;
protected:
ChannelItem *ciParent;
Channel *c;
QList<Channel *> qlChannels;
QList<Player *> qlPlayers;
ChannelItem(ChannelItem *parent, Channel *c);
void dump();
Channel *cChan;
Player *pPlayer;
QList<Channel *> qlChannels;
QList<Player *> qlPlayers;
static QHash <Channel *, ModelItem *> c_qhChannels;
static QHash <Player *, ModelItem *> c_qhPlayers;
ModelItem(Channel *c);
ModelItem(Player *p);
~ModelItem();
ModelItem *parent() const;
ModelItem *child(int idx) const;
bool validRow(int idx) const;
Player *playerAt(int idx) const;
Channel *channelAt(int idx) const;
int rowOf(Channel *c) const;
int rowOf(Player *p) const;
int rowOfSelf() const;
int rows() const;
int insertIndex(Channel *c) const;
int insertIndex(Player *p) const;
void insertChannel(Channel *c);
void insertPlayer(Player *p);
bool isValid() const;
};
class PlayerModel : public QAbstractItemModel {
@ -63,8 +84,8 @@ protected:
QIcon qiTalkingOn, qiTalkingOff;
QIcon qiMutedSelf, qiMutedServer;
QIcon qiDeafenedSelf, qiDeafenedServer;
QIcon qiAuthenticated;
ChannelItem *ciRoot;
QIcon qiAuthenticated, qiChannel;
ModelItem *miRoot;
QHash <Channel *, ChannelItem *> qhChannelItems;
QModelIndex index(Player *, int column = 0) const;
@ -78,6 +99,8 @@ protected:
void showChannel(Channel *c, Channel *p);
QString stringIndex(const QModelIndex &index) const;
void unbugHide(const QModelIndex &index);
public:
PlayerModel(QObject *parent = 0);
~PlayerModel();
@ -108,7 +131,7 @@ public:
void removeAll();
QVariant otherRoles(int column, int role) const;
QVariant otherRoles(int column, int role, bool isPlayer) const;
public slots:
void playerTalkingChanged(bool talking);
void playerMuteDeafChanged();

View File

@ -146,7 +146,7 @@ ServerDB::ServerDB() {
if (query.next()) {
int c = query.value(0).toInt();
if (c == 0) {
query.exec("INSERT INTO acl (channel_id, priority, player_id, group_name, apply_here, apply_sub, grant, revoke) VALUES (0, 1, -1, 'reg', 1, 0, 64, 0)");
query.exec("INSERT INTO acl (channel_id, priority, player_id, group_name, apply_here, apply_sub, grant, revoke) VALUES (0, 1, -1, 'auth', 1, 0, 64, 0)");
query.exec("INSERT INTO acl (channel_id, priority, player_id, group_name, apply_here, apply_sub, grant, revoke) VALUES (0, 2, -1, 'admin', 1, 1, 1, 0)");
}
}

View File

@ -10,6 +10,7 @@
<file>icons/muted_server.png</file>
<file>icons/deafened_server.png</file>
<file>icons/authenticated.png</file>
<file>icons/channel.png</file>
<file>icons/config_basic.png</file>
<file>icons/config_dsound.png</file>
<file>icons/config_msgs.png</file>