[SCM] ktp-contact-list packaging branch, master, updated. debian/15.12.1-2-1070-g6c56f91
Maximiliano Curia
maxy at moszumanska.debian.org
Sat May 28 00:06:28 UTC 2016
Gitweb-URL: http://git.debian.org/?p=pkg-kde/applications/ktp-contact-list.git;a=commitdiff;h=8f0624f
The following commit has been merged in the master branch:
commit 8f0624fa92f34fde82a6ea89c80e195edf50cc8b
Author: Martin Klapetek <martin.klapetek at gmail.com>
Date: Sat May 21 09:58:05 2011 +0200
Add groups support
Reviewed-by: David Edmundson
REVIEW: 101380
---
CMakeLists.txt | 4 +
account-filter-model.cpp | 92 +++++---
account-filter-model.h | 6 +
contact-delegate.cpp | 48 ++--
groups-model-item.cpp | 116 ++++++++++
contact-model-item.h => groups-model-item.h | 41 ++--
groups-model.cpp | 345 ++++++++++++++++++++++++++++
groups-model.h | 94 ++++++++
main-widget.cpp | 63 ++++-
main-widget.h | 3 +
proxy-tree-node.cpp | 84 +++++++
tree-node.h => proxy-tree-node.h | 41 ++--
tree-node.h | 2 +
13 files changed, 838 insertions(+), 101 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 919df77..f2247eb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,6 +36,10 @@ set (contactlist_SRCS
add-contact-dialog.cpp
remove-contact-dialog.cpp
fetch-avatar-job.cpp
+
+ groups-model-item.cpp
+ groups-model.cpp
+ proxy-tree-node.cpp
)
diff --git a/account-filter-model.cpp b/account-filter-model.cpp
index 75f2126..4a8df8c 100644
--- a/account-filter-model.cpp
+++ b/account-filter-model.cpp
@@ -21,6 +21,7 @@
#include "account-filter-model.h"
#include "accounts-model.h"
+#include "groups-model.h"
#include <KDebug>
@@ -29,7 +30,9 @@ AccountFilterModel::AccountFilterModel(QObject *parent)
m_filterOfflineUsers(false),
m_filterByName(false)
{
-
+ //FIXME FIXME FIXME -- this is an ugly workaround for some filter-misbehaving issues, need to investigate
+ connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(invalidate()));
}
void AccountFilterModel::filterOfflineUsers(bool filterOfflineUsers)
@@ -59,20 +62,27 @@ bool AccountFilterModel::filterAcceptsRow(int source_row, const QModelIndex &sou
//filter offline users out
if (m_filterOfflineUsers &&
((source_parent.child(source_row, 0).data(AccountsModel::PresenceTypeRole).toUInt()
- == Tp::ConnectionPresenceTypeOffline) ||
+ == Tp::ConnectionPresenceTypeOffline) ||
(source_parent.child(source_row, 0).data(AccountsModel::PresenceTypeRole).toUInt()
- == Tp::ConnectionPresenceTypeUnknown))) {
+ == Tp::ConnectionPresenceTypeUnknown))) {
rowAccepted = false;
}
} else {
- if (!sourceModel()->index(source_row, 0).data(AccountsModel::EnabledRole).toBool()) {
- rowAccepted = false;
- }
- if (sourceModel()->index(source_row, 0).data(AccountsModel::ConnectionStatusRole).toUInt()
- != Tp::ConnectionStatusConnected) {
-
- rowAccepted = false;
+ QModelIndex index = sourceModel()->index(source_row, 0);
+ if (index.isValid()) {
+ if (m_groupsActive) {
+ rowAccepted = true;
+ } else {
+ if (!index.data(AccountsModel::EnabledRole).toBool()) {
+ rowAccepted = false;
+ }
+ if (index.data(AccountsModel::ConnectionStatusRole).toUInt()
+ != Tp::ConnectionStatusConnected) {
+
+ rowAccepted = false;
+ }
+ }
}
}
@@ -95,34 +105,34 @@ void AccountFilterModel::clearFilterString()
bool AccountFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
{
- uint leftPresence;
- uint rightPresence;
-
- QString leftDisplayedName = sourceModel()->data(left).toString();
- QString rightDisplayedName = sourceModel()->data(right).toString();
-
- if (sortRole() == AccountsModel::PresenceTypeRole) {
- leftPresence = sourceModel()->data(left, AccountsModel::PresenceTypeRole).toUInt();
- rightPresence = sourceModel()->data(right, AccountsModel::PresenceTypeRole).toUInt();
-
- if (leftPresence == rightPresence) {
- return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
- } else {
- if (leftPresence == Tp::ConnectionPresenceTypeAvailable) {
- return true;
- }
- if (leftPresence == Tp::ConnectionPresenceTypeUnset ||
- leftPresence == Tp::ConnectionPresenceTypeOffline ||
- leftPresence == Tp::ConnectionPresenceTypeUnknown ||
- leftPresence == Tp::ConnectionPresenceTypeError) {
- return false;
+ uint leftPresence;
+ uint rightPresence;
+
+ QString leftDisplayedName = sourceModel()->data(left).toString();
+ QString rightDisplayedName = sourceModel()->data(right).toString();
+
+ if (sortRole() == AccountsModel::PresenceTypeRole) {
+ leftPresence = sourceModel()->data(left, AccountsModel::PresenceTypeRole).toUInt();
+ rightPresence = sourceModel()->data(right, AccountsModel::PresenceTypeRole).toUInt();
+
+ if (leftPresence == rightPresence) {
+ return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
+ } else {
+ if (leftPresence == Tp::ConnectionPresenceTypeAvailable) {
+ return true;
+ }
+ if (leftPresence == Tp::ConnectionPresenceTypeUnset ||
+ leftPresence == Tp::ConnectionPresenceTypeOffline ||
+ leftPresence == Tp::ConnectionPresenceTypeUnknown ||
+ leftPresence == Tp::ConnectionPresenceTypeError) {
+ return false;
+ }
+
+ return leftPresence < rightPresence;
}
-
- return leftPresence < rightPresence;
+ } else {
+ return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
}
- } else {
- return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
- }
}
void AccountFilterModel::setSortByPresence(bool enabled)
@@ -139,4 +149,14 @@ bool AccountFilterModel::isSortedByPresence() const
return sortRole() == AccountsModel::PresenceTypeRole;
}
+bool AccountFilterModel::groupsActive() const
+{
+ return m_groupsActive;
+}
+
+void AccountFilterModel::setGroupsActive(bool active)
+{
+ m_groupsActive = active;
+}
+
#include "account-filter-model.moc"
diff --git a/account-filter-model.h b/account-filter-model.h
index 6591355..007c2a9 100644
--- a/account-filter-model.h
+++ b/account-filter-model.h
@@ -48,6 +48,9 @@ public:
*/
bool isSortedByPresence() const;
+ bool groupsActive() const;
+ void setGroupsActive(bool active);
+
public slots:
void filterOfflineUsers(bool filterOfflineUsers);
@@ -73,6 +76,9 @@ private:
/// Holds the string which is searched in the model
QString m_filterString;
+
+ /// True if the source is groups model
+ bool m_groupsActive;
};
#endif // ACCOUNTFILTERMODEL_H
diff --git a/contact-delegate.cpp b/contact-delegate.cpp
index 209e715..e1e444a 100644
--- a/contact-delegate.cpp
+++ b/contact-delegate.cpp
@@ -24,9 +24,10 @@
#include <QtGui/QPainter>
#include <QtGui/QPainterPath>
+#include <QtGui/QToolTip>
#include <QApplication>
#include <QStyle>
-#include <QtGui/QToolTip>
+#include <QHelpEvent>
#include <KIconLoader>
#include <KIcon>
@@ -36,7 +37,9 @@
#include "accounts-model.h"
#include "contact-model-item.h"
-#include <QHelpEvent>
+#include "proxy-tree-node.h"
+#include "groups-model-item.h"
+#include "groups-model.h"
const int SPACING = 4;
const int AVATAR_SIZE = 32;
@@ -67,7 +70,7 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
- bool isContact = !index.data(AccountsModel::AliasRole).toString().isEmpty();
+ bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
if (isContact) {
QRect iconRect = optV4.rect;
@@ -182,25 +185,35 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
QString counts;// = QString(" (%1/%2)").arg(index.data(AccountsModel::).toString(),
// index.data(ModelRoles::AccountAllContactsCountRole).toString());
- painter->fillRect(groupRect, m_palette->color(QPalette::AlternateBase));
-
- painter->drawPixmap(accountGroupRect, KIcon(index.data(AccountsModel::IconRole).toString())
- .pixmap(ACCOUNT_ICON_SIZE, ACCOUNT_ICON_SIZE));
+ if (index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<AccountsModelItem*>()) {
+ painter->drawPixmap(accountGroupRect, KIcon(index.data(AccountsModel::IconRole).toString())
+ .pixmap(ACCOUNT_ICON_SIZE, ACCOUNT_ICON_SIZE));
+ } else {
+ painter->drawPixmap(accountGroupRect, KIconLoader::global()->loadIcon(QString("system-users"),
+ KIconLoader::Desktop));
+ }
painter->setPen(m_palette->color(QPalette::WindowText));
painter->setFont(groupFont);
painter->drawText(groupLabelRect, Qt::AlignVCenter | Qt::AlignRight,
- index.data(AccountsModel::DisplayNameRole).toString().append(counts));
+ index.data(GroupsModel::GroupNameRole).toString().append(counts));
QPen thinLinePen;
thinLinePen.setWidth(0);
- thinLinePen.setCosmetic(true);
- thinLinePen.setColor(m_palette->color(QPalette::ButtonText));
+ thinLinePen.setColor(m_palette->color(QPalette::Disabled, QPalette::Button));
painter->setPen(thinLinePen);
+ painter->setRenderHint(QPainter::Antialiasing, false);
- painter->drawLine(groupRect.x(), groupRect.y(), groupRect.width(), groupRect.y());
- painter->drawLine(groupRect.x(), groupRect.bottom(), groupRect.width(), groupRect.bottom());
+ QFontMetrics fm = painter->fontMetrics();
+ int groupNameWidth = fm.width(index.data(GroupsModel::GroupNameRole).toString());
+
+ painter->drawLine(expandSignRect.right() + SPACING * 2,
+ groupRect.y() + groupRect.height() / 2,
+ groupRect.width() - groupNameWidth - SPACING * 2,
+ groupRect.y() + groupRect.height() / 2);
+
+ painter->setRenderHint(QPainter::Antialiasing, true);
QStyleOption expandSignOption = option;
expandSignOption.rect = expandSignRect;
@@ -218,12 +231,13 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
QSize ContactDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
-// if(option.state & QStyle::State_Selected)
-// kDebug() << index.data(ModelRoles::UserNameRole).toString();
+ bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
- if (!index.data(AccountsModel::AliasRole).toString().isEmpty()) {
+ if (isContact) {
return QSize(0, 32 + 4 * SPACING);
- } else return QSize(0, 20);
+ } else {
+ return QSize(0, 20);
+ }
}
void ContactDelegate::hideStatusMessageSlot(const QModelIndex& index)
@@ -330,8 +344,6 @@ bool ContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, cons
* * Contact is blocked will only show if the contact is blocked, else no display.
*/
- kDebug() << contactAvatar;
-
QString table;
table += QString("<table><th colspan='2' align='center'><img src='%2' height='16' width='16' /> %3</th>").arg(cmIconPath, displayName);
if (contactAvatar.isEmpty() || QPixmap(contactAvatar).isNull()) {
diff --git a/groups-model-item.cpp b/groups-model-item.cpp
new file mode 100644
index 0000000..6eec952
--- /dev/null
+++ b/groups-model-item.cpp
@@ -0,0 +1,116 @@
+/*
+ * Contact groups model item, represents a group in the contactlist tree
+ * This file is based on TelepathyQt4Yell Models
+ *
+ * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <TelepathyQt4/Account>
+#include <TelepathyQt4/ContactManager>
+
+#include "groups-model-item.h"
+#include "groups-model.h"
+#include "accounts-model.h"
+#include "proxy-tree-node.h"
+#include "contact-model-item.h"
+
+struct GroupsModelItem::Private
+{
+ Private(const QString &groupName)
+ : mGroupName(groupName)
+ {
+ }
+
+ void setGroupName(const QString &value);
+ QString groupName();
+
+ QString mGroupName;
+};
+
+void GroupsModelItem::Private::setGroupName(const QString& value)
+{
+ mGroupName = value;
+}
+
+QString GroupsModelItem::Private::groupName()
+{
+ return mGroupName;
+}
+
+GroupsModelItem::GroupsModelItem(const QString &groupName)
+ : mPriv(new Private(groupName))
+{
+}
+
+GroupsModelItem::~GroupsModelItem()
+{
+ delete mPriv;
+}
+
+QVariant GroupsModelItem::data(int role) const
+{
+ switch (role) {
+ case AccountsModel::ItemRole:
+ return QVariant::fromValue((GroupsModelItem*)this);
+ case GroupsModel::GroupNameRole:
+ return mPriv->mGroupName;
+ default:
+ return QVariant();
+ }
+}
+
+bool GroupsModelItem::setData(int role, const QVariant &value)
+{
+ switch (role) {
+ case GroupsModel::GroupNameRole:
+ setGroupName(value.toString());
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GroupsModelItem::setGroupName(const QString& value)
+{
+ mPriv->setGroupName(value);
+}
+
+QString GroupsModelItem::groupName()
+{
+ return mPriv->groupName();
+}
+
+void GroupsModelItem::addProxyContact(ProxyTreeNode *proxyNode)
+{
+ emit childrenAdded(this, QList<TreeNode*>() << proxyNode);
+}
+
+void GroupsModelItem::removeProxyContact(ProxyTreeNode *proxyNode)
+{
+ emit childrenRemoved(this, indexOf(proxyNode), indexOf(proxyNode));
+}
+
+void GroupsModelItem::removeContact(ContactModelItem* contact)
+{
+ for (int i = 0; i < children().size(); i++) {
+ ProxyTreeNode* proxyNode = qobject_cast<ProxyTreeNode*>(childAt(i));
+ if (proxyNode->data(AccountsModel::ItemRole).value<ContactModelItem*>() == contact) {
+ proxyNode->remove();
+ }
+ }
+}
diff --git a/contact-model-item.h b/groups-model-item.h
similarity index 56%
copy from contact-model-item.h
copy to groups-model-item.h
index 772becd..63f3973 100644
--- a/contact-model-item.h
+++ b/groups-model-item.h
@@ -1,8 +1,8 @@
/*
- * Contacts model item, represents a contact in the contactlist tree
+ * Contact groups model item, represents a group in the contactlist tree
* This file is based on TelepathyQt4Yell Models
*
- * Copyright (C) 2010 Collabora Ltd. <info at collabora.co.uk>
+ * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
* Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
*
* This library is free software; you can redistribute it and/or
@@ -20,31 +20,43 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef TELEPATHY_CONTACT_MODEL_ITEM_H
-#define TELEPATHY_CONTACT_MODEL_ITEM_H
+#ifndef TELEPATHY_GROUPS_MODEL_ITEM_H
+#define TELEPATHY_GROUPS_MODEL_ITEM_H
+#include <TelepathyQt4/Constants>
+#include <TelepathyQt4/Contact>
#include <TelepathyQt4/Types>
#include <QtCore/QVariant> //needed for declare metatype
#include "tree-node.h"
-class ContactModelItem : public TreeNode
+class ContactModelItem;
+class ProxyTreeNode;
+
+class GroupsModelItem : public TreeNode
{
Q_OBJECT
- Q_DISABLE_COPY(ContactModelItem)
+ Q_DISABLE_COPY(GroupsModelItem)
public:
- ContactModelItem(const Tp::ContactPtr &contact);
- virtual ~ContactModelItem();
+ GroupsModelItem(const QString &groupName);
+ virtual ~GroupsModelItem();
Q_INVOKABLE virtual QVariant data(int role) const;
- Q_INVOKABLE virtual bool setData(int role, const QVariant &value);
+ virtual bool setData(int role, const QVariant &value);
+
+ Q_INVOKABLE void setGroupName(const QString &value);
+ QString groupName();
+
+ void addProxyContact(ProxyTreeNode* proxyNode);
+ void removeProxyContact(ProxyTreeNode* proxyNode);
+ void removeContact(ContactModelItem* contact);
- Tp::ContactPtr contact() const;
+// void clearContacts();
+
+private Q_SLOTS:
-public Q_SLOTS:
- void onChanged();
private:
struct Private;
@@ -52,7 +64,6 @@ private:
Private *mPriv;
};
-Q_DECLARE_METATYPE(ContactModelItem*);
-
+Q_DECLARE_METATYPE(GroupsModelItem*);
-#endif // TELEPATHY_CONTACT_MODEL_ITEM_H
+#endif // TELEPATHY_GROUPS_MODEL_ITEM_H
diff --git a/groups-model.cpp b/groups-model.cpp
new file mode 100644
index 0000000..2b7fec9
--- /dev/null
+++ b/groups-model.cpp
@@ -0,0 +1,345 @@
+/*
+ * Contact groups model
+ * This file is based on TelepathyQt4Yell Models
+ *
+ * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <TelepathyQt4/ContactManager>
+#include <TelepathyQt4/Contact>
+#include <TelepathyQt4/PendingReady>
+
+#include "groups-model.h"
+#include "groups-model-item.h"
+#include "proxy-tree-node.h"
+#include "accounts-model.h"
+#include "contact-model-item.h"
+
+#include <KDebug>
+
+struct GroupsModel::Private
+{
+ Private(AccountsModel *am)
+ : mAM(am)
+ {
+ }
+
+ TreeNode *node(const QModelIndex &index) const;
+
+ AccountsModel *mAM;
+ TreeNode *mTree;
+};
+
+TreeNode *GroupsModel::Private::node(const QModelIndex &index) const
+{
+ TreeNode *node = reinterpret_cast<TreeNode *>(index.internalPointer());
+ return node ? node : mTree;
+}
+
+GroupsModel::GroupsModel(AccountsModel *am, QObject *parent)
+ : QAbstractItemModel(parent),
+ mPriv(new GroupsModel::Private(am))
+{
+ mPriv->mTree = new TreeNode;
+
+ connect(mPriv->mTree,
+ SIGNAL(changed(TreeNode*)),
+ SLOT(onItemChanged(TreeNode*)));
+
+ connect(mPriv->mTree,
+ SIGNAL(childrenAdded(TreeNode*,QList<TreeNode*>)),
+ SLOT(onItemsAdded(TreeNode*,QList<TreeNode*>)));
+
+ connect(mPriv->mTree,
+ SIGNAL(childrenRemoved(TreeNode*,int,int)),
+ SLOT(onItemsRemoved(TreeNode*,int,int)));
+
+ loadAccountsModel();
+ QHash<int, QByteArray> roles;
+ roles[GroupNameRole] = "groupName";
+ setRoleNames(roles);
+}
+
+GroupsModel::~GroupsModel()
+{
+ delete mPriv->mTree;
+ delete mPriv;
+}
+
+int GroupsModel::columnCount(const QModelIndex &parent) const
+{
+ return 1;
+}
+
+int GroupsModel::rowCount(const QModelIndex &parent) const
+{
+ return mPriv->node(parent)->size();
+}
+
+QVariant GroupsModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ return mPriv->node(index)->data(role);
+}
+
+Qt::ItemFlags GroupsModel::flags(const QModelIndex &index) const
+{
+ if (index.isValid()) {
+ return Qt::ItemIsEnabled;
+ }
+
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+}
+
+bool GroupsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (index.isValid()) {
+ mPriv->node(index)->setData(role, value);
+ }
+
+ return false;
+}
+
+QModelIndex GroupsModel::index(int row, int column, const QModelIndex &parent) const
+{
+ TreeNode *parentNode = mPriv->node(parent);
+ if (row < parentNode->size()) {
+ return createIndex(row, column, parentNode->childAt(row));
+ }
+
+ return QModelIndex();
+}
+
+QModelIndex GroupsModel::index(TreeNode *node) const
+{
+ if (node->parent()) {
+ return createIndex(node->parent()->indexOf(node), 0, node);
+ } else {
+ return QModelIndex();
+ }
+}
+
+QModelIndex GroupsModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return QModelIndex();
+ }
+
+ TreeNode *currentNode = mPriv->node(index);
+ if (currentNode->parent()) {
+ return GroupsModel::index(currentNode->parent());
+ } else {
+ // no parent: return root node
+ return QModelIndex();
+ }
+}
+
+void GroupsModel::onItemChanged(TreeNode* node)
+{
+ emit dataChanged(index(node), index(node));
+}
+
+void GroupsModel::onItemsAdded(TreeNode *parent, const QList<TreeNode *> &nodes)
+{
+ QModelIndex parentIndex = index(parent);
+ int currentSize = rowCount(parentIndex);
+ beginInsertRows(parentIndex, currentSize, currentSize + nodes.size() - 1);
+ foreach (TreeNode *node, nodes) {
+ parent->addChild(node);
+ }
+ endInsertRows();
+}
+
+void GroupsModel::onItemsRemoved(TreeNode *parent, int first, int last)
+{
+ kDebug();
+ QModelIndex parentIndex = index(parent);
+ QList<TreeNode *> removedItems;
+ beginRemoveRows(parentIndex, first, last);
+ for (int i = last; i >= first; i--) {
+ parent->childAt(i)->remove();
+ }
+ endRemoveRows();
+}
+
+
+void GroupsModel::onSourceItemsAdded(TreeNode *parent, const QList<TreeNode *> &nodes)
+{
+ kDebug() << "Adding" << nodes.size() << "nodes...";
+ QModelIndex parentIndex = index(parent);
+ int currentSize = rowCount(parentIndex);
+ foreach (TreeNode *node, nodes) {
+ ContactModelItem *contactItem = qobject_cast<ContactModelItem*>(node);
+ QStringList groups = contactItem->contact()->groups();
+ addContactToGroups(contactItem, groups);
+ }
+}
+
+void GroupsModel::onSourceItemsRemoved(TreeNode* parent, int first, int last)
+{
+
+}
+
+void GroupsModel::loadAccountsModel()
+{
+ for (int x = 0; x < mPriv->mAM->rowCount(); x++) {
+ QModelIndex parent = mPriv->mAM->index(x, 0);
+ for (int i = 0; i < mPriv->mAM->rowCount(parent); i++) {
+ if (mPriv->mAM->data(mPriv->mAM->index(i, 0, parent),
+ AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>()) {
+
+ QStringList groups = mPriv->mAM->data(mPriv->mAM->index(i, 0, parent),
+ AccountsModel::GroupsRole).toStringList();
+
+ ContactModelItem *contactItem = mPriv->mAM->data(mPriv->mAM->index(i, 0, parent),
+ AccountsModel::ItemRole).value<ContactModelItem*>();
+
+ addContactToGroups(contactItem, groups);
+ }
+ }
+
+ //we need to connect accounts onItemsAdded/onItemsRemoved to watch for changes
+ //and process them directly (directly add/remove the nodes)
+ AccountsModelItem *accountItem = mPriv->mAM->data(parent, AccountsModel::ItemRole).value<AccountsModelItem*>();
+ connect(accountItem, SIGNAL(childrenAdded(TreeNode*,QList<TreeNode*>)),
+ this, SLOT(onSourceItemsAdded(TreeNode*,QList<TreeNode*>)));
+
+ connect(accountItem, SIGNAL(childrenRemoved(TreeNode*,int,int)),
+ this, SLOT(onSourceItemsRemoved(TreeNode*,int,int)));
+
+ kDebug() << "Connecting" << accountItem->account()->displayName() << "to groups model";
+
+ }
+}
+
+void GroupsModel::onContactAddedToGroup(const QString& group)
+{
+ addContactToGroups(qobject_cast<ProxyTreeNode*>(sender()), group);
+}
+
+void GroupsModel::onContactRemovedFromGroup(const QString& group)
+{
+ removeContactFromGroup(qobject_cast<ProxyTreeNode*>(sender()), group);
+}
+
+void GroupsModel::removeContactFromGroup(ProxyTreeNode* proxyNode, const QString& group)
+{
+ kDebug() << "Removing contact from" << group;
+
+ QStringList contactGroups = proxyNode->data(AccountsModel::ItemRole).value<ContactModelItem*>()->contact()->groups();
+ kDebug() << "Left groups are:" << contactGroups;
+
+ contactGroups.removeOne(group);
+
+ //if the contact really is in that group, remove it
+ if (qobject_cast<GroupsModelItem*>(proxyNode->parent())->groupName() == group) {
+
+ disconnect(proxyNode, SIGNAL(contactAddedToGroup(QString)), 0, 0);
+ disconnect(proxyNode, SIGNAL(contactRemovedFromGroup(QString)), 0, 0);
+
+ //if the the contact has no groups left, then put it in Ungroupped group
+ if (contactGroups.isEmpty()) {
+ addContactToGroups(proxyNode->data(AccountsModel::ItemRole).value<ContactModelItem*>(), contactGroups);
+ }
+
+// beginRemoveRows(index(proxyNode->parent()), proxyNode->parent()->indexOf(proxyNode), proxyNode->parent()->indexOf(proxyNode));
+ qobject_cast<GroupsModelItem*>(proxyNode->parent())->removeProxyContact(proxyNode);
+// endRemoveRows();
+ }
+}
+
+void GroupsModel::addContactToGroups(ProxyTreeNode* proxyNode, const QString& group)
+{
+ addContactToGroups(proxyNode->data(AccountsModel::ItemRole).value<ContactModelItem*>(), group);
+}
+
+void GroupsModel::addContactToGroups(ContactModelItem* contactItem, const QString& group)
+{
+ addContactToGroups(contactItem, QStringList(group));
+}
+
+void GroupsModel::addContactToGroups(ContactModelItem* contactItem, QStringList groups)
+{
+ kDebug() << "Contact groups:" << groups;
+
+ //check if the contact is in Ungroupped group, if it is, it needs to be removed from there
+ bool checkUngroupped = false;
+ //if the contact has no groups, create an 'Ungroupped' group for it
+ if (groups.isEmpty()) {
+ groups.append("Ungroupped"); //FIXME i18n
+ } else {
+ checkUngroupped = true;
+ }
+
+ groups.removeDuplicates();
+
+ foreach (QString group, groups) {
+ bool groupExists = false;
+ GroupsModelItem *groupItem;
+
+ kDebug() << "Adding" << contactItem->contact()->alias() << "to" << group;
+
+ //check if the group already exists first
+ for (int i = 0; i < mPriv->mTree->children().size(); i++) {
+// foreach (GroupsModelItem *savedGroupItem, mPriv->mTree->children()) {
+ GroupsModelItem *savedGroupItem = qobject_cast<GroupsModelItem*>(mPriv->mTree->childAt(i));
+ if (savedGroupItem->groupName() == group) {
+ groupExists = true;
+ kDebug() << "Existing group found for" << group;
+ groupItem = savedGroupItem;
+
+ if (!checkUngroupped) {
+ break;
+ }
+ }
+ if (checkUngroupped) {
+ if (savedGroupItem->groupName() == "Ungroupped") {
+ for (int i = 0; i < savedGroupItem->size(); i++) {
+ ProxyTreeNode *tmpNode = qobject_cast<ProxyTreeNode*>(savedGroupItem->childAt(i));
+ if (tmpNode->data(AccountsModel::ItemRole).value<ContactModelItem*>()->contact()->id() == contactItem->contact()->id()) {
+ removeContactFromGroup(tmpNode, QString("Ungroupped"));
+ if (groupExists) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!groupExists) {
+ kDebug() << "Creating new group for" << group;
+ groupItem = new GroupsModelItem(group);
+ onItemsAdded(mPriv->mTree, QList<TreeNode *>() << groupItem);
+ }
+
+ ProxyTreeNode *proxyNode = new ProxyTreeNode(contactItem);
+ groupItem->addProxyContact(proxyNode);
+
+ connect(proxyNode, SIGNAL(contactAddedToGroup(QString)),
+ this, SLOT(onContactAddedToGroup(QString)));
+
+ connect(proxyNode, SIGNAL(contactRemovedFromGroup(QString)),
+ this, SLOT(onContactRemovedFromGroup(QString)));
+
+ }
+}
+
diff --git a/groups-model.h b/groups-model.h
new file mode 100644
index 0000000..f838897
--- /dev/null
+++ b/groups-model.h
@@ -0,0 +1,94 @@
+/*
+ * Contact groups model
+ * This file is based on TelepathyQt4Yell Models
+ *
+ * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+ * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TELEPATHY_GROUPS_MODEL_H
+#define TELEPATHY_GROUPS_MODEL_H
+
+#include <QAbstractListModel>
+
+#include <TelepathyQt4/Account>
+#include <TelepathyQt4/AccountManager>
+#include <TelepathyQt4/TextChannel>
+#include <TelepathyQt4/Types>
+
+class ContactModelItem;
+class GroupsModelItem;
+class AccountsModel;
+class ProxyTreeNode;
+class TreeNode;
+
+class GroupsModel : public QAbstractItemModel
+{
+ Q_OBJECT
+// Q_DISABLE_COPY(GroupsModel)const AccountsModel& am, QObject* parentconst AccontsModel& am, QObject* parent
+// Q_PROPERTY(int accountCount READ accountCount NOTIFY accountCountChanged)
+ Q_ENUMS(Role)
+
+public:
+ enum Role {
+ // general roles
+ GroupNameRole = Qt::DisplayRole
+ };
+
+ explicit GroupsModel(AccountsModel* am, QObject* parent = 0);
+ virtual ~GroupsModel();
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+ virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ virtual QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
+ virtual QModelIndex index(TreeNode *node) const;
+ virtual QModelIndex parent(const QModelIndex &index) const;
+
+ void addContactToGroups(ContactModelItem* contactItem, QStringList groups = QStringList());
+ ///Convenience classes for addContactToGroups
+ void addContactToGroups(ProxyTreeNode* proxyNode, const QString& group);
+ void addContactToGroups(ContactModelItem* contactItem, const QString& group);
+
+ void removeContactFromGroup(ProxyTreeNode* proxyNode, const QString& group);
+
+// Q_SIGNALS:
+// void accountCountChanged();
+// void accountConnectionStatusChanged(const QString &accountId, int status);
+
+private Q_SLOTS:
+// void onNewAccount(const Tp::AccountPtr &account);
+ void onItemChanged(TreeNode *node);
+ void loadAccountsModel();
+ void onItemsAdded(TreeNode *parent, const QList<TreeNode *> &nodes);
+ void onItemsRemoved(TreeNode *parent, int first, int last);
+
+ void onSourceItemsAdded(TreeNode *parent, const QList<TreeNode *> &nodes);
+ void onSourceItemsRemoved(TreeNode *parent, int first, int last);
+ void onContactAddedToGroup(const QString &group);
+ void onContactRemovedFromGroup(const QString &group);
+
+private:
+ struct Private;
+ friend struct Private;
+ Private *mPriv;
+};
+
+#endif // TELEPATHY_GROUPS_MODEL_H
diff --git a/main-widget.cpp b/main-widget.cpp
index 41f3be1..98f7fd7 100644
--- a/main-widget.cpp
+++ b/main-widget.cpp
@@ -62,6 +62,7 @@
#include "add-contact-dialog.h"
#include "remove-contact-dialog.h"
#include "fetch-avatar-job.h"
+#include "groups-model.h"
#define PREFERRED_TEXTCHAT_HANDLER "org.freedesktop.Telepathy.Client.KDE.TextUi"
#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"
@@ -252,8 +253,15 @@ void MainWidget::onAccountManagerReady(Tp::PendingOperation* op)
}
m_model = new AccountsModel(m_accountManager, this);
+ m_groupsModel = new GroupsModel(m_model, this);
m_modelFilter = new AccountFilterModel(this);
- m_modelFilter->setSourceModel(m_model);
+ if (m_groupContactsAction->isChecked()) {
+ m_modelFilter->setGroupsActive(true);
+ m_modelFilter->setSourceModel(m_groupsModel);
+ } else {
+ m_modelFilter->setGroupsActive(false);
+ m_modelFilter->setSourceModel(m_model);
+ }
m_modelFilter->setDynamicSortFilter(true);
m_modelFilter->filterOfflineUsers(m_hideOfflineAction->isChecked());
m_modelFilter->clearFilterString();
@@ -306,7 +314,7 @@ void MainWidget::onAccountManagerReady(Tp::PendingOperation* op)
foreach (const Tp::AccountPtr account, accounts) {
onNewAccountAdded(account);
}
- m_contactsListView->expandAll();
+// m_contactsListView->expandAll();
}
void MainWidget::onAccountConnectionStatusChanged(Tp::ConnectionStatus status)
@@ -464,11 +472,22 @@ void MainWidget::startTextChannel(const QModelIndex &index)
}
QModelIndex realIndex = m_modelFilter->mapToSource(index);
- Tp::ContactPtr contact = m_model->data(realIndex, AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
+ Tp::ContactPtr contact;
+
+ if (m_groupContactsAction->isChecked()) {
+ contact = m_groupsModel->data(realIndex, AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
+ } else {
+ contact = m_model->data(realIndex, AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
+ }
kDebug() << "Requesting chat for contact" << contact->alias();
- Tp::AccountPtr account = m_model->accountForContactIndex(realIndex);
+ Tp::AccountPtr account;
+ if (m_groupContactsAction->isChecked()) {
+ account = qobject_cast<AccountsModelItem*>(m_groupsModel->data(realIndex, AccountsModel::ItemRole).value<ContactModelItem*>()->parent())->account();
+ } else {
+ account = m_model->accountForContactIndex(realIndex);
+ }
Tp::PendingChannelRequest* channelRequest = account->ensureTextChat(contact,
QDateTime::currentDateTime(),
@@ -656,13 +675,25 @@ void MainWidget::onCustomContextMenuRequested(const QPoint &)
{
QModelIndex index = m_contactsListView->currentIndex();
- Tp::ContactPtr contact = m_model->contactForIndex(m_modelFilter->mapToSource(index));
+ Tp::ContactPtr contact;
+ if (m_groupContactsAction->isChecked()) {
+ contact = m_groupsModel->data(m_modelFilter->mapToSource(index), AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
+ } else {
+ contact = m_model->contactForIndex(m_modelFilter->mapToSource(index));
+ }
+
if (contact.isNull()) {
kDebug() << "Contact is nulled";
return;
}
- Tp::AccountPtr account = m_model->accountForContactIndex(m_modelFilter->mapToSource(index));
+ Tp::AccountPtr account;
+ if (m_groupContactsAction->isChecked()) {
+ account = qobject_cast<AccountsModelItem*>(m_groupsModel->data(m_modelFilter->mapToSource(index), AccountsModel::ItemRole).value<ContactModelItem*>()->parent())->account();
+ } else {
+ account = m_model->accountForContactIndex(m_modelFilter->mapToSource(index));
+ }
+
if (account.isNull()) {
kDebug() << "Account is nulled";
return;
@@ -772,7 +803,12 @@ void MainWidget::onCustomContextMenuRequested(const QPoint &)
void MainWidget::slotAddContactToGroupTriggered()
{
QModelIndex index = m_contactsListView->currentIndex();
- Tp::ContactPtr contact = m_model->contactForIndex(m_modelFilter->mapToSource(index));
+ Tp::ContactPtr contact;
+ if (m_groupContactsAction->isChecked()) {
+ contact = m_groupsModel->data(m_modelFilter->mapToSource(index), AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
+ } else {
+ contact = m_model->contactForIndex(m_modelFilter->mapToSource(index));
+ }
if (contact.isNull()) {
kDebug() << "Contact is nulled";
return;
@@ -1123,5 +1159,18 @@ void MainWidget::handleConnectionError(const Tp::AccountPtr& account)
}
}
+void MainWidget::onGroupContacts(bool enabled)
+{
+ if (enabled) {
+ m_modelFilter->setSourceModel(0); //this prevents some crashes
+ m_modelFilter->setGroupsActive(true);
+ m_modelFilter->setSourceModel(m_groupsModel);
+ } else {
+ m_modelFilter->setSourceModel(0);
+ m_modelFilter->setGroupsActive(false);
+ m_modelFilter->setSourceModel(m_model);
+ }
+
+}
#include "main-widget.moc"
diff --git a/main-widget.h b/main-widget.h
index 4ec5357..555f1f1 100644
--- a/main-widget.h
+++ b/main-widget.h
@@ -33,6 +33,7 @@
#include <KAction>
#include "ui_main-widget.h"
+class GroupsModel;
class KMenu;
class KSelectAction;
class AccountsModel;
@@ -88,6 +89,7 @@ public Q_SLOTS:
void startAudioChannel(const QModelIndex &index);
void startVideoChannel(const QModelIndex &index);
void onCustomContextMenuRequested(const QPoint &point);
+ void onGroupContacts(bool enabled);
private Q_SLOTS:
void slotAddContactToGroupTriggered();
@@ -112,6 +114,7 @@ private:
void handleConnectionError(const Tp::AccountPtr &account);
AccountsModel *m_model;
+ GroupsModel *m_groupsModel;
AccountFilterModel *m_modelFilter;
Tp::AccountManagerPtr m_accountManager;
KMenu *m_accountMenu;
diff --git a/proxy-tree-node.cpp b/proxy-tree-node.cpp
new file mode 100644
index 0000000..0dfa373
--- /dev/null
+++ b/proxy-tree-node.cpp
@@ -0,0 +1,84 @@
+/*
+ * Proxy tree model node
+ *
+ * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
+ *
+ * This library 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <TelepathyQt4/Contact>
+
+#include "proxy-tree-node.h"
+#include "tree-node.h"
+#include "contact-model-item.h"
+
+struct ProxyTreeNode::Private
+{
+ Private(ContactModelItem *sourceNode) :
+ mSource(sourceNode)
+ {
+ }
+
+ ~Private()
+ {
+ }
+
+ ContactModelItem *mSource;
+};
+
+ProxyTreeNode::ProxyTreeNode(ContactModelItem *sourceNode)
+ : mPriv(new Private(sourceNode))
+{
+ connect(sourceNode->contact().data(),
+ SIGNAL(addedToGroup(QString)),
+ SIGNAL(contactAddedToGroup(QString)));
+
+ connect(sourceNode->contact().data(),
+ SIGNAL(removedFromGroup(QString)),
+ SIGNAL(contactRemovedFromGroup(QString)));
+
+ connect(sourceNode, SIGNAL(destroyed(QObject*)),
+ this, SLOT(onSourceNodeRemoved()));
+
+ connect(sourceNode,
+ SIGNAL(changed(TreeNode*)),
+ SIGNAL(changed(TreeNode*)));
+}
+
+ProxyTreeNode::~ProxyTreeNode()
+{
+ delete mPriv;
+}
+
+QVariant ProxyTreeNode::data(int role) const
+{
+ if (!mPriv->mSource) {
+ return QVariant();
+ }
+ return mPriv->mSource->data(role);
+}
+
+bool ProxyTreeNode::setData(int role, const QVariant &value)
+{
+ return false;
+}
+
+void ProxyTreeNode::onSourceNodeRemoved()
+{
+ int index = parent()->indexOf(this);
+ emit childrenRemoved(parent(), index, index);
+
+ remove();
+}
diff --git a/tree-node.h b/proxy-tree-node.h
similarity index 58%
copy from tree-node.h
copy to proxy-tree-node.h
index adeefa4..347210a 100644
--- a/tree-node.h
+++ b/proxy-tree-node.h
@@ -1,8 +1,6 @@
-/* *
- * Tree model node
- * This file is based on TelepathyQt4Yell Models
+/*
+ * Proxy tree model node
*
- * Copyright (C) 2010 Collabora Ltd. <info at collabora.co.uk>
* Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
*
* This library is free software; you can redistribute it and/or
@@ -20,40 +18,33 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef TELEPATHY_TREE_NODE_H
-#define TELEPATHY_TREE_NODE_H
+#ifndef TELEPATHY_PROXY_TREE_NODE_H
+#define TELEPATHY_PROXY_TREE_NODE_H
#include <QObject>
#include <QVariant>
+#include "tree-node.h"
-class TreeNode : public QObject
+class ContactModelItem;
+class ProxyTreeNode : public TreeNode
{
Q_OBJECT
- Q_DISABLE_COPY(TreeNode)
+ Q_DISABLE_COPY(ProxyTreeNode)
public:
- TreeNode();
+ ProxyTreeNode(ContactModelItem* sourceNode);
- virtual ~TreeNode();
-
- TreeNode *childAt(int index) const;
-
- void addChild(TreeNode *node);
-
- int indexOf(TreeNode *node) const;
-
- int size() const;
-
- TreeNode *parent() const;
+ virtual ~ProxyTreeNode();
virtual QVariant data(int role) const;
virtual bool setData(int role, const QVariant &value);
- virtual void remove();
+
+public Q_SLOTS:
+ void onSourceNodeRemoved();
Q_SIGNALS:
- void changed(TreeNode *);
- void childrenAdded(TreeNode *parent, const QList<TreeNode *> &nodes);
- void childrenRemoved(TreeNode *parent, int first, int last);
+ void contactAddedToGroup(const QString& group);
+ void contactRemovedFromGroup(const QString& group);
private:
struct Private;
@@ -61,4 +52,4 @@ private:
Private *mPriv;
};
-#endif // TELEPATHY_TREE_NODE_H
+#endif // TELEPATHY_PROXY_TREE_NODE_H
diff --git a/tree-node.h b/tree-node.h
index adeefa4..9f675ab 100644
--- a/tree-node.h
+++ b/tree-node.h
@@ -48,6 +48,8 @@ public:
virtual QVariant data(int role) const;
virtual bool setData(int role, const QVariant &value);
+
+public Q_SLOTS:
virtual void remove();
Q_SIGNALS:
--
ktp-contact-list packaging
More information about the pkg-kde-commits
mailing list