From cd122ca8e0d2c0ffc5397e0a813c75d791a7e6e3 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Wed, 24 Oct 2007 22:10:25 +0000 Subject: [PATCH] Added ModelPropertyMapper which allows to keep track of /current/ changes in the model and propagate the changes to connected qobjects. --- src/client/buffertreemodel.cpp | 29 ++++++++- src/client/buffertreemodel.h | 15 ++++- src/client/client.pri | 4 +- src/client/modelpropertymapper.cpp | 100 +++++++++++++++++++++++++++++ src/client/modelpropertymapper.h | 73 +++++++++++++++++++++ src/common/ircchannel.cpp | 4 +- src/common/networkinfo.cpp | 8 +-- src/qtui/bufferview.cpp | 1 + src/qtui/bufferviewfilter.cpp | 9 +-- src/qtui/mainwin.cpp | 40 ++++++------ 10 files changed, 244 insertions(+), 39 deletions(-) create mode 100644 src/client/modelpropertymapper.cpp create mode 100644 src/client/modelpropertymapper.h diff --git a/src/client/buffertreemodel.cpp b/src/client/buffertreemodel.cpp index 7117b07b..a881b5f3 100644 --- a/src/client/buffertreemodel.cpp +++ b/src/client/buffertreemodel.cpp @@ -21,7 +21,9 @@ #include // FIXME Dependency on QtGui! #include "buffertreemodel.h" -#include "selectionmodelsynchronizer.h" + +#include "mappedselectionmodel.h" +#include #include "bufferinfo.h" #include "client.h" @@ -119,8 +121,15 @@ Qt::ItemFlags NetworkTreeItem::flags() const { *****************************************/ BufferTreeModel::BufferTreeModel(QObject *parent) : TreeModel(BufferTreeModel::defaultHeader(), parent), - _selectionModelSynchronizer(new SelectionModelSynchronizer(this)) + _selectionModelSynchronizer(new SelectionModelSynchronizer(this)), + _propertyMapper(new ModelPropertyMapper(this)) { + _propertyMapper->setModel(this); + delete _propertyMapper->selectionModel(); + MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(this); + _propertyMapper->setSelectionModel(mappedSelectionModel); + synchronizeSelectionModel(mappedSelectionModel); + connect(_selectionModelSynchronizer, SIGNAL(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags)), this, SLOT(setCurrentIndex(QModelIndex, QItemSelectionModel::SelectionFlags))); } @@ -131,6 +140,22 @@ QListBufferTreeModel::defaultHeader() { return data; } +void BufferTreeModel::synchronizeSelectionModel(MappedSelectionModel *selectionModel) { + selectionModelSynchronizer()->addSelectionModel(selectionModel); +} + +void BufferTreeModel::synchronizeView(QAbstractItemView *view) { + MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(view->model()); + selectionModelSynchronizer()->addSelectionModel(mappedSelectionModel); + Q_ASSERT(mappedSelectionModel); + delete view->selectionModel(); + view->setSelectionModel(mappedSelectionModel); +} + +void BufferTreeModel::mapProperty(int column, int role, QObject *target, const QByteArray &property) { + propertyMapper()->addMapping(column, role, target, property); +} + bool BufferTreeModel::isBufferIndex(const QModelIndex &index) const { // not so purdy... return parent(index) != QModelIndex(); diff --git a/src/client/buffertreemodel.h b/src/client/buffertreemodel.h index f300d986..70a96193 100644 --- a/src/client/buffertreemodel.h +++ b/src/client/buffertreemodel.h @@ -26,11 +26,16 @@ #include "treemodel.h" #include "buffer.h" +#include + #include class BufferInfo; -class SelectionModelSynchronizer; +#include "selectionmodelsynchronizer.h" +#include "modelpropertymapper.h" +class MappedSelectionModel; +class QAbstractItemView; /***************************************** * Fancy Buffer Items @@ -91,6 +96,11 @@ public: static QList defaultHeader(); inline SelectionModelSynchronizer *selectionModelSynchronizer() { return _selectionModelSynchronizer; } + inline ModelPropertyMapper *propertyMapper() { return _propertyMapper; } + + void synchronizeSelectionModel(MappedSelectionModel *selectionModel); + void synchronizeView(QAbstractItemView *view); + void mapProperty(int column, int role, QObject *target, const QByteArray &property); public slots: void bufferUpdated(Buffer *); @@ -113,7 +123,8 @@ private: QMimeData *mimeData(const QModelIndexList &) const; bool dropMimeData(const QMimeData *, Qt::DropAction, int, int, const QModelIndex &); - SelectionModelSynchronizer *_selectionModelSynchronizer; + QPointer _selectionModelSynchronizer; + QPointer _propertyMapper; Buffer *currentBuffer; }; diff --git a/src/client/client.pri b/src/client/client.pri index 56442f8c..7a47f5e9 100644 --- a/src/client/client.pri +++ b/src/client/client.pri @@ -1,4 +1,4 @@ DEPMOD = common contrib/qxt QT_MOD = core network gui # gui is needed just for QColor... FIXME! -SRCS += buffer.cpp buffertreemodel.cpp client.cpp clientsettings.cpp treemodel.cpp mappedselectionmodel.cpp selectionmodelsynchronizer.cpp -HDRS += buffer.h buffertreemodel.h client.h clientsettings.h quasselui.h treemodel.h mappedselectionmodel.h selectionmodelsynchronizer.h +SRCS += buffer.cpp buffertreemodel.cpp client.cpp clientsettings.cpp treemodel.cpp mappedselectionmodel.cpp selectionmodelsynchronizer.cpp modelpropertymapper.cpp +HDRS += buffer.h buffertreemodel.h client.h clientsettings.h quasselui.h treemodel.h mappedselectionmodel.h selectionmodelsynchronizer.h modelpropertymapper.h diff --git a/src/client/modelpropertymapper.cpp b/src/client/modelpropertymapper.cpp new file mode 100644 index 00000000..31f8d546 --- /dev/null +++ b/src/client/modelpropertymapper.cpp @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "modelpropertymapper.h" + +#include +#include + +ModelPropertyMapper::ModelPropertyMapper(QObject *parent) + : QObject(parent), + _model(0), + _selectionModel(0) +{ +} + +ModelPropertyMapper::~ModelPropertyMapper() { +} + +void ModelPropertyMapper::setModel(QAbstractItemModel *model) { + if(_model) + setSelectionModel(new QItemSelectionModel(model)); + _model = model; +} + +QAbstractItemModel *ModelPropertyMapper::model() const { + return _model; +} + +void ModelPropertyMapper::setSelectionModel(QItemSelectionModel *selectionModel) { + if(selectionModel->model() != model()) { + qWarning() << "cannot set itemSelectionModel" << selectionModel << "which uses different basemodel than" << model(); + return; + } + if(_selectionModel) + disconnect(_selectionModel, 0, this, 0); + _selectionModel = selectionModel; + connect(_selectionModel, SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), + this, SLOT(setCurrentRow(QModelIndex, QModelIndex))); + + setCurrentRow(selectionModel->currentIndex(), QModelIndex()); +} + +QItemSelectionModel *ModelPropertyMapper::selectionModel() const { + return _selectionModel; +} + +void ModelPropertyMapper::addMapping(int column, int role, QObject *target, const QByteArray &property) { + Mapping mapping(column, role, target, property); + if(!_mappings.contains(mapping)) + _mappings.append(mapping); +} + +void ModelPropertyMapper::removeMapping(int column, int role, QObject *target, const QByteArray &property) { + if(column == 0 && role == 0 && target == 0 && !property.isNull()) { + _mappings.clear(); + return; + } + + if(column == 0 && role == 0 && !property.isNull()) { + QList::iterator iter; + for(iter = _mappings.begin(); iter != _mappings.end(); iter++) { + if((*iter).target == target) + _mappings.erase(iter); + } + return; + } + _mappings.removeAll(Mapping(column, role, target, property)); +} + +void ModelPropertyMapper::setCurrentRow(const QModelIndex ¤t, const QModelIndex &previous) { + Q_UNUSED(previous) + foreach(Mapping mapping, _mappings) { + QModelIndex index = current.sibling(current.row(), mapping.column); + // qDebug() << mapping.target << mapping.property << index.data(mapping.role); + mapping.target->setProperty(mapping.property, index.data(mapping.role)); + } +} + + +void ModelPropertyMapper::targetDestroyed() { + QObject *obj = static_cast(sender()); + removeMapping(0, 0, obj, QByteArray()); +} diff --git a/src/client/modelpropertymapper.h b/src/client/modelpropertymapper.h new file mode 100644 index 00000000..988efa8f --- /dev/null +++ b/src/client/modelpropertymapper.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2005-07 by The Quassel Team * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _MODELPROPERTYMAPPER_H_ +#define _MODELPROPERTYMAPPER_H_ + +#include +#include +#include + +class QAbstractItemModel; +class QItemSelectionModel; + + +class ModelPropertyMapper : public QObject { + Q_OBJECT + +public: + ModelPropertyMapper(QObject *parent = 0); + virtual ~ModelPropertyMapper(); + + void setModel(QAbstractItemModel *model); + QAbstractItemModel *model() const; + + void setSelectionModel(QItemSelectionModel *selectionModel); + QItemSelectionModel *selectionModel() const; + + void addMapping(int column, int role, QObject *target, const QByteArray &property); + void removeMapping(int column, int role, QObject *target, const QByteArray &property); + +public slots: + void setCurrentRow(const QModelIndex ¤t, const QModelIndex &previous); + +private slots: + void targetDestroyed(); + +private: + struct Mapping { + int column; + int role; + QPointer target; + QByteArray property; + + Mapping(int _column, int _role, QObject *_target, const QByteArray &_property) + : column(_column), role(_role), target(_target), property(_property) {}; + inline bool operator==(const Mapping &other) { + return (column == other.column && role == other.role && target == other.target && property == other.property); } + }; + + QPointer _model; + QPointer _selectionModel; + QList _mappings; + +}; + +#endif diff --git a/src/common/ircchannel.cpp b/src/common/ircchannel.cpp index 2233861b..b9caebd0 100644 --- a/src/common/ircchannel.cpp +++ b/src/common/ircchannel.cpp @@ -192,9 +192,7 @@ void IrcChannel::initSetUserModes(const QVariantMap &usermodes) { } void IrcChannel::ircUserDestroyed() { - IrcUser *ircUser = qobject_cast(sender()); - // in case this assert triggers we probably need a static_cast - // dynamic_casts seem to screw things up when using the destroyed signal + IrcUser *ircUser = static_cast(sender()); Q_ASSERT(ircUser); part(ircUser); } diff --git a/src/common/networkinfo.cpp b/src/common/networkinfo.cpp index f79ef5c5..24ed8d7f 100644 --- a/src/common/networkinfo.cpp +++ b/src/common/networkinfo.cpp @@ -310,17 +310,13 @@ void NetworkInfo::ircUserNickChanged(QString newnick) { } void NetworkInfo::ircUserDestroyed() { - IrcUser *ircuser = qobject_cast(sender()); - // in case this assert triggers we probably need a static_cast - // dynamic_casts seem to screw things up when using the destroyed signal + IrcUser *ircuser = static_cast(sender()); Q_ASSERT(ircuser); _ircUsers.remove(_ircUsers.key(ircuser)); } void NetworkInfo::channelDestroyed() { - IrcChannel *channel = qobject_cast(sender()); - // in case this assert triggers we probably need a static_cast - // dynamic_casts seem to screw things up when using the destroyed signal + IrcChannel *channel = static_cast(sender()); Q_ASSERT(channel); _ircChannels.remove(_ircChannels.key(channel)); } diff --git a/src/qtui/bufferview.cpp b/src/qtui/bufferview.cpp index 40995ad7..4ad1138e 100644 --- a/src/qtui/bufferview.cpp +++ b/src/qtui/bufferview.cpp @@ -56,6 +56,7 @@ void BufferView::setFilteredModel(QAbstractItemModel *model, BufferViewFilter::M } void BufferView::setModel(QAbstractItemModel *model) { + delete selectionModel(); QTreeView::setModel(model); init(); diff --git a/src/qtui/bufferviewfilter.cpp b/src/qtui/bufferviewfilter.cpp index 6bcfb6ad..d30c3133 100644 --- a/src/qtui/bufferviewfilter.cpp +++ b/src/qtui/bufferviewfilter.cpp @@ -23,13 +23,14 @@ /***************************************** * The Filter for the Tree View *****************************************/ -BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, const Modes &filtermode, const QStringList &nets) : QSortFilterProxyModel(model) { +BufferViewFilter::BufferViewFilter(QAbstractItemModel *model, const Modes &filtermode, const QStringList &nets) + : QSortFilterProxyModel(model), + mode(filtermode), + networks(nets) +{ setSourceModel(model); setSortRole(BufferTreeModel::BufferNameRole); setSortCaseSensitivity(Qt::CaseInsensitive); - - mode = filtermode; - networks = nets; connect(model, SIGNAL(invalidateFilter()), this, SLOT(invalidateMe())); } diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index ee253097..12bd7205 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -86,23 +86,29 @@ void MainWin::init() { if(serverListDlg->showOnStartup()) { showServerList(); } - + + setDockNestingEnabled(true); + + // TESTING -// setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); -// setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); + setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); -// setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); -// setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); - -// QDockWidget *dock = new QDockWidget("Topic Dock", this); -// dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); + setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); -// TopicWidget *topicwidget = new TopicWidget(dock); -// dock->setWidget(topicwidget); - -// addDockWidget(Qt::TopDockWidgetArea, dock); -// ui.menuViews->addAction(dock->toggleViewAction()); + QDockWidget *dock = new QDockWidget("Topic Dock", this); + dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); + + TopicWidget *topicwidget = new TopicWidget(dock); + dock->setWidget(topicwidget); + + Client::bufferModel()->mapProperty(0, Qt::DisplayRole, topicwidget, "topic"); + + addDockWidget(Qt::TopDockWidgetArea, dock); + + ui.menuViews->addAction(dock->toggleViewAction()); } @@ -159,13 +165,7 @@ void MainWin::addBufferView(const QString &viewname, QAbstractItemModel *model, //create the view and initialize it's filter BufferView *view = new BufferView(dock); view->setFilteredModel(model, mode, nets); - - MappedSelectionModel *mappedSelectionModel = new MappedSelectionModel(view->model()); - Client::bufferModel()->selectionModelSynchronizer()->addSelectionModel(mappedSelectionModel); - Q_ASSERT(mappedSelectionModel); - delete view->selectionModel(); - view->setSelectionModel(mappedSelectionModel); - + Client::bufferModel()->synchronizeView(view); dock->setWidget(view); addDockWidget(Qt::LeftDockWidgetArea, dock); -- 2.20.1