summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Capriotti <p.capriotti@gmail.com>2011-07-28 19:46:14 (GMT)
committerPaolo Capriotti <p.capriotti@gmail.com>2011-07-28 19:55:41 (GMT)
commitd6d1154d7a038fadeb1714efa0fd37a81457f55f (patch)
tree6124300b50f5c05c355f61840d3fef1ae703f16a
parent9392c71479630b3f9c6ae5fa7b7497c416cce6fa (diff)
downloadkde-telepathy-contact-list-master.tar.gz
kde-telepathy-contact-list-master.tar.xz
Initial port to QtFolks.HEADmaster
-rw-r--r--CMakeLists.txt63
-rw-r--r--README7
-rw-r--r--abstract-contact-delegate.cpp109
-rw-r--r--abstract-contact-delegate.h23
-rw-r--r--action-invoker.cpp53
-rw-r--r--action-invoker.h41
-rw-r--r--actions/CMakeLists.txt25
-rw-r--r--actions/actions.cpp139
-rw-r--r--actions/actions.h95
-rw-r--r--actions/im-action-factory.cpp100
-rw-r--r--actions/im-action-factory.h58
-rw-r--r--actions/im-actions-plugin.cpp45
-rw-r--r--actions/im-actions-plugin.h40
-rw-r--r--actions/service.xml14
-rw-r--r--cmake/modules/FindQtContacts.cmake26
-rw-r--r--cmake/modules/FindQtMobility.cmake103
-rw-r--r--contact-delegate-compact.cpp44
-rw-r--r--contact-delegate-compact.h1
-rw-r--r--contact-delegate-overlay.cpp18
-rw-r--r--contact-delegate.cpp46
-rw-r--r--contact-list.cpp106
-rw-r--r--contact-list.h67
-rw-r--r--contact-overlays.cpp63
-rw-r--r--contact-overlays.h16
-rw-r--r--dialogs/contact-info.cpp59
-rw-r--r--dialogs/contact-info.h9
-rw-r--r--dialogs/remove-contact-dialog.cpp18
-rw-r--r--dialogs/remove-contact-dialog.h11
-rw-r--r--main-widget.cpp1393
-rw-r--r--main-widget.h153
-rw-r--r--main-widget.ui7
-rw-r--r--main.cpp8
-rw-r--r--models/contact-filter-model.cpp150
-rw-r--r--models/contact-filter-model.h88
-rw-r--r--models/contact-model.cpp164
-rw-r--r--models/contact-model.h87
-rw-r--r--models/grouping-model.cpp282
-rw-r--r--models/grouping-model.h126
-rw-r--r--telepathy-utils.cpp57
-rw-r--r--telepathy-utils.h31
40 files changed, 2402 insertions, 1543 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b01272f..e1ca7f9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,7 @@ set (CMAKE_MODULE_PATH
set(KDE_MIN_VERSION "4.4.75")
find_package (KDE4 4.4.75 REQUIRED)
find_package (TelepathyQt4 0.7.1 REQUIRED)
+find_package (QtMobility COMPONENTS Contacts)
include (KDE4Defaults)
include (MacroLibrary)
@@ -17,45 +18,40 @@ add_definitions (${KDE4_DEFINITIONS}
include_directories (${KDE4_INCLUDES}
${TELEPATHY_QT4_INCLUDE_DIR}
+ ${QTMOBILITY_INCLUDE_DIR}
+ ${QTMOBILITY_CONTACTS_INCLUDE_DIR}
)
-set (contactlist_SRCS
- abstract-contact-delegate.cpp
- contact-list-application.cpp
- contact-view-hover-button.cpp
- contact-overlays.cpp
- contact-delegate-overlay.cpp
- contact-delegate.cpp
- contact-delegate-compact.cpp
- account-button.cpp
- filter-bar.cpp
- main.cpp
- main-widget.cpp
- fetch-avatar-job.cpp
- dialogs/add-contact-dialog.cpp
- dialogs/join-chat-room-dialog.cpp
- dialogs/remove-contact-dialog.cpp
- dialogs/contact-info.cpp
- models/accounts-filter-model.cpp
- models/contact-model-item.cpp
- models/accounts-model-item.cpp
- models/tree-node.cpp
- models/accounts-model.cpp
- models/groups-model-item.cpp
- models/groups-model.cpp
- models/proxy-tree-node.cpp
+set(contactlist_SRCS
+ abstract-contact-delegate.cpp
+ action-invoker.cpp
+ account-button.cpp
+ contact-delegate.cpp
+ contact-delegate-compact.cpp
+ contact-delegate-overlay.cpp
+ contact-list.cpp
+ contact-overlays.cpp
+ contact-view-hover-button.cpp
+ filter-bar.cpp
+ main.cpp
+ main-widget.cpp
+ telepathy-utils.cpp
+
+ dialogs/contact-info.cpp
+ dialogs/remove-contact-dialog.cpp
+
+ models/contact-filter-model.cpp
+ models/contact-model.cpp
+ models/grouping-model.cpp
)
kde4_add_ui_files (contactlist_SRCS
- main-widget.ui
- dialogs/add-contact-dialog.ui
- dialogs/join-chat-room-dialog.ui
- dialogs/remove-contact-dialog.ui
- dialogs/contact-info.ui
-)
+ main-widget.ui
-add_subdirectory (icons)
+ dialogs/contact-info.ui
+ dialogs/remove-contact-dialog.ui
+)
kde4_add_executable (telepathy-kde-contactlist
${contactlist_SRCS}
@@ -66,6 +62,7 @@ target_link_libraries (telepathy-kde-contactlist
${KDE4_KDEUI_LIBS}
${KDE4_KIO_LIBS}
${KDE4_KCMUTILS_LIBS}
+ ${QTMOBILITY_CONTACTS_LIBRARY}
)
# Install:
@@ -77,3 +74,5 @@ install(FILES ktelepathy.notifyrc DESTINATION ${DATA_INSTALL_DIR}/ktelepathy)
install (PROGRAMS telepathy-kde-contactlist.desktop
DESTINATION ${XDG_APPS_INSTALL_DIR}
)
+
+add_subdirectory(actions)
diff --git a/README b/README
new file mode 100644
index 0000000..ca5d810
--- /dev/null
+++ b/README
@@ -0,0 +1,7 @@
+## How to run
+
+- Install libfolks: git://git.gnome.org/folks
+- Install our branch of qt-folks: git://git.collabora.co.uk/git/user/paolo/qt-folks.git
+- Build normally (but don't install)
+- Copy lib/libtelepathy-kde-im-actions.so to one of the paths in your $QT_PLUGIN_PATH, or adjust $QT_PLUGIN_PATH accordingly
+- Run telepathy-kde-contactlist
diff --git a/abstract-contact-delegate.cpp b/abstract-contact-delegate.cpp
index 309910d..1040a3b 100644
--- a/abstract-contact-delegate.cpp
+++ b/abstract-contact-delegate.cpp
@@ -32,15 +32,16 @@
#include <KDE/KIconLoader>
#include <KDE/KIcon>
-#include "models/accounts-model.h"
-#include "models/groups-model.h"
-#include "models/contact-model-item.h"
+#include <QContactAvatar>
-const int SPACING = 2;
-const int ACCOUNT_ICON_SIZE = 13;
+#include "models/contact-model.h"
+
+static const int SPACING = 2;
+static const int ACCOUNT_ICON_SIZE = 13;
AbstractContactDelegate::AbstractContactDelegate(QObject* parent)
: QStyledItemDelegate(parent), m_palette(0)
+ , m_numTotalItems(0)
{
m_palette = new QPalette(QApplication::palette());
}
@@ -78,21 +79,28 @@ void AbstractContactDelegate::paint(QPainter* painter, const QStyleOptionViewIte
QFont groupFont = KGlobalSettings::smallestReadableFont();
- QString counts = QString(" (%1/%2)").arg(index.data(AccountsModel::OnlineUsersCountRole).toString(),
- index.data(AccountsModel::TotalUsersCountRole).toString());
-
- if (index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<AccountsModelItem*>()) {
- painter->drawPixmap(accountGroupRect, KIcon(index.data(AccountsModel::IconRole).toString())
- .pixmap(ACCOUNT_ICON_SIZE, ACCOUNT_ICON_SIZE));
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ const QString counts = QString(" (%1/%2)").
+ arg(index.model()->rowCount(index)).
+ arg(m_numTotalItems);
+
+ if (contact.type() == QContactType::TypeContact) {
+ QPixmap avatarPixmap;
+ QString avatarPath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
+ if (!avatarPath.isEmpty()) {
+ avatarPixmap.load(avatarPath);
+ painter->drawPixmap(accountGroupRect, avatarPixmap);
+ }
} else {
painter->drawPixmap(accountGroupRect, KIconLoader::global()->loadIcon(QString("system-users"),
KIconLoader::Desktop));
}
+ const QString displayLabel = index.data(Qt::DisplayRole).toString() + counts;
+
painter->setPen(m_palette->color(QPalette::WindowText));
painter->setFont(groupFont);
- painter->drawText(groupLabelRect, Qt::AlignVCenter | Qt::AlignRight,
- index.data(GroupsModel::GroupNameRole).toString().append(counts));
+ painter->drawText(groupLabelRect, Qt::AlignVCenter | Qt::AlignRight, displayLabel);
QPen thinLinePen;
thinLinePen.setWidth(0);
@@ -102,7 +110,7 @@ void AbstractContactDelegate::paint(QPainter* painter, const QStyleOptionViewIte
painter->setRenderHint(QPainter::Antialiasing, false);
QFontMetrics fm = painter->fontMetrics();
- int groupNameWidth = fm.width(index.data(GroupsModel::GroupNameRole).toString().append(counts));
+ int groupNameWidth = fm.width(displayLabel);
painter->drawLine(expandSignRect.right() + SPACING * 2,
groupRect.y() + groupRect.height() / 2,
@@ -125,16 +133,22 @@ void AbstractContactDelegate::paint(QPainter* painter, const QStyleOptionViewIte
QSize AbstractContactDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
+ Q_UNUSED(option);
+ Q_UNUSED(index);
return QSize(0, 20);
}
-
-bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index)
+bool AbstractContactDelegate::helpEvent(QHelpEvent *event,
+ QAbstractItemView *view,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index)
{
Q_UNUSED(option);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+
// Check and make sure that we only want it to work on contacts and nothing else.
- if (index.data(AccountsModel::ItemRole).userType() != qMetaTypeId<ContactModelItem*>()) {
+ if (contact.type() != QContactType::TypeContact) {
return false;
}
@@ -142,37 +156,47 @@ bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *vi
return false;
}
- const QString contactAvatar = index.data(AccountsModel::AvatarRole).toString();
- const QString displayName = index.parent().data(AccountsModel::DisplayNameRole).toString();
- const QString cmIconPath = KIconLoader::global()->iconPath(index.parent().data(AccountsModel::IconRole).toString(), 1);
- const QString alias = index.data(AccountsModel::AliasRole).toString();
- const QString id = index.data(AccountsModel::IdRole).toString();
- const QString presenceStatus = index.data(AccountsModel::PresenceMessageRole).toString();
+ const QString avatarPath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
+ QPixmap contactAvatar;
+ if (!avatarPath.isEmpty()) {
+ contactAvatar.load(avatarPath);
+ }
+ const QString displayName = contact.displayLabel();
+
+ // FIXME: display info for all QContactOnlineAccount detail, instead of just the first one
+
+ QContactOnlineAccount account = contact.detail<QContactOnlineAccount>();
+ const QString cmIconPath = account.value("icon");
+ const QString alias = account.value("alias");
+ const QString id = account.accountUri();
+
+ QContactPresence presence = presenceDetail(contact, account);
+ const QString presenceStatus = presence.customMessage();
QString presenceIconPath;
QString presenceText;
- switch (index.data(AccountsModel::PresenceTypeRole).toUInt()) {
- case Tp::ConnectionPresenceTypeAvailable:
+ switch (presence.presenceState()) {
+ case QContactPresence::PresenceAvailable:
presenceIconPath = KIconLoader::global()->iconPath("user-online", 1);
presenceText = i18nc("This is an IM user status", "Online");
break;
- case Tp::ConnectionPresenceTypeAway:
+ case QContactPresence::PresenceAway:
presenceIconPath = KIconLoader::global()->iconPath("user-away", 1);
presenceText = i18nc("This is an IM user status", "Away");
break;
- case Tp::ConnectionPresenceTypeExtendedAway:
+ case QContactPresence::PresenceExtendedAway:
presenceIconPath = KIconLoader::global()->iconPath("user-away-extended", 1);
presenceText = i18nc("This is an IM user status", "Away");
break;
- case Tp::ConnectionPresenceTypeBusy:
+ case QContactPresence::PresenceBusy:
presenceIconPath = KIconLoader::global()->iconPath("user-busy", 1);
presenceText = i18nc("This is an IM user status", "Busy");
break;
- case Tp::ConnectionPresenceTypeHidden:
+ case QContactPresence::PresenceHidden:
presenceIconPath = KIconLoader::global()->iconPath("user-invisible", 1);
presenceText = i18nc("This is an IM user status", "Invisible");
break;
- case Tp::ConnectionPresenceTypeOffline:
+ case QContactPresence::PresenceOffline:
presenceIconPath = KIconLoader::global()->iconPath("user-offline", 1);
presenceText = i18nc("This is an IM user status", "Offline");
break;
@@ -197,10 +221,10 @@ bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *vi
QString table;
table += QString("<table><tr><td rowspan='2' width='96'>");
- if (contactAvatar.isEmpty() || QPixmap(contactAvatar).isNull()) {
+ if (avatarPath.isEmpty() || contactAvatar.isNull()) {
table += QString("<img src='%1' width='96' />").arg(KIconLoader::global()->iconPath("im-user", -1));
} else {
- table += QString("<img src='%1' width='96' />").arg(contactAvatar);
+ table += QString("<img src='%1' width='96' />").arg(avatarPath);
}
table += QString("</td>");
@@ -209,7 +233,8 @@ bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *vi
table += QString("<tr><td>");
table += QString("%2").arg(presenceStatus.isEmpty() ? presenceText : presenceStatus);
table += QString("</td></tr>");
- if (index.data(AccountsModel::BlockedRole).toBool()) {
+ // FIXME: blocked contact
+ if (false) {
table += QString("<tr><td colspan='2'>%1</td></tr>").arg(i18n("User is blocked"));
}
table += QString("</table>");
@@ -217,4 +242,20 @@ bool AbstractContactDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *vi
QToolTip::showText(QCursor::pos(), table, view);
return true;
-} \ No newline at end of file
+}
+
+QContactPresence AbstractContactDelegate::presenceDetail(const QContact &contact,
+ const QContactOnlineAccount &account) const
+{
+ QStringList detailUris = account.linkedDetailUris();
+ QList<QContactPresence> result;
+ foreach (const QString &uri, detailUris) {
+ result << contact.details<QContactPresence>(QContactDetail::FieldDetailUri, uri);
+ }
+
+ if (!result.isEmpty()) {
+ return result.first();
+ } else {
+ return QContactPresence();
+ }
+}
diff --git a/abstract-contact-delegate.h b/abstract-contact-delegate.h
index b6dcfc8..cb4b3f6 100644
--- a/abstract-contact-delegate.h
+++ b/abstract-contact-delegate.h
@@ -24,6 +24,10 @@
#include <QStyledItemDelegate>
+#include <QContactPresence>
+#include <QContactOnlineAccount>
+
+QTM_USE_NAMESPACE
class AbstractContactDelegate : public QStyledItemDelegate
{
@@ -36,20 +40,21 @@ public:
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
-public Q_SLOTS:
- /**
- * Reimplements the help tooltip for the contact delegate.
- *
- * When the user hovers over a contact it will display their information like Alias, which contact belongs to what account,
- * is this contact blocked, their status message if their is one, etc.
- */
- bool helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index);
-
Q_SIGNALS:
void repaintItem(QModelIndex);
protected:
QPalette *m_palette;
+
+ virtual bool helpEvent(QHelpEvent *event,
+ QAbstractItemView *view,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index);
+private:
+ int m_numTotalItems;
+
+ QContactPresence presenceDetail(const QContact &contact,
+ const QContactOnlineAccount &account) const;
};
#endif // ABSTRACT_CONTACT_DELEGATE_H
diff --git a/action-invoker.cpp b/action-invoker.cpp
new file mode 100644
index 0000000..14e1c2c
--- /dev/null
+++ b/action-invoker.cpp
@@ -0,0 +1,53 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "action-invoker.h"
+
+#include <QScopedPointer>
+
+#include <QContactAction>
+#include <QContactActionDescriptor>
+
+#include <KDebug>
+
+ActionInvoker::ActionInvoker(QObject *parent)
+ : QObject(parent)
+{
+}
+
+ActionInvoker::~ActionInvoker()
+{
+}
+
+bool ActionInvoker::invoke(const QString &name, const QContact &target)
+{
+ QList<QContactActionDescriptor> descriptors = QContactAction::actionDescriptors(name);
+ if (descriptors.size() == 1) {
+ QScopedPointer<QContactAction> action(QContactAction::action(descriptors.first()));
+ if (action) {
+ return action->invokeAction(target);
+ }
+ else {
+ kDebug() << "action is null";
+ }
+ }
+
+ return false;
+}
diff --git a/action-invoker.h b/action-invoker.h
new file mode 100644
index 0000000..8b58547
--- /dev/null
+++ b/action-invoker.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 ACTION_INVOKER_H
+#define ACTION_INVOKER_H
+
+#include <QObject>
+#include <QContact>
+
+QTM_USE_NAMESPACE
+
+class ActionInvoker : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ ActionInvoker(QObject *parent = 0);
+ virtual ~ActionInvoker();
+
+ virtual bool invoke(const QString &name, const QContact &target);
+};
+
+#endif // ACTION_INVOKER_H
diff --git a/actions/CMakeLists.txt b/actions/CMakeLists.txt
new file mode 100644
index 0000000..7fde26e
--- /dev/null
+++ b/actions/CMakeLists.txt
@@ -0,0 +1,25 @@
+find_package (QtMobility COMPONENTS Contacts ServiceFramework)
+
+include_directories (${KDE4_INCLUDES}
+ ${TELEPATHY_QT4_INCLUDE_DIR}
+ ${QTMOBILITY_INCLUDE_DIR}
+ ${QTMOBILITY_CONTACTS_INCLUDE_DIR}
+ ${QTMOBILITY_SERVICEFRAMEWORK_INCLUDE_DIR}
+)
+
+set(imactions_SRCS
+ actions.cpp
+ im-action-factory.cpp
+ im-actions-plugin.cpp
+)
+
+kde4_add_library(telepathy-kde-im-actions SHARED
+ ${imactions_SRCS})
+
+target_link_libraries (telepathy-kde-im-actions
+ ${TELEPATHY_QT4_LIBRARIES}
+ ${KDE4_KDEUI_LIBS}
+ ${KDE4_KIO_LIBS}
+ ${QTMOBILITY_CONTACTS_LIBRARY}
+ ${QTMOBILITY_SERVICEFRAMEWORK_LIBRARY}
+)
diff --git a/actions/actions.cpp b/actions/actions.cpp
new file mode 100644
index 0000000..8e8ef4b
--- /dev/null
+++ b/actions/actions.cpp
@@ -0,0 +1,139 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "actions.h"
+
+#include <QMessageBox>
+#include <QTimer>
+
+#include <TelepathyQt4/Account>
+
+#include <QContactOnlineAccount>
+
+#include <KDebug>
+#include <KFileDialog>
+#include <KLocalizedString>
+
+#define PREFERRED_TEXTCHAT_HANDLER "org.freedesktop.Telepathy.Client.KDE.TextUi"
+#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"
+#define PREFERRED_AUDIO_VIDEO_HANDLER "org.freedesktop.Telepathy.Client.KDE.CallUi"
+
+QVariantMap IMAction::results() const
+{
+ return QVariantMap();
+}
+
+QContactAction::State IMAction::state() const
+{
+ return QContactAction::FinishedState;
+}
+
+bool IMAction::invokeAction(const QContactActionTarget &target,
+ const QVariantMap &params)
+{
+ Q_UNUSED(params);
+
+ QContactOnlineAccount detail = target.contact().details<QContactOnlineAccount>().first();
+
+ const QString accountPath = detail.value("TelepathyAccountPath");
+ Tp::AccountPtr account = Tp::Account::create(
+ QLatin1String(TELEPATHY_ACCOUNT_MANAGER_BUS_NAME),
+ accountPath);
+
+ Tp::PendingChannelRequest* channelRequest = createChannel(detail.accountUri(),
+ account);
+
+ if (channelRequest) {
+ connect(channelRequest, SIGNAL(finished(Tp::PendingOperatio n*)),
+ this, SLOT(onRequestFinished(Tp::PendingOperation *)));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool IMAction::invokeAction(const QList<QContactActionTarget>& targets,
+ const QVariantMap& params)
+{
+ if (targets.size() == 1) {
+ return invokeAction(targets.first(), params);
+ }
+
+ return false;
+}
+
+void IMAction::onRequestFinished(Tp::PendingOperation *op)
+{
+ Q_UNUSED(op);
+ emit stateChanged(QContactAction::FinishedState);
+}
+
+Tp::PendingChannelRequest *TextChatAction::createChannel(const QString &contactId,
+ const Tp::AccountPtr &account)
+{
+ return account->ensureTextChat(contactId,
+ QDateTime::currentDateTime(),
+ PREFERRED_TEXTCHAT_HANDLER);
+}
+
+Tp::PendingChannelRequest *CallAction::createChannel(const QString &contactId,
+ const Tp::AccountPtr &account)
+{
+ return account->ensureStreamedMediaAudioCall(contactId,
+ QDateTime::currentDateTime(),
+ PREFERRED_AUDIO_VIDEO_HANDLER);
+}
+
+Tp::PendingChannelRequest *VideoCallAction::createChannel(const QString &contactId,
+ const Tp::AccountPtr &account)
+{
+ return account->ensureStreamedMediaVideoCall(contactId,
+ true,
+ QDateTime::currentDateTime(),
+ PREFERRED_AUDIO_VIDEO_HANDLER);
+}
+
+Tp::PendingChannelRequest *FileTransferAction::createChannel(const QString &contactId,
+ const Tp::AccountPtr &account)
+{
+ QString filename = KFileDialog::getOpenFileName(KUrl("kfiledialog:///FileTransferLastDirectory"),
+ QString(),
+ 0,
+ i18n("Choose a file"));
+
+ if (filename.isEmpty()) { // User hit cancel button
+ return 0;
+ }
+
+ QFileInfo fileinfo(filename);
+
+ kDebug() << "Filename:" << filename;
+ kDebug() << "Content type:" << KMimeType::findByFileContent(filename)->name();
+ // TODO Let the user set a description?
+
+ Tp::FileTransferChannelCreationProperties
+ fileTransferProperties(filename,
+ KMimeType::findByFileContent(filename)->name());
+
+ return account->createFileTransfer(contactId,
+ fileTransferProperties,
+ QDateTime::currentDateTime(),
+ PREFERRED_FILETRANSFER_HANDLER);
+}
diff --git a/actions/actions.h b/actions/actions.h
new file mode 100644
index 0000000..a3bc43b
--- /dev/null
+++ b/actions/actions.h
@@ -0,0 +1,95 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 ACTIONS_H
+#define ACTIONS_H
+
+#include <TelepathyQt4/Types>
+#include <TelepathyQt4/PendingChannelRequest>
+
+#include <QContactAction>
+
+QTM_USE_NAMESPACE
+
+class IMAction : public QContactAction
+{
+ Q_OBJECT
+
+public:
+
+ virtual bool invokeAction(const QContactActionTarget &target,
+ const QVariantMap &params = QVariantMap());
+ virtual bool invokeAction(const QList<QContactActionTarget>& targets,
+ const QVariantMap& params = QVariantMap());
+
+ virtual QVariantMap results() const;
+ virtual State state() const;
+
+protected:
+
+ virtual Tp::PendingChannelRequest *createChannel(
+ const QString &contactId, const Tp::AccountPtr &account) = 0;
+
+private Q_SLOTS:
+
+ void onRequestFinished(Tp::PendingOperation *);
+};
+
+class TextChatAction : public IMAction
+{
+ Q_OBJECT
+
+protected:
+
+ virtual Tp::PendingChannelRequest *createChannel(const QString &contactId, const Tp::AccountPtr &account);
+
+};
+
+class CallAction : public IMAction
+{
+ Q_OBJECT
+
+protected:
+
+ virtual Tp::PendingChannelRequest *createChannel(const QString &contactId, const Tp::AccountPtr &account);
+
+};
+
+class VideoCallAction : public IMAction
+{
+ Q_OBJECT
+
+protected:
+
+ virtual Tp::PendingChannelRequest *createChannel(const QString &contactId, const Tp::AccountPtr &account);
+
+};
+
+class FileTransferAction : public IMAction
+{
+ Q_OBJECT
+
+protected:
+
+ virtual Tp::PendingChannelRequest *createChannel(const QString &contactId, const Tp::AccountPtr &account);
+
+};
+
+#endif // ACTIONS_H
diff --git a/actions/im-action-factory.cpp b/actions/im-action-factory.cpp
new file mode 100644
index 0000000..f205d0c
--- /dev/null
+++ b/actions/im-action-factory.cpp
@@ -0,0 +1,100 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "im-action-factory.h"
+
+#include <QContactAction>
+#include <QContactFilter>
+#include <QContactOnlineAccount>
+
+#include "actions.h"
+
+ImActionFactory::ImActionFactory()
+{
+ m_textDescriptor = createDescriptor("chat", "im:actions", "chat", 1);
+ m_callDescriptor = createDescriptor("call", "im:actions", "call", 1);
+ m_videoCallDescriptor = createDescriptor("video-call", "im:actions", "video-call", 1);
+ m_fileTransferDescriptor = createDescriptor("file-transfer", "im:actions", "file-transfer", 1);
+}
+
+ImActionFactory::~ImActionFactory()
+{
+}
+
+
+QContactAction *ImActionFactory::create(const QContactActionDescriptor &which) const
+{
+ if (which == m_textDescriptor) {
+ return new TextChatAction;
+ } else if (which == m_callDescriptor) {
+ return new CallAction;
+ } else if (which == m_videoCallDescriptor) {
+ return new VideoCallAction;
+ } else if (which == m_fileTransferDescriptor) {
+ return new FileTransferAction;
+ } else {
+ return 0;
+ }
+}
+
+QContactFilter ImActionFactory::contactFilter(const QContactActionDescriptor &which) const
+{
+ Q_UNUSED(which);
+ return QContactFilter();
+}
+
+
+QList<QContactActionDescriptor> ImActionFactory::actionDescriptors() const
+{
+ return QList<QContactActionDescriptor>() <<
+ m_textDescriptor <<
+ m_callDescriptor <<
+ m_videoCallDescriptor <<
+ m_fileTransferDescriptor;
+}
+
+QSet<QContactActionTarget> ImActionFactory::supportedTargets(const QContact &contact,
+ const QContactActionDescriptor &which) const
+{
+ QSet<QContactActionTarget> result;
+ if (which == m_textDescriptor) {
+ foreach (const QContactOnlineAccount &account, contact.details<QContactOnlineAccount>()) {
+ QContactActionTarget target;
+ target.setContact(contact);
+ target.setDetails(QList<QContactDetail>() << account);
+ result << target;
+ }
+ }
+
+ return result;
+}
+
+
+QVariant ImActionFactory::metaData(const QString &key,
+ const QList<QContactActionTarget> &target,
+ const QVariantMap &parameters,
+ const QContactActionDescriptor &which) const
+{
+ Q_UNUSED(key);
+ Q_UNUSED(target);
+ Q_UNUSED(parameters);
+ Q_UNUSED(which);
+ return QVariant();
+}
diff --git a/actions/im-action-factory.h b/actions/im-action-factory.h
new file mode 100644
index 0000000..85b70e4
--- /dev/null
+++ b/actions/im-action-factory.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 IM_ACTION_FACTORY_H
+#define IM_ACTION_FACTORY_H
+
+#include <QContactActionFactory>
+#include <QContactActionDescriptor>
+
+QTM_USE_NAMESPACE
+
+class ImActionFactory : public QContactActionFactory
+{
+ Q_OBJECT
+
+public:
+
+ ImActionFactory();
+ ~ImActionFactory();
+
+ QList<QContactActionDescriptor> actionDescriptors() const;
+ QContactAction *create(const QContactActionDescriptor &which) const;
+
+ QSet<QContactActionTarget> supportedTargets(const QContact &contact,
+ const QContactActionDescriptor &which) const;
+ QContactFilter contactFilter(const QContactActionDescriptor &which) const;
+ QVariant metaData(const QString &key,
+ const QList<QContactActionTarget> &target,
+ const QVariantMap &parameters,
+ const QContactActionDescriptor &which) const;
+
+private:
+
+ QContactActionDescriptor m_textDescriptor;
+ QContactActionDescriptor m_callDescriptor;
+ QContactActionDescriptor m_videoCallDescriptor;
+ QContactActionDescriptor m_fileTransferDescriptor;
+};
+
+
+#endif // IM_ACTION_FACTORY_H
diff --git a/actions/im-actions-plugin.cpp b/actions/im-actions-plugin.cpp
new file mode 100644
index 0000000..bea536e
--- /dev/null
+++ b/actions/im-actions-plugin.cpp
@@ -0,0 +1,45 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "im-actions-plugin.h"
+
+#include <QContactAction>
+#include <QServiceInterfaceDescriptor>
+
+#include "im-action-factory.h"
+
+QObject *ImActionsPlugin::createInstance(const QServiceInterfaceDescriptor &descriptor,
+ QServiceContext *context,
+ QAbstractSecuritySession *session)
+{
+ Q_UNUSED(context);
+ Q_UNUSED(session);
+
+ if (descriptor.interfaceName() == QContactActionFactory::InterfaceName &&
+ descriptor.serviceName() == QLatin1String("im:actions") &&
+ descriptor.majorVersion() == 1 &&
+ descriptor.minorVersion() == 0) {
+ return new ImActionFactory;
+ } else {
+ return 0;
+ }
+}
+
+Q_EXPORT_PLUGIN2(imactions, ImActionsPlugin);
diff --git a/actions/im-actions-plugin.h b/actions/im-actions-plugin.h
new file mode 100644
index 0000000..b60b137
--- /dev/null
+++ b/actions/im-actions-plugin.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 IM_ACTIONS_PLUGIN_H
+#define IM_ACTIONS_PLUGIN_H
+
+#include <QObject>
+#include <QServicePluginInterface>
+
+QTM_USE_NAMESPACE
+
+class ImActionsPlugin : public QObject, public QServicePluginInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QtMobility::QServicePluginInterface)
+
+public:
+ QObject *createInstance(const QServiceInterfaceDescriptor &descriptor,
+ QServiceContext *context,
+ QAbstractSecuritySession *session);
+};
+
+#endif // IM_ACTIONS_PLUGIN_H
diff --git a/actions/service.xml b/actions/service.xml
new file mode 100644
index 0000000..981572a
--- /dev/null
+++ b/actions/service.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SFW version="1.1">
+ <service>
+ <name>im:actions</name>
+ <filepath>contacts/libtelepathy-kde-im-actions</filepath>
+ <description>This service provides Telepathy-based IM actions for contacts</description>
+ <interface>
+ <name>com.nokia.qt.mobility.contacts.action</name>
+ <version>1.0</version>
+ <description>Provides IM actions for a contact</description>
+ <capabilities></capabilities>
+ </interface>
+ </service>
+</SFW>
diff --git a/cmake/modules/FindQtContacts.cmake b/cmake/modules/FindQtContacts.cmake
new file mode 100644
index 0000000..1963730
--- /dev/null
+++ b/cmake/modules/FindQtContacts.cmake
@@ -0,0 +1,26 @@
+# Try to find QtContacts
+
+find_package(PkgConfig)
+if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_QTCONTACTS QUIET QtContacts)
+endif(PKG_CONFIG_FOUND)
+
+find_path(QTCONTACTS_INCLUDE_DIR
+ NAMES QtContacts/QContact
+ HINTS
+ ${PC_QTCONTACTS_INCLUDEDIR}
+ ${PC_QTCONTACTS_INCLUDE_DIRS}
+)
+
+find_library(QTCONTACTS_LIBRARIES
+ NAMES QtContacts
+ HINTS
+ ${PC_QTCONTACTS_LIBDIR}
+ ${PC_QTCONTACTS_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(QTCONTACTS DEFAULT_MSG
+ QTCONTACTS_INCLUDE_DIR QTCONTACTS_LIBRARIES)
+
+
diff --git a/cmake/modules/FindQtMobility.cmake b/cmake/modules/FindQtMobility.cmake
new file mode 100644
index 0000000..602a3b8
--- /dev/null
+++ b/cmake/modules/FindQtMobility.cmake
@@ -0,0 +1,103 @@
+# - Try to find the QtMobility libraries
+#
+# This module will search for the QtMobility libraries.
+#
+# It supports both a minimum version and searching for individual
+# components. For the minimum version, use
+# find_package(QtMobility 1.2.0). For specific components, use
+# find_package(QtMobility COMPONENTS ...). See below for a list of known
+# components.
+#
+# Once done this will define
+# QTMOBILITY_FOUND - QtMobility and all specified components were found.
+# QTMOBILITY_INCLUDE_DIR - Include directory for global QtMobility files.
+# QTMOBILITY_INCLUDE_DIRS - All found QtMobility components' include dirs.
+# QTMOBILITY_LIBRARIES - All found QtMobility components' libraries.
+# QTMOBILITY_VERSION - The version of QtMobility that was found.
+#
+# For each found component the following will be defined:
+# QTMOBILITY_{COMPONENT}_INCLUDE_DIR - The include directory for the component.
+# QTMOBILITY_{COMPONENT}_LIBRARY - The location of the library for the component.
+#
+# Note that searching for components will be limited to the specified components
+# if the components option is used.
+#
+# Copyright (c) 2011 Arjen Hiemstra <ahiemstra@heimr.nl>
+# Redistribution and use is allowed according to the terms of the BSD license.
+
+set(QTMOBILITY_COMPONENTS
+ Bearer
+ Connectivity
+ Contacts
+ Feedback
+ Gallery
+ Location
+ Messaging
+ MultimediaKit
+ Organizer
+ PublishSubscribe
+ Sensors
+ ServiceFramework
+ SystemInfo
+ Versit
+)
+
+if (QtMobility_FIND_COMPONENTS)
+ foreach (component ${QtMobility_FIND_COMPONENTS})
+ string(TOUPPER ${component} _COMPONENT)
+ set(QTMOBILITY_USE_${_COMPONENT} 1)
+ endforeach (component)
+endif (QtMobility_FIND_COMPONENTS)
+
+find_path(QTMOBILITY_INCLUDE_DIR qmobilityglobal.h PATH_SUFFIXES QtMobility)
+
+#Find the mobility version
+if(QTMOBILITY_INCLUDE_DIR)
+ file(READ "${QTMOBILITY_INCLUDE_DIR}/qmobilityglobal.h" _qtmobility_global_header LIMIT 2000)
+ string(REGEX MATCH "#define QTM_VERSION_STR \"([0-9.]*)\"" _qtmobility_version_match "${_qtmobility_global_header}")
+ set(QTMOBILITY_VERSION "${CMAKE_MATCH_1}")
+ message(STATUS "QtMobility Version ${QTMOBILITY_VERSION} detected")
+endif(QTMOBILITY_INCLUDE_DIR)
+
+set(QTMOBILITY_VARIABLES "QTMOBILITY_INCLUDE_DIR")
+set(QTMOBILITY_INCLUDE_DIRS ${QTMOBILITY_INCLUDE_DIR})
+
+#A list of files to find for specific components
+set(QTMOBILITY_FIND_FILES
+ QNetworkConfiguration #Bearer
+ QBluetoothSocket #Connectivity
+ QContact #Contacts
+ QFeedbackInterface #Feedback
+ QAbstractGallery #Gallery
+ QLandmark #Location
+ QMessage #Messaging
+ QMediaPlayer #MultimediaKit
+ QOrganizerItem #Organizer
+ QValueSpace #PublishSubscribe
+ QSensor #Sensors
+ QService #ServiceFramework
+ QSystemInfo #SystemInfo
+ QVersitDocument #Versit
+)
+
+list(LENGTH QTMOBILITY_COMPONENTS _component_count)
+math(EXPR _component_count "${_component_count} - 1")
+foreach (index RANGE ${_component_count})
+ list(GET QTMOBILITY_COMPONENTS ${index} component)
+ list(GET QTMOBILITY_FIND_FILES ${index} file)
+ string(TOUPPER ${component} _COMPONENT)
+ if (NOT QtMobility_FIND_COMPONENTS OR QTMOBILITY_USE_${_COMPONENT})
+ message(STATUS "Looking for QtMobility Component \"${component}\"")
+ find_path(QTMOBILITY_${_COMPONENT}_INCLUDE_DIR ${file} PATH_SUFFIXES Qt${component})
+ find_library(QTMOBILITY_${_COMPONENT}_LIBRARY NAMES Qt${component})
+ list(APPEND QTMOBILITY_VARIABLES "QTMOBILITY_${_COMPONENT}_INCLUDE_DIR" "QTMOBILITY_${_COMPONENT}_LIBRARY")
+ list(APPEND QTMOBILITY_INCLUDE_DIRS ${QTMOBILITY_${_COMPONENT}_INCLUDE_DIR})
+ list(APPEND QTMOBILITY_LIBRARIES ${QTMOBILITY_${_COMPONENT}_LIBRARY})
+ endif (NOT QtMobility_FIND_COMPONENTS OR QTMOBILITY_USE_${_COMPONENT})
+endforeach (index)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(QtMobility REQUIRED_VARS ${QTMOBILITY_VARIABLES} VERSION_VAR QTMOBILITY_VERSION)
+
+mark_as_advanced(${QTMOBILITY_VARIABLES})
+
diff --git a/contact-delegate-compact.cpp b/contact-delegate-compact.cpp
index 4415af8..1b00659 100644
--- a/contact-delegate-compact.cpp
+++ b/contact-delegate-compact.cpp
@@ -33,11 +33,12 @@
#include <KGlobalSettings>
#include <KDE/KLocale>
-#include "models/accounts-model.h"
-#include "models/contact-model-item.h"
-#include "models/proxy-tree-node.h"
-#include "models/groups-model-item.h"
-#include "models/groups-model.h"
+#include <QContactAvatar>
+#include <QContactGlobalPresence>
+
+#include "models/contact-model.h"
+
+QTM_USE_NAMESPACE
const int SPACING = 4;
const int AVATAR_SIZE = 22;
@@ -67,15 +68,16 @@ void ContactDelegateCompact::paint(QPainter * painter, const QStyleOptionViewIte
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
- bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
- if (isContact) {
+ if (contact.type() == QContactType::TypeContact) {
QRect iconRect = optV4.rect;
iconRect.setSize(QSize(AVATAR_SIZE, AVATAR_SIZE));
iconRect.moveTo(QPoint(iconRect.x() + SPACING, iconRect.y() + SPACING));
+ QString imagePath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
QPixmap avatar;
- avatar.load(index.data(AccountsModel::AvatarRole).toString());
+ avatar.load(imagePath);
bool noContactAvatar = avatar.isNull();
@@ -85,25 +87,26 @@ void ContactDelegateCompact::paint(QPainter * painter, const QStyleOptionViewIte
painter->drawPixmap(iconRect, avatar);
+ QContactGlobalPresence presence = contact.detail<QContactGlobalPresence>();
QPixmap icon;
- switch (index.data(AccountsModel::PresenceTypeRole).toInt()) {
- case Tp::ConnectionPresenceTypeAvailable:
+ switch (presence.presenceState()) {
+ case QContactPresence::PresenceAvailable:
icon = SmallIcon("user-online", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeAway:
+ case QContactPresence::PresenceAway:
icon = SmallIcon("user-away", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeExtendedAway:
+ case QContactPresence::PresenceExtendedAway:
icon = SmallIcon("user-away-extended", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeBusy:
+ case QContactPresence::PresenceBusy:
icon = SmallIcon("user-busy", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeHidden:
+ case QContactPresence::PresenceHidden:
icon = SmallIcon("user-invisible", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeOffline:
+ case QContactPresence::PresenceOffline:
icon = SmallIcon("user-offline", KIconLoader::SizeSmallMedium);
break;
default:
@@ -143,9 +146,11 @@ void ContactDelegateCompact::paint(QPainter * painter, const QStyleOptionViewIte
painter->setPen(presenceMessagePen);
- painter->drawText(presenceMessageRect,
- nameFontMetrics.elidedText(index.data(AccountsModel::PresenceMessageRole).toString(),
- Qt::ElideRight, presenceMessageRect.width()));
+ QString msg = presence.customMessage();
+ if (!msg.isEmpty()) {
+ painter->drawText(presenceMessageRect,
+ nameFontMetrics.elidedText(msg, Qt::ElideRight, presenceMessageRect.width()));
+ }
} else {
AbstractContactDelegate::paint(painter, option, index);
}
@@ -156,7 +161,8 @@ void ContactDelegateCompact::paint(QPainter * painter, const QStyleOptionViewIte
QSize ContactDelegateCompact::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
- bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ bool isContact = contact.type() == QContactType::TypeContact;
if (isContact) {
return QSize(0, 28);
diff --git a/contact-delegate-compact.h b/contact-delegate-compact.h
index 4387e0c..0d05d17 100644
--- a/contact-delegate-compact.h
+++ b/contact-delegate-compact.h
@@ -26,7 +26,6 @@
class ContactDelegateCompact : public AbstractContactDelegate
{
Q_OBJECT
-// Q_PROPERTY(int m_fadingValue READ fadingValue WRITE setFadingValue);
public:
ContactDelegateCompact(QObject *parent = 0);
diff --git a/contact-delegate-overlay.cpp b/contact-delegate-overlay.cpp
index 5fe83ab..b9cd9f9 100644
--- a/contact-delegate-overlay.cpp
+++ b/contact-delegate-overlay.cpp
@@ -27,6 +27,7 @@
#include <KDebug>
+#include "models/contact-model.h"
#include "contact-view-hover-button.h"
ContactDelegateOverlay::ContactDelegateOverlay(QObject* parent)
@@ -77,17 +78,7 @@ QAbstractItemView* ContactDelegateOverlay::view() const
void ContactDelegateOverlay::setDelegate(QAbstractItemDelegate* delegate)
{
- if (m_delegate) {
- disconnect(m_delegate, SIGNAL(visualChange()),
- this, SLOT(visualChange()));
- }
-
m_delegate = delegate;
-
- if (m_delegate) {
- connect(m_delegate, SIGNAL(visualChange()),
- this, SLOT(visualChange()));
- }
}
QAbstractItemDelegate* ContactDelegateOverlay::delegate() const
@@ -194,8 +185,8 @@ void AbstractWidgetDelegateOverlay::slotWidgetAboutToShow(const QModelIndex& ind
bool AbstractWidgetDelegateOverlay::checkIndex(const QModelIndex& index) const
{
- Q_UNUSED(index);
- return true;
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ return contact.type() == QContactType::TypeContact;
}
void AbstractWidgetDelegateOverlay::slotViewportEntered()
@@ -327,9 +318,6 @@ void ContactDelegateOverlayContainer::installOverlay(ContactDelegateOverlay* ove
overlay->setDelegate(asDelegate());
m_overlays << overlay;
// let the view call setActive
-
- QObject::connect(overlay, SIGNAL(destroyed(QObject*)),
- asDelegate(), SLOT(overlayDestroyed(QObject*)));
}
void ContactDelegateOverlayContainer::removeOverlay(ContactDelegateOverlay* overlay)
diff --git a/contact-delegate.cpp b/contact-delegate.cpp
index e75d094..8190ab0 100644
--- a/contact-delegate.cpp
+++ b/contact-delegate.cpp
@@ -22,9 +22,10 @@
#include "contact-delegate.h"
-#include <QtGui/QPainter>
-#include <QtGui/QPainterPath>
#include <QApplication>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPropertyAnimation>
#include <QStyle>
#include <KIconLoader>
@@ -33,11 +34,12 @@
#include <KGlobalSettings>
#include <KDE/KLocale>
-#include "models/accounts-model.h"
-#include "models/contact-model-item.h"
-#include "models/proxy-tree-node.h"
-#include "models/groups-model-item.h"
-#include "models/groups-model.h"
+#include <QContactAvatar>
+#include <QContactPresence>
+
+#include "models/contact-model.h"
+
+QTM_USE_NAMESPACE
const int SPACING = 4;
const int AVATAR_SIZE = 32;
@@ -68,15 +70,16 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
QStyle *style = QApplication::style();
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter);
- bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
- if (isContact) {
+ if (contact.type() == QContactType::TypeContact) {
QRect iconRect = optV4.rect;
iconRect.setSize(QSize(AVATAR_SIZE, AVATAR_SIZE));
iconRect.moveTo(QPoint(iconRect.x() + SPACING, iconRect.y() + SPACING));
QPixmap avatar;
- avatar.load(index.data(AccountsModel::AvatarRole).toString());
+ QString avatarPath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
+ avatar.load(avatarPath);
bool noContactAvatar = avatar.isNull();
@@ -100,24 +103,25 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
}
QPixmap icon;
+ QContactPresence presence = contact.detail<QContactPresence>();
- switch (index.data(AccountsModel::PresenceTypeRole).toInt()) {
- case Tp::ConnectionPresenceTypeAvailable:
+ switch (presence.presenceState()) {
+ case QContactPresence::PresenceAvailable:
icon = SmallIcon("user-online", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeAway:
+ case QContactPresence::PresenceAway:
icon = SmallIcon("user-away", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeExtendedAway:
+ case QContactPresence::PresenceExtendedAway:
icon = SmallIcon("user-away-extended", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeBusy:
+ case QContactPresence::PresenceBusy:
icon = SmallIcon("user-busy", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeHidden:
+ case QContactPresence::PresenceHidden:
icon = SmallIcon("user-invisible", KIconLoader::SizeSmallMedium);
break;
- case Tp::ConnectionPresenceTypeOffline:
+ case QContactPresence::PresenceOffline:
icon = SmallIcon("user-offline", KIconLoader::SizeSmallMedium);
break;
default:
@@ -165,7 +169,7 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
painter->setFont(statusFont);
painter->drawText(statusMsgRect,
- statusFontMetrics.elidedText(index.data(AccountsModel::PresenceMessageRole).toString(),
+ statusFontMetrics.elidedText(presence.customMessage(),
Qt::ElideRight, statusMsgRect.width()));
} else {
@@ -178,9 +182,9 @@ void ContactDelegate::paint(QPainter * painter, const QStyleOptionViewItem & opt
QSize ContactDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option);
- bool isContact = index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>();
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
- if (isContact) {
+ if (contact.type() == QContactType::TypeContact) {
return QSize(0, 32 + 4 * SPACING);
} else {
return AbstractContactDelegate::sizeHint(option, index);
@@ -197,7 +201,7 @@ void ContactDelegate::reshowStatusMessageSlot()
{
m_fadingValue = 255;
m_indexForHiding = QModelIndex();
- emit repaintItem(m_indexForHiding);
+ triggerRepaint();
}
void ContactDelegate::fadeOutStatusMessageSlot()
diff --git a/contact-list.cpp b/contact-list.cpp
new file mode 100644
index 0000000..f04f85a
--- /dev/null
+++ b/contact-list.cpp
@@ -0,0 +1,106 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info@collabora.co.uk>
+ * @Author George Goldberg <george.goldberg@collabora.co.uk>
+ * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
+ * Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "contact-list.h"
+
+#include <QHeaderView>
+
+#include "contact-delegate.h"
+#include "contact-overlays.h"
+
+ContactList::ContactList(QWidget *parent)
+ : QTreeView(parent)
+{
+ m_delegate = new ContactDelegate(this);
+
+ header()->hide();
+ setItemDelegate(m_delegate);
+ setRootIsDecorated(false);
+ setSortingEnabled(true);
+ sortByColumn(0, Qt::AscendingOrder);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ setItemDelegate(m_delegate);
+ setIndentation(0);
+ setMouseTracking(true);
+ setExpandsOnDoubleClick(false); //the expanding/collapsing is handled manually
+ expandAll();
+
+
+ addOverlayButtons();
+
+ connect(m_delegate, SIGNAL(repaintItem(QModelIndex)),
+ viewport(), SLOT(repaint()));
+}
+
+void ContactList::addOverlayButtons()
+{
+ TextChannelContactOverlay *m_textOverlay = new TextChannelContactOverlay(this);
+ AudioChannelContactOverlay *m_audioOverlay = new AudioChannelContactOverlay(this);
+ VideoChannelContactOverlay *m_videoOverlay = new VideoChannelContactOverlay(this);
+ FileTransferContactOverlay *m_fileOverlay = new FileTransferContactOverlay(this);
+
+ m_delegate->installOverlay(m_textOverlay);
+ m_delegate->installOverlay(m_audioOverlay);
+ m_delegate->installOverlay(m_videoOverlay);
+ m_delegate->installOverlay(m_fileOverlay);
+
+ m_textOverlay->setView(this);
+ m_textOverlay->setActive(true);
+
+ m_audioOverlay->setView(this);
+ m_audioOverlay->setActive(true);
+
+ m_videoOverlay->setView(this);
+ m_videoOverlay->setActive(true);
+
+ m_fileOverlay->setView(this);
+ m_fileOverlay->setActive(true);
+
+ connect(m_textOverlay, SIGNAL(overlayActivated(QModelIndex)),
+ m_delegate, SLOT(hideStatusMessageSlot(QModelIndex)));
+
+ connect(m_textOverlay, SIGNAL(overlayHidden()),
+ m_delegate, SLOT(reshowStatusMessageSlot()));
+
+ connect(m_textOverlay, SIGNAL(activated(QContact)),
+ this, SIGNAL(startTextChannel(QContact)));
+
+ connect(m_fileOverlay, SIGNAL(activated(QContact)),
+ this, SIGNAL(startFileTransferChannel(QContact)));
+
+ connect(m_audioOverlay, SIGNAL(activated(QContact)),
+ this, SIGNAL(startAudioChannel(QContact)));
+
+ connect(m_videoOverlay, SIGNAL(activated(QContact)),
+ this, SIGNAL(startVideoChannel(QContact)));
+}
+
+void ContactList::enableOverlays(bool value)
+{
+ m_textOverlay->setActive(value);
+ m_audioOverlay->setActive(value);
+ m_videoOverlay->setActive(value);
+ m_fileOverlay->setActive(value);
+}
+
diff --git a/contact-list.h b/contact-list.h
new file mode 100644
index 0000000..d699867
--- /dev/null
+++ b/contact-list.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info@collabora.co.uk>
+ * @Author George Goldberg <george.goldberg@collabora.co.uk>
+ * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
+ * Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 CONTACT_LIST_H
+#define CONTACT_LIST_H
+
+#include <QTreeView>
+
+#include <QContact>
+
+QTM_USE_NAMESPACE
+
+class HoverButtonDelegateOverlay;
+class ContactDelegate;
+
+class ContactList : public QTreeView
+{
+ Q_OBJECT
+
+public:
+
+ ContactList(QWidget *parent = 0);
+
+Q_SIGNALS:
+
+ void startTextChannel(const QContact &contact);
+ void startAudioChannel(const QContact &contact);
+ void startVideoChannel(const QContact &contact);
+ void startFileTransferChannel(const QContact &contact);
+
+private:
+
+ void addOverlayButtons();
+ void enableOverlays(bool);
+
+ ContactDelegate *m_delegate;
+ HoverButtonDelegateOverlay *m_textOverlay;
+ HoverButtonDelegateOverlay *m_audioOverlay;
+ HoverButtonDelegateOverlay *m_videoOverlay;
+ HoverButtonDelegateOverlay *m_fileOverlay;
+
+};
+
+
+#endif // CONTACT_LIST_H
+
diff --git a/contact-overlays.cpp b/contact-overlays.cpp
index 9e4eb01..0a9fec6 100644
--- a/contact-overlays.cpp
+++ b/contact-overlays.cpp
@@ -25,8 +25,7 @@
#include <KIconLoader>
#include <KDebug>
-#include "models/accounts-model.h"
-#include "models/contact-model-item.h"
+#include "models/contact-model.h"
class TextChannelContactOverlay::Button : public ContactViewHoverButton
{
@@ -114,22 +113,13 @@ void TextChannelContactOverlay::slotClicked(bool checked)
QModelIndex index = button()->index();
if (index.isValid()) {
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (contactItem) {
- emit activated(contactItem);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ if (contact.type() == QContactType::TypeContact) {
+ emit activated(contact);
}
}
}
-bool TextChannelContactOverlay::checkIndex(const QModelIndex& index) const
-{
- if (index.data(AccountsModel::TextChatCapabilityRole).toBool()) {
- return true;
- }
-
- return false;
-}
-
// ------------------------------------------------------------------------
class AudioChannelContactOverlay::Button : public ContactViewHoverButton
@@ -218,22 +208,13 @@ void AudioChannelContactOverlay::slotClicked(bool checked)
QModelIndex index = button()->index();
if (index.isValid()) {
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (contactItem) {
- emit activated(contactItem);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ if (contact.type() == QContactType::TypeContact) {
+ emit activated(contact);
}
}
}
-bool AudioChannelContactOverlay::checkIndex(const QModelIndex& index) const
-{
- if (index.data(AccountsModel::AudioCallCapabilityRole).toBool()) {
- return true;
- }
-
- return false;
-}
-
// ----------------------------------------------------------
class VideoChannelContactOverlay::Button : public ContactViewHoverButton
@@ -322,22 +303,13 @@ void VideoChannelContactOverlay::slotClicked(bool checked)
QModelIndex index = button()->index();
if (index.isValid()) {
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (contactItem) {
- emit activated(contactItem);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ if (contact.type() == QContactType::TypeContact) {
+ emit activated(contact);
}
}
}
-bool VideoChannelContactOverlay::checkIndex(const QModelIndex& index) const
-{
- if (index.data(AccountsModel::VideoCallCapabilityRole).toBool()) {
- return true;
- }
-
- return false;
-}
-
// ----------------------------------------------------------
class FileTransferContactOverlay::Button : public ContactViewHoverButton
@@ -426,20 +398,11 @@ void FileTransferContactOverlay::slotClicked(bool checked)
QModelIndex index = button()->index();
if (index.isValid()) {
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (contactItem) {
- emit activated(contactItem);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ if (contact.type() == QContactType::TypeContact) {
+ emit activated(contact);
}
}
}
-bool FileTransferContactOverlay::checkIndex(const QModelIndex& index) const
-{
- if (index.data(AccountsModel::FileTransferCapabilityRole).toBool()) {
- return true;
- }
-
- return false;
-}
-
#include "contact-overlays.moc"
diff --git a/contact-overlays.h b/contact-overlays.h
index cad1b03..145a6be 100644
--- a/contact-overlays.h
+++ b/contact-overlays.h
@@ -27,7 +27,9 @@
#include "contact-delegate-overlay.h"
#include "contact-view-hover-button.h"
-class ContactModelItem;
+#include <QContact>
+
+QTM_USE_NAMESPACE
class TextChannelContactOverlay : public HoverButtonDelegateOverlay
{
@@ -41,13 +43,12 @@ public Q_SLOTS:
virtual void setActive(bool active);
Q_SIGNALS:
- void activated(ContactModelItem *contactItem);
+ void activated(const QContact &contact);
protected:
virtual ContactViewHoverButton* createButton();
virtual void updateButton(const QModelIndex& index);
- virtual bool checkIndex(const QModelIndex& index) const;
protected Q_SLOTS:
@@ -74,13 +75,12 @@ public Q_SLOTS:
virtual void setActive(bool active);
Q_SIGNALS:
- void activated(ContactModelItem *contactItem);
+ void activated(const QContact &contact);
protected:
virtual ContactViewHoverButton* createButton();
virtual void updateButton(const QModelIndex& index);
- virtual bool checkIndex(const QModelIndex& index) const;
protected Q_SLOTS:
@@ -108,13 +108,12 @@ public Q_SLOTS:
virtual void setActive(bool active);
Q_SIGNALS:
- void activated(ContactModelItem *contactItem);
+ void activated(const QContact &contact);
protected:
virtual ContactViewHoverButton* createButton();
virtual void updateButton(const QModelIndex& index);
- virtual bool checkIndex(const QModelIndex& index) const;
protected Q_SLOTS:
@@ -142,13 +141,12 @@ public Q_SLOTS:
virtual void setActive(bool active);
Q_SIGNALS:
- void activated(ContactModelItem *contactItem);
+ void activated(const QContact &contact);
protected:
virtual ContactViewHoverButton* createButton();
virtual void updateButton(const QModelIndex& index);
- virtual bool checkIndex(const QModelIndex& index) const;
protected Q_SLOTS:
diff --git a/dialogs/contact-info.cpp b/dialogs/contact-info.cpp
index b3efa99..9615633 100644
--- a/dialogs/contact-info.cpp
+++ b/dialogs/contact-info.cpp
@@ -2,6 +2,7 @@
* Dialog for showing contact info
*
* Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,14 +22,16 @@
#include "contact-info.h"
#include "ui_contact-info.h"
-#include <TelepathyQt4/AvatarData>
-#include <TelepathyQt4/Presence>
+#include <QPixmap>
+#include <QTextDocument>
-#include <QtGui/QPixmap>
+#include <QContactAvatar>
+#include <QContactNickname>
+#include <QContactOnlineAccount>
#include <KProtocolInfo>
-ContactInfo::ContactInfo(const Tp::ContactPtr &contact, QWidget *parent) :
+ContactInfo::ContactInfo(const QContact &contact, QWidget *parent) :
KDialog(parent),
ui(new Ui::ContactInfo)
{
@@ -36,18 +39,28 @@ ContactInfo::ContactInfo(const Tp::ContactPtr &contact, QWidget *parent) :
setMainWidget(widget);
ui->setupUi(widget);
- setWindowTitle(contact->alias());
+ setWindowTitle(contact.displayLabel());
setButtons(KDialog::Close);
- QPixmap avatar(contact->avatarData().fileName);
+ QPixmap avatar;
+ QString avatarPath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
+ if (!avatarPath.isEmpty()) {
+ avatar.load(avatarPath);
+ }
ui->avatarLabel->setPixmap(avatar.scaled(ui->avatarLabel->maximumSize(), Qt::KeepAspectRatio));
- ui->idLabel->setText(contact->id());
- ui->nameLabel->setText(contact->alias());
+ QStringList ids;
+ foreach (QContactOnlineAccount account, contact.details<QContactOnlineAccount>()) {
+ ids << account.accountUri();
+ }
+ ui->idLabel->setText(ids.join("\n"));
+
+ ui->nameLabel->setText(contact.displayLabel());
- QString presenceMessage = contact->presence().statusMessage();
+ QContactPresence presence = contact.detail<QContactPresence>();
+ QString presenceMessage = Qt::escape(presence.customMessage());
//find links in presence message
QRegExp linkRegExp("\\b(\\w+)://[^ \t\n\r\f\v]+");
@@ -67,33 +80,13 @@ ContactInfo::ContactInfo(const Tp::ContactPtr &contact, QWidget *parent) :
ui->presenceLabel->setTextFormat(Qt::RichText);
ui->presenceLabel->setText(presenceMessage);
- KIcon blockedIcon;
- if (contact->isBlocked()) {
- blockedIcon = KIcon("task-complete");
- } else {
- blockedIcon = KIcon("task-reject");
- }
- ui->blockedLabel->setPixmap(blockedIcon.pixmap(16));
-
- ui->subscriptionStateLabel->setPixmap(iconForPresenceState(contact->subscriptionState()).pixmap(16));
- ui->publishStateLabel->setPixmap(iconForPresenceState(contact->publishState()).pixmap(16));
+ // TODO: get presence state info from telepathy
+ ui->blockedLabel->setPixmap(KIcon("task-complete").pixmap(16));
+ ui->subscriptionStateLabel->setPixmap(KIcon("task-complete").pixmap(16));
+ ui->publishStateLabel->setPixmap(KIcon("task-complete").pixmap(16));
}
ContactInfo::~ContactInfo()
{
delete ui;
}
-
-KIcon ContactInfo::iconForPresenceState(Tp::Contact::PresenceState state) const
-{
- switch (state) {
- case Tp::Contact::PresenceStateYes:
- return KIcon("task-complete");
- case Tp::Contact::PresenceStateNo:
- return KIcon("task-reject");
- case Tp::Contact::PresenceStateAsk:
- /* Drop Through*/
- default:
- return KIcon("task-attempt");
- }
-}
diff --git a/dialogs/contact-info.h b/dialogs/contact-info.h
index 95add7d..f8367df 100644
--- a/dialogs/contact-info.h
+++ b/dialogs/contact-info.h
@@ -2,6 +2,7 @@
* Dialog for showing contact info
*
* Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,8 +24,11 @@
#define CONTACTINFO_H
#include <KDialog>
-#include <TelepathyQt4/Contact>
+#include <QContact>
+#include <QContactPresence>
+
+QTM_USE_NAMESPACE
namespace Ui {
class ContactInfo;
@@ -35,12 +39,11 @@ class ContactInfo : public KDialog
Q_OBJECT
public:
- explicit ContactInfo(const Tp::ContactPtr &contact, QWidget *parent = 0);
+ explicit ContactInfo(const QContact &contact, QWidget *parent = 0);
~ContactInfo();
private:
Ui::ContactInfo *ui;
- KIcon iconForPresenceState(Tp::Contact::PresenceState state) const;
};
#endif // CONTACTINFO_H
diff --git a/dialogs/remove-contact-dialog.cpp b/dialogs/remove-contact-dialog.cpp
index 2e40ca1..50a7d45 100644
--- a/dialogs/remove-contact-dialog.cpp
+++ b/dialogs/remove-contact-dialog.cpp
@@ -2,6 +2,7 @@
* This file is part of telepathy-contactslist
*
* Copyright (C) 2011 by Francesco Nwokeka <francesco.nwokeka@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,12 +25,12 @@
#include <KIcon>
#include <KLocalizedString>
-#include <QtGui/QCheckBox>
-#include <QtGui/QLabel>
+#include <QCheckBox>
+#include <QLabel>
-#include <TelepathyQt4/AvatarData>
+#include <QContactAvatar>
-RemoveContactDialog::RemoveContactDialog(Tp::ContactPtr contact, QWidget* parent)
+RemoveContactDialog::RemoveContactDialog(const QContact &contact, QWidget* parent)
: KDialog(parent, Qt::Dialog)
, ui(new Ui::RemoveContactDialog)
{
@@ -39,14 +40,15 @@ RemoveContactDialog::RemoveContactDialog(Tp::ContactPtr contact, QWidget* parent
setMainWidget(removeDialog);
ui->textLabel->setText(i18n("Remove the selected contact?"));
- ui->contactAliasLabel->setText(contact->alias());
+ ui->contactAliasLabel->setText(contact.displayLabel());
// load contact avatar
- if (contact->avatarData().fileName.isEmpty()) {
+ QString avatarPath = contact.detail<QContactAvatar>().imageUrl().toLocalFile();
+ if (avatarPath.isEmpty()) {
KIcon defaultIcon("im-user"); // load KIcon with the desired pixmap
ui->contactAvatarLabel->setPixmap(defaultIcon.pixmap(QSize(90, 90)));
} else {
- ui->contactAvatarLabel->setPixmap(contact->avatarData().fileName);
+ ui->contactAvatarLabel->setPixmap(avatarPath);
}
}
@@ -54,5 +56,3 @@ bool RemoveContactDialog::blockContact() const
{
return ui->blockCheckbox->isChecked();
}
-
-#include "remove-contact-dialog.moc"
diff --git a/dialogs/remove-contact-dialog.h b/dialogs/remove-contact-dialog.h
index f225fc9..60d6f6d 100644
--- a/dialogs/remove-contact-dialog.h
+++ b/dialogs/remove-contact-dialog.h
@@ -2,6 +2,7 @@
* This file is part of telepathy-contactslist
*
* Copyright (C) 2011 by Francesco Nwokeka <francesco.nwokeka@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,7 +24,9 @@
#include <KDialog>
-#include <TelepathyQt4/Contact>
+#include <QContact>
+
+QTM_USE_NAMESPACE
namespace Ui {
class RemoveContactDialog;
@@ -38,18 +41,16 @@ class RemoveContactDialog : public KDialog
public:
/**
* constructor
- * @param contact Tp::ContactPtr of the contact to remove
+ * @param contact contact to remove
* @param parent parent widget
*/
- explicit RemoveContactDialog(Tp::ContactPtr contact, QWidget *parent = 0);
+ explicit RemoveContactDialog(const QContact &contact, QWidget *parent = 0);
/** returns value of "block contact" checkbox */
bool blockContact() const;
-
private:
Ui::RemoveContactDialog *ui;
};
-
#endif // REMOVECONTACTDIALOG_H
diff --git a/main-widget.cpp b/main-widget.cpp
index 93f936e..f55580f 100644
--- a/main-widget.cpp
+++ b/main-widget.cpp
@@ -5,6 +5,7 @@
* @Author George Goldberg <george.goldberg@collabora.co.uk>
* Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
* Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -23,82 +24,75 @@
#include "main-widget.h"
-#include <QtGui/QSortFilterProxyModel>
-#include <QtGui/QPainter>
-#include <QtGui/QMenu>
-#include <QtGui/QLabel>
-#include <QtGui/QCheckBox>
-#include <QtGui/QPushButton>
-#include <QtGui/QToolButton>
-#include <QtCore/QWeakPointer>
#include <QWidgetAction>
-#include <QCloseEvent>
-
-#include <TelepathyQt4/PendingReady>
-#include <TelepathyQt4/PendingChannelRequest>
-#include <TelepathyQt4/PendingContacts>
-#include <TelepathyQt4/ClientRegistrar>
-#include <TelepathyQt4/Constants>
-#include <TelepathyQt4/ContactManager>
+#include <KAction>
#include <KDebug>
-#include <KDialog>
-#include <KIO/Job>
-#include <KUser>
-#include <KMenu>
-#include <KMessageBox>
#include <KSettings/Dialog>
-#include <KSharedConfig>
-#include <KFileDialog>
-#include <KInputDialog>
#include <KStandardShortcut>
-#include <KNotification>
+#include <KUser>
+
+#include <TelepathyQt4/PendingReady>
+
+#include <QContactAction>
+#include <QContactActionDescriptor>
+#include <QContactManager>
+#include <QContactOnlineAccount>
+#include <QContactType>
-#include "ui_main-widget.h"
#include "account-button.h"
-#include "contact-overlays.h"
-#include "contact-delegate.h"
+#include "action-invoker.h"
+#include "contact-list.h"
#include "contact-delegate-compact.h"
-#include "fetch-avatar-job.h"
-#include "contact-list-application.h"
-
-#include "dialogs/add-contact-dialog.h"
-#include "dialogs/join-chat-room-dialog.h"
-#include "dialogs/remove-contact-dialog.h"
+#include "contact-delegate.h"
#include "dialogs/contact-info.h"
+#include "dialogs/remove-contact-dialog.h"
+#include "models/contact-filter-model.h"
+#include "models/contact-model.h"
+#include "models/grouping-model.h"
+#include "telepathy-utils.h"
+MainWidget::MainWidget(QWidget *parent)
+ : KMainWindow(parent)
+{
+ m_accountManager = TelepathyUtils::createAccountManager();
+ connect(m_accountManager->becomeReady(),
+ SIGNAL(finished(Tp::PendingOperation *)),
+ SLOT(onAccountManagerReady(Tp::PendingOperation *)));
-#include "models/groups-model.h"
-#include "models/contact-model-item.h"
-#include "models/groups-model-item.h"
-#include "models/accounts-model.h"
-#include "models/accounts-filter-model.h"
-#include "models/proxy-tree-node.h"
+ m_actionInvoker = new ActionInvoker(this);
-#define PREFERRED_TEXTCHAT_HANDLER "org.freedesktop.Telepathy.Client.KDE.TextUi"
-#define PREFERRED_FILETRANSFER_HANDLER "org.freedesktop.Telepathy.Client.KDE.FileTransfer"
-#define PREFERRED_AUDIO_VIDEO_HANDLER "org.freedesktop.Telepathy.Client.KDE.CallUi"
+ setupUi(this);
+ setupToolBar();
-bool kde_tp_filter_contacts_by_publication_status(const Tp::ContactPtr &contact)
-{
- return contact->publishState() == Tp::Contact::PresenceStateAsk;
-}
+ QMap<QString, QString> params;
+ QString managerUri = QContactManager::buildUri(
+ QLatin1String("folks"), params);
+ QContactManager *manager = QContactManager::fromUri(managerUri);
-MainWidget::MainWidget(QWidget *parent)
- : KMainWindow(parent),
- m_model(0),
- m_modelFilter(0)
-{
- Tp::registerTypes();
- KUser user;
+ m_model = new ContactModel(manager, QContactType::TypeContact, this);
+ ContactModel *groupModel = new ContactModel(manager, QContactType::TypeGroup, this);
+
+ Grouping *grouping = new ContactGrouping(groupModel, this);
+
+ GroupingModel *model = new GroupingModel(m_model, grouping);
+
+ m_filterModel = new ContactFilterModel(this);
+ m_filterModel->setSourceModel(model);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->showOfflineUsers(m_showOfflineAction->isChecked());
+ m_filterModel->clearFilterString();
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSortRole(Qt::DisplayRole);
+ m_filterModel->setSortByPresence(m_sortByPresenceAction->isChecked());
+
+ m_delegate = new ContactDelegate(this);
+ m_contactList->setModel(m_filterModel);
- setupUi(this);
m_filterBar->hide();
setWindowIcon(KIcon("kde-telepathy"));
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup guiConfigGroup(config, "GUI");
-
+ KUser user;
m_userAccountNameLabel->setText(user.property(KUser::FullName).isNull() ?
user.loginName() : user.property(KUser::FullName).toString()
);
@@ -126,6 +120,74 @@ MainWidget::MainWidget(QWidget *parent)
m_userAccountIconButton->setMenu(m_avatarButtonMenu);
+ connect(m_showOfflineAction, SIGNAL(toggled(bool)),
+ m_filterModel, SLOT(showOfflineUsers(bool)));
+
+ connect(m_filterBar, SIGNAL(filterChanged(QString)),
+ m_filterModel, SLOT(setFilterString(QString)));
+
+ connect(m_filterBar, SIGNAL(closeRequest()),
+ m_filterModel, SLOT(clearFilterString()));
+
+ connect(m_filterBar, SIGNAL(closeRequest()),
+ m_filterBar, SLOT(hide()));
+
+ connect(m_filterBar, SIGNAL(closeRequest()),
+ m_searchContactAction, SLOT(toggle()));
+
+ connect(m_sortByPresenceAction, SIGNAL(toggled(bool)),
+ m_filterModel, SLOT(setSortByPresence(bool)));
+
+ connect(m_addContactAction, SIGNAL(triggered(bool)),
+ this, SLOT(onAddContactRequest()));
+
+ connect(m_groupContactsAction, SIGNAL(triggered(bool)),
+ this, SLOT(onGroupContacts(bool)));
+
+ connect(m_searchContactAction, SIGNAL(triggered(bool)),
+ this, SLOT(toggleSearchWidget(bool)));
+
+ connect(m_presenceMessageEdit, SIGNAL(returnPressed(QString)),
+ this, SLOT(setCustomPresenceMessage(QString)));
+
+ KConfigGroup guiConfigGroup(KGlobal::config(), "GUI");
+ if (guiConfigGroup.readEntry("pin_filterbar", true)) {
+ toggleSearchWidget(true);
+ m_searchContactAction->setChecked(true);
+ }
+
+ bool useGroups = guiConfigGroup.readEntry("use_groups", true);
+ m_groupContactsAction->setChecked(useGroups);
+
+ bool showOffline = guiConfigGroup.readEntry("show_offline", false);
+ m_filterModel->showOfflineUsers(showOffline);
+ m_showOfflineAction->setChecked(showOffline);
+
+ bool sortByPresence = guiConfigGroup.readEntry("sort_by_presence", true);
+ m_filterModel->setSortByPresence(sortByPresence);
+ m_sortByPresenceAction->setChecked(sortByPresence);
+
+ connect(m_contactList, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(onCustomContextMenuRequested(QPoint)));
+
+ connect(m_contactList, SIGNAL(clicked(QModelIndex)),
+ this, SLOT(onContactListClicked(QModelIndex)));
+
+ connect(m_contactList, SIGNAL(doubleClicked(QModelIndex)),
+ this, SLOT(onContactListDoubleClick(QModelIndex)));
+
+ connect(m_contactList, SIGNAL(startTextChannel(QContact)),
+ this, SLOT(startTextChannel(QContact)));
+ connect(m_contactList, SIGNAL(startAudioChannel(QContact)),
+ this, SLOT(startAudioChannel(QContact)));
+ connect(m_contactList, SIGNAL(startVideoChannel(QContact)),
+ this, SLOT(startVideoChannel(QContact)));
+ connect(m_contactList, SIGNAL(startFileTransferChannel(QContact)),
+ this, SLOT(startFileTransferChannel(QContact)));
+}
+
+void MainWidget::setupToolBar()
+{
m_addContactAction = new KAction(KIcon("list-add-user"), QString(), this);
m_addContactAction->setToolTip(i18n("Add new contacts.."));
@@ -182,6 +244,7 @@ MainWidget::MainWidget(QWidget *parent)
this, SLOT(onSwitchToFullView())));
delegateTypeGroup->actions().last()->setCheckable(true);
+ KConfigGroup guiConfigGroup(KGlobal::config(), "GUI");
if (guiConfigGroup.readEntry("selected_delegate", "full") == QLatin1String("full")) {
delegateTypeGroup->actions().last()->setChecked(true);
}
@@ -203,96 +266,12 @@ MainWidget::MainWidget(QWidget *parent)
settingsButton->setMenu(settingsButtonMenu);
m_toolBar->addWidget(settingsButton);
-
- // Start setting up the Telepathy AccountManager.
- Tp::AccountFactoryPtr accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
- Tp::Features() << Tp::Account::FeatureCore
- << Tp::Account::FeatureAvatar
- << Tp::Account::FeatureCapabilities
- << Tp::Account::FeatureProtocolInfo
- << Tp::Account::FeatureProfile);
-
- Tp::ConnectionFactoryPtr connectionFactory = Tp::ConnectionFactory::create(QDBusConnection::sessionBus(),
- Tp::Features() << Tp::Connection::FeatureCore
- << Tp::Connection::FeatureRosterGroups
- << Tp::Connection::FeatureRoster
- << Tp::Connection::FeatureSelfContact);
-
- Tp::ContactFactoryPtr contactFactory = Tp::ContactFactory::create(Tp::Features() << Tp::Contact::FeatureAlias
- << Tp::Contact::FeatureAvatarData
- << Tp::Contact::FeatureSimplePresence
- << Tp::Contact::FeatureCapabilities);
-
- Tp::ChannelFactoryPtr channelFactory = Tp::ChannelFactory::create(QDBusConnection::sessionBus());
-
- m_accountManager = Tp::AccountManager::create(QDBusConnection::sessionBus(),
- accountFactory,
- connectionFactory,
- channelFactory,
- contactFactory);
-
- connect(m_accountManager->becomeReady(),
- SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(onAccountManagerReady(Tp::PendingOperation*)));
-
- connect(m_accountManager.data(), SIGNAL(newAccount(Tp::AccountPtr)),
- this, SLOT(onNewAccountAdded(Tp::AccountPtr)));
-
- m_delegate = new ContactDelegate(this);
- m_compactDelegate = new ContactDelegateCompact(this);
-
- m_contactsListView->header()->hide();
- m_contactsListView->setRootIsDecorated(false);
- m_contactsListView->setSortingEnabled(true);
- m_contactsListView->setContextMenuPolicy(Qt::CustomContextMenu);
- if (guiConfigGroup.readEntry("selected_delegate", "full") == QLatin1String("compact")) {
- m_contactsListView->setItemDelegate(m_compactDelegate);
- } else {
- m_contactsListView->setItemDelegate(m_delegate);
- }
- m_contactsListView->setIndentation(0);
- m_contactsListView->setMouseTracking(true);
- m_contactsListView->setExpandsOnDoubleClick(false); //the expanding/collapsing is handled manually
-
- addOverlayButtons();
-
- emit enableOverlays(guiConfigGroup.readEntry("selected_delegate", "full") == QLatin1String("full"));
-
- connect(m_contactsListView, SIGNAL(customContextMenuRequested(QPoint)),
- this, SLOT(onCustomContextMenuRequested(QPoint)));
-
- connect(m_contactsListView, SIGNAL(clicked(QModelIndex)),
- this, SLOT(onContactListClicked(QModelIndex)));
-
- connect(m_contactsListView, SIGNAL(doubleClicked(QModelIndex)),
- this, SLOT(onContactListDoubleClick(QModelIndex)));
-
- connect(m_delegate, SIGNAL(repaintItem(QModelIndex)),
- m_contactsListView->viewport(), SLOT(repaint())); //update(QModelIndex)
-
- connect(m_addContactAction, SIGNAL(triggered(bool)),
- this, SLOT(onAddContactRequest()));
-
- connect(m_groupContactsAction, SIGNAL(triggered(bool)),
- this, SLOT(onGroupContacts(bool)));
-
- connect(m_searchContactAction, SIGNAL(triggered(bool)),
- this, SLOT(toggleSearchWidget(bool)));
-
- connect(m_presenceMessageEdit, SIGNAL(returnPressed(QString)),
- this, SLOT(setCustomPresenceMessage(QString)));
-
- if (guiConfigGroup.readEntry("pin_filterbar", true)) {
- toggleSearchWidget(true);
- m_searchContactAction->setChecked(true);
- }
}
MainWidget::~MainWidget()
{
//save the state of the filter bar, pinned or not
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup configGroup(config, "GUI");
+ KConfigGroup configGroup(KGlobal::config(), "GUI");
configGroup.writeEntry("pin_filterbar", m_searchContactAction->isChecked());
configGroup.writeEntry("use_groups", m_groupContactsAction->isChecked());
configGroup.writeEntry("show_offline", m_showOfflineAction->isChecked());
@@ -300,57 +279,17 @@ MainWidget::~MainWidget()
configGroup.config()->sync();
}
-void MainWidget::onAccountManagerReady(Tp::PendingOperation* op)
+void MainWidget::onAccountManagerReady(Tp::PendingOperation *op)
{
if (op->isError()) {
kDebug() << op->errorName();
kDebug() << op->errorMessage();
}
- m_model = new AccountsModel(m_accountManager, this);
- m_groupsModel = new GroupsModel(m_model, this);
- m_modelFilter = new AccountsFilterModel(this);
- if (m_groupContactsAction->isChecked()) {
- m_modelFilter->setSourceModel(m_groupsModel);
- } else {
- m_modelFilter->setSourceModel(m_model);
- }
- m_modelFilter->setDynamicSortFilter(true);
- m_modelFilter->showOfflineUsers(m_showOfflineAction->isChecked());
- m_modelFilter->clearFilterString();
- m_modelFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_modelFilter->setSortRole(Qt::DisplayRole);
- m_modelFilter->setSortByPresence(m_sortByPresenceAction->isChecked());
- m_contactsListView->setModel(m_modelFilter);
- m_contactsListView->setSortingEnabled(true);
- m_contactsListView->sortByColumn(0, Qt::AscendingOrder);
-
- connect(m_showOfflineAction, SIGNAL(toggled(bool)),
- m_modelFilter, SLOT(showOfflineUsers(bool)));
-
- connect(m_filterBar, SIGNAL(filterChanged(QString)),
- m_modelFilter, SLOT(setFilterString(QString)));
-
- connect(m_filterBar, SIGNAL(closeRequest()),
- m_modelFilter, SLOT(clearFilterString()));
-
- connect(m_filterBar, SIGNAL(closeRequest()),
- m_filterBar, SLOT(hide()));
-
- connect(m_filterBar, SIGNAL(closeRequest()),
- m_searchContactAction, SLOT(toggle()));
-
- connect(m_sortByPresenceAction, SIGNAL(toggled(bool)),
- m_modelFilter, SLOT(setSortByPresence(bool)));
-
- connect(m_modelFilter, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)),
- m_delegate, SLOT(contactRemoved(QModelIndex,int,int)));
-
m_accountButtonsLayout->insertStretch(-1);
- QList<Tp::AccountPtr> accounts = m_accountManager->allAccounts();
-
- if(accounts.count() == 0) {
+ m_accounts = m_accountManager->enabledAccounts();
+ if (m_accounts->accounts().count() == 0) {
KDialog *dialog = new KDialog(this);
dialog->setCaption(i18n("No Accounts Found"));
dialog->setButtons(KDialog::Ok | KDialog::Cancel);
@@ -362,1164 +301,228 @@ void MainWidget::onAccountManagerReady(Tp::PendingOperation* op)
connect(dialog, SIGNAL(okClicked()), dialog, SLOT(close()));
connect(dialog, SIGNAL(cancelClicked()), dialog, SLOT(close()));
dialog->show();
+ } else {
+ foreach (Tp::AccountPtr account, m_accounts->accounts()) {
+ onAccountAdded(account);
+ }
}
- foreach (const Tp::AccountPtr &account, accounts) {
- onNewAccountAdded(account);
- }
-
- m_contactsListView->expandAll();
-
KSharedConfigPtr config = KGlobal::config();
KConfigGroup guiConfigGroup(config, "GUI");
- bool useGroups = guiConfigGroup.readEntry("use_groups", true);
- onGroupContacts(useGroups);
- m_groupContactsAction->setChecked(useGroups);
-
- bool showOffline = guiConfigGroup.readEntry("show_offline", false);
- m_modelFilter->showOfflineUsers(showOffline);
- m_showOfflineAction->setChecked(showOffline);
-
- bool sortByPresence = guiConfigGroup.readEntry("sort_by_presence", true);
- m_modelFilter->setSortByPresence(sortByPresence);
- m_sortByPresenceAction->setChecked(sortByPresence);
-}
-
-void MainWidget::onAccountConnectionStatusChanged(Tp::ConnectionStatus status)
-{
- kDebug() << "Connection status is" << status;
-
- Tp::AccountPtr account(qobject_cast< Tp::Account* >(sender()));
- QModelIndex index = m_model->index(qobject_cast<AccountsModelItem*>(m_model->accountItemForId(account->uniqueIdentifier())));
-
- switch (status) {
- case Tp::ConnectionStatusConnected:
- m_contactsListView->setExpanded(index, true);
- break;
- case Tp::ConnectionStatusDisconnected:
- handleConnectionError(account);
- break;
- case Tp::ConnectionStatusConnecting:
- m_contactsListView->setExpanded(index, false);
- default:
- break;
- }
+ connect(m_presenceMessageEdit, SIGNAL(returnPressed(QString)),
+ this, SLOT(setCustomPresenceMessage(QString)));
}
-void MainWidget::onNewAccountAdded(const Tp::AccountPtr& account)
+void MainWidget::onAccountAdded(const Tp::AccountPtr &account)
{
- Q_ASSERT(account->isReady(Tp::Account::FeatureCore));
-
- if (account->connection()) {
- monitorPresence(account->connection());
- }
-
- connect(account.data(),
- SIGNAL(connectionChanged(Tp::ConnectionPtr)),
- this, SLOT(onConnectionChanged(Tp::ConnectionPtr)));
-
- connect(account.data(),
- SIGNAL(connectionStatusChanged(Tp::ConnectionStatus)),
- this, SLOT(onAccountConnectionStatusChanged(Tp::ConnectionStatus)));
-
- connect(account.data(), SIGNAL(stateChanged(bool)),
- this, SLOT(onAccountStateChanged(bool)));
-
- connect(account.data(),
- SIGNAL(removed()),
- this, SLOT(onAccountRemoved()));
-
AccountButton *bt = new AccountButton(account, this);
bt->setObjectName(account->uniqueIdentifier());
- bt->hide();
-
m_accountButtonsLayout->insertWidget(m_accountButtonsLayout->count() - 1, bt);
-
- if(account->isEnabled()) {
- bt->show();
- loadAvatar(account);
- }
-
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup avatarGroup(config, "Avatar");
- if (avatarGroup.readEntry("method", QString()) == QLatin1String("account")) {
- //this also updates the avatar if it was changed somewhere else
- selectAvatarFromAccount(avatarGroup.readEntry("source", QString()));
- }
-}
-
-void MainWidget::monitorPresence(const Tp::ConnectionPtr &connection)
-{
- kDebug();
- connect(connection->contactManager().data(), SIGNAL(presencePublicationRequested(Tp::Contacts)),
- this, SLOT(onPresencePublicationRequested(Tp::Contacts)));
-
- connect(connection->contactManager().data(),
- SIGNAL(stateChanged(Tp::ContactListState)),
- this, SLOT(onContactManagerStateChanged(Tp::ContactListState)));
- onContactManagerStateChanged(connection->contactManager(),
- connection->contactManager()->state());
-}
-
-void MainWidget::onContactManagerStateChanged(Tp::ContactListState state)
-{
- onContactManagerStateChanged(Tp::ContactManagerPtr(qobject_cast< Tp::ContactManager* >(sender())), state);
-}
-
-void MainWidget::onContactManagerStateChanged(const Tp::ContactManagerPtr &contactManager, Tp::ContactListState state)
-{
- if (state == Tp::ContactListStateSuccess) {
- QFutureWatcher< Tp::ContactPtr > *watcher = new QFutureWatcher< Tp::ContactPtr >(this);
- connect(watcher, SIGNAL(finished()), this, SLOT(onAccountsPresenceStatusFiltered()));
- watcher->setFuture(QtConcurrent::filtered(contactManager->allKnownContacts(),
- kde_tp_filter_contacts_by_publication_status));
-
- kDebug() << "Watcher is on";
- }
-}
-
-void MainWidget::onAccountStateChanged(bool enabled)
-{
- Tp::AccountPtr account(qobject_cast<Tp::Account*>(sender()));
-
- if(enabled) {
- findChild<AccountButton *>(account->uniqueIdentifier())->show();
- } else {
- findChild<AccountButton *>(account->uniqueIdentifier())->hide();
- showMessageToUser(i18n("Account %1 was disabled.", account->displayName()),
- MainWidget::SystemMessageError);
- }
+ loadAvatar(account);
}
-void MainWidget::onAccountRemoved()
+void MainWidget::onAccountRemoved(const Tp::AccountPtr &account)
{
- Tp::AccountPtr account(qobject_cast<Tp::Account*>(sender()));
delete findChild<AccountButton *>(account->uniqueIdentifier());
-
- showMessageToUser(i18n("Account %1 was removed.", account->displayName()),
- MainWidget::SystemMessageError);
-}
-
-void MainWidget::onConnectionChanged(const Tp::ConnectionPtr& connection)
-{
- if(! connection.isNull()) {
- monitorPresence(connection);
- }
-}
-
-void MainWidget::onContactListClicked(const QModelIndex& index)
-{
- if (!index.isValid()) {
- return;
- }
-
- if (index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<AccountsModelItem*>()
- || index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<GroupsModelItem*>()) {
-
- if (m_contactsListView->isExpanded(index)) {
- m_contactsListView->collapse(index);
- } else {
- m_contactsListView->expand(index);
- }
- }
}
-void MainWidget::onContactListDoubleClick(const QModelIndex& index)
+void MainWidget::setCustomPresenceMessage(const QString& message)
{
- if (!index.isValid()) {
- return;
- }
+ for (int i = 0; i < m_accountButtonsLayout->count() - 1; i++) {
+ qobject_cast<AccountButton*>(m_accountButtonsLayout->itemAt(i)->widget())->setCustomPresenceMessage(message);
- if (index.data(AccountsModel::ItemRole).userType() == qMetaTypeId<ContactModelItem*>()) {
- kDebug() << "Text chat requested for index" << index;
- startTextChannel(index.data(AccountsModel::ItemRole).value<ContactModelItem*>());
}
-}
-
-void MainWidget::startTextChannel(ContactModelItem *contactItem)
-{
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- kDebug() << "Requesting chat for contact" << contact->alias();
- Tp::AccountPtr account = m_model->accountForContactItem(contactItem);
-
- Tp::PendingChannelRequest* channelRequest = account->ensureTextChat(contact,
- QDateTime::currentDateTime(),
- PREFERRED_TEXTCHAT_HANDLER);
- connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)),
- this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-}
-
-void MainWidget::startAudioChannel(ContactModelItem *contactItem)
-{
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- kDebug() << "Requesting audio for contact" << contact->alias();
-
- Tp::AccountPtr account = m_model->accountForContactItem(contactItem);
-
- Tp::PendingChannelRequest* channelRequest = account->ensureStreamedMediaAudioCall(contact,
- QDateTime::currentDateTime(),
- PREFERRED_AUDIO_VIDEO_HANDLER);
- connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)),
- this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
+ m_presenceMessageEdit->clearFocus();
}
-void MainWidget::startVideoChannel(ContactModelItem *contactItem)
+void MainWidget::showSettingsKCM()
{
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- kDebug() << "Requesting video for contact" << contact->alias();
+ KSettings::Dialog *dialog = new KSettings::Dialog(this);
- Tp::AccountPtr account = m_model->accountForContactItem(contactItem);
+ dialog->addModule("kcm_telepathy_accounts");
- Tp::PendingChannelRequest* channelRequest = account->ensureStreamedMediaVideoCall(contact, true,
- QDateTime::currentDateTime(),
- PREFERRED_AUDIO_VIDEO_HANDLER);
- connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)),
- this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->exec();
}
-
-void MainWidget::startFileTransferChannel(ContactModelItem *contactItem)
+void MainWidget::loadAvatar(const Tp::AccountPtr &account)
{
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- kDebug() << "Requesting file transfer for contact" << contact->alias();
-
- Tp::AccountPtr account = m_model->accountForContactItem(contactItem);
-
- QString filename = KFileDialog::getOpenFileName(KUrl("kfiledialog:///FileTransferLastDirectory"),
- QString(),
- this,
- i18n("Choose a file"));
+ if (!account->avatar().avatarData.isEmpty()) {
+ QIcon icon;
+ Tp::Avatar avatar = account->avatar();
+ icon.addPixmap(QPixmap::fromImage(QImage::fromData(avatar.avatarData)).scaled(48, 48));
- if (filename.isEmpty()) { // User hit cancel button
- return;
- }
+ QToolButton *avatarButton = new QToolButton(this);
+ avatarButton->setIcon(icon);
+ avatarButton->setIconSize(QSize(48, 48));
+ avatarButton->setText(i18nc("String in menu saying Use avatar from account X",
+ "Use from %1", account->displayName()));
+ avatarButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
- QFileInfo fileinfo(filename);
+ QWidgetAction *avatarAction = new QWidgetAction(m_avatarButtonMenu);
+ avatarAction->setDefaultWidget(avatarButton);
+ avatarAction->setData(account->uniqueIdentifier());
- kDebug() << "Filename:" << filename;
- kDebug() << "Content type:" << KMimeType::findByFileContent(filename)->name();
- // TODO Let the user set a description?
+ connect(avatarButton, SIGNAL(clicked(bool)),
+ avatarAction, SIGNAL(triggered(bool)));
- Tp::FileTransferChannelCreationProperties fileTransferProperties(filename,
- KMimeType::findByFileContent(filename)->name());
+ connect(avatarAction, SIGNAL(triggered(bool)),
+ this, SLOT(selectAvatarFromAccount()));
- Tp::PendingChannelRequest* channelRequest = account->createFileTransfer(contact,
- fileTransferProperties,
- QDateTime::currentDateTime(),
- PREFERRED_FILETRANSFER_HANDLER);
- connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-}
-void MainWidget::showMessageToUser(const QString& text, const MainWidget::SystemMessageType type)
-{
- //The pointer is automatically deleted when the event is closed
- KNotification *notification;
- if (type == MainWidget::SystemMessageError) {
- notification = new KNotification("telepathyError", this);
- } else {
- notification = new KNotification("telepathyInfo", this);
+ m_avatarButtonMenu->addAction(avatarAction);
}
-
- KAboutData aboutData("ktelepathy",0,KLocalizedString(),0);
- notification->setComponentData(KComponentData(aboutData));
-
- notification->setText(text);
- notification->sendEvent();
-}
-
-void MainWidget::addOverlayButtons()
-{
- TextChannelContactOverlay* textOverlay = new TextChannelContactOverlay(this);
- AudioChannelContactOverlay* audioOverlay = new AudioChannelContactOverlay(this);
- VideoChannelContactOverlay* videoOverlay = new VideoChannelContactOverlay(this);
-
- FileTransferContactOverlay* fileOverlay = new FileTransferContactOverlay(this);
-
- m_delegate->installOverlay(textOverlay);
- m_delegate->installOverlay(audioOverlay);
- m_delegate->installOverlay(videoOverlay);
- m_delegate->installOverlay(fileOverlay);
-
- textOverlay->setView(m_contactsListView);
- textOverlay->setActive(true);
-
- audioOverlay->setView(m_contactsListView);
- audioOverlay->setActive(true);
-
- videoOverlay->setView(m_contactsListView);
- videoOverlay->setActive(true);
-
- fileOverlay->setView(m_contactsListView);
- fileOverlay->setActive(true);
-
- connect(textOverlay, SIGNAL(overlayActivated(QModelIndex)),
- m_delegate, SLOT(hideStatusMessageSlot(QModelIndex)));
-
- connect(textOverlay, SIGNAL(overlayHidden()),
- m_delegate, SLOT(reshowStatusMessageSlot()));
-
- connect(textOverlay, SIGNAL(activated(ContactModelItem*)),
- this, SLOT(startTextChannel(ContactModelItem*)));
-
- connect(fileOverlay, SIGNAL(activated(ContactModelItem*)),
- this, SLOT(startFileTransferChannel(ContactModelItem*)));
-
- connect(audioOverlay, SIGNAL(activated(ContactModelItem*)),
- this, SLOT(startAudioChannel(ContactModelItem*)));
-
- connect(videoOverlay, SIGNAL(activated(ContactModelItem*)),
- this, SLOT(startVideoChannel(ContactModelItem*)));
-
- connect(this, SIGNAL(enableOverlays(bool)),
- textOverlay, SLOT(setActive(bool)));
-
- connect(this, SIGNAL(enableOverlays(bool)),
- audioOverlay, SLOT(setActive(bool)));
-
- connect(this, SIGNAL(enableOverlays(bool)),
- videoOverlay, SLOT(setActive(bool)));
-
- connect(this, SIGNAL(enableOverlays(bool)),
- fileOverlay, SLOT(setActive(bool)));
-
}
void MainWidget::toggleSearchWidget(bool show)
{
- if(show) {
+ if (show) {
m_filterBar->show();
}
else {
- m_modelFilter->clearFilterString();
m_filterBar->clear();
m_filterBar->hide();
}
}
-void MainWidget::onAddContactRequest() {
- QWeakPointer<AddContactDialog> dialog = new AddContactDialog(m_model, this);
- if (dialog.data()->exec() == QDialog::Accepted) {
- Tp::AccountPtr account = dialog.data()->account();
- QStringList identifiers = QStringList() << dialog.data()->screenName();
- Tp::PendingContacts* pendingContacts = account->connection()->contactManager()->contactsForIdentifiers(identifiers);
- connect(pendingContacts, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAddContactRequestFoundContacts(Tp::PendingOperation*)));
- }
- delete dialog.data();
-}
-
-void MainWidget::onAddContactRequestFoundContacts(Tp::PendingOperation *operation) {
- Tp::PendingContacts *pendingContacts = qobject_cast<Tp::PendingContacts*>(operation);
-
- if (! pendingContacts->isError()) {
- //request subscription
- pendingContacts->manager()->requestPresenceSubscription(pendingContacts->contacts());
- }
- else {
- kDebug() << pendingContacts->errorName();
- kDebug() << pendingContacts->errorMessage();
- }
-}
-
void MainWidget::onCustomContextMenuRequested(const QPoint &pos)
{
- QModelIndex index = m_contactsListView->indexAt(pos);
+ QModelIndex index = m_contactList->indexAt(pos);
if (!index.isValid()) {
return;
}
- Tp::ContactPtr contact;
- QVariant item = index.data(AccountsModel::ItemRole);
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
- KMenu *menu = 0;
+ QSharedPointer<KMenu> menu;
- if (item.userType() == qMetaTypeId<ContactModelItem*>()) {
- menu = contactContextMenu(index);
- } else if (item.userType() == qMetaTypeId<GroupsModelItem*>()) {
- menu = groupContextMenu(index);
+ if (contact.type() == QContactType::TypeContact) {
+ menu = contactContextMenu(contact);
}
if (menu) {
menu->exec(QCursor::pos());
- menu->deleteLater();
}
}
-KMenu* MainWidget::contactContextMenu(const QModelIndex &index)
+QSharedPointer<KMenu> MainWidget::contactContextMenu(const QContact &contact)
{
- if (!index.isValid()) {
- return 0;
- }
-
- Tp::ContactPtr contact = index.data(AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
-
- if (contact.isNull()) {
- kDebug() << "Contact is nulled";
- return 0;
- }
-
- Tp::AccountPtr account = m_model->accountForContactItem(index.data(AccountsModel::ItemRole).value<ContactModelItem*>());
-
- if (account.isNull()) {
- kDebug() << "Account is nulled";
- return 0;
- }
-
- KMenu *menu = new KMenu();
- menu->addTitle(contact->alias());
+ QSharedPointer<KMenu> menu(new KMenu);
+ menu->addTitle(contact.displayLabel());
QAction* action = menu->addAction(i18n("Start Chat..."));
action->setIcon(KIcon("mail-message-new"));
- action->setDisabled(true);
connect(action, SIGNAL(triggered(bool)),
SLOT(slotStartTextChat()));
- if (index.data(AccountsModel::TextChatCapabilityRole).toBool()) {
- action->setEnabled(true);
- }
-
- Tp::ConnectionPtr accountConnection = account->connection();
- if (accountConnection.isNull()) {
- kDebug() << "Account connection is nulled.";
- return 0;
- }
-
action = menu->addAction(i18n("Start Audio Call..."));
action->setIcon(KIcon("voicecall"));
- action->setDisabled(true);
connect(action, SIGNAL(triggered(bool)),
SLOT(slotStartAudioChat()));
- if (index.data(AccountsModel::AudioCallCapabilityRole).toBool()) {
- action->setEnabled(true);
- }
-
action = menu->addAction(i18n("Start Video Call..."));
action->setIcon(KIcon("webcamsend"));
- action->setDisabled(true);
connect(action, SIGNAL(triggered(bool)),
SLOT(slotStartVideoChat()));
- if (index.data(AccountsModel::VideoCallCapabilityRole).toBool()) {
- action->setEnabled(true);
- }
-
action = menu->addAction(i18n("Send File..."));
action->setIcon(KIcon("mail-attachment"));
- action->setDisabled(true);
connect(action, SIGNAL(triggered(bool)),
SLOT(slotStartFileTransfer()));
- if (index.data(AccountsModel::FileTransferCapabilityRole).toBool()) {
- action->setEnabled(true);
- }
-
menu->addSeparator();
// remove contact action
QAction *removeAction = menu->addAction(KIcon("list-remove-user"), i18n("Remove Contact"));
connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(slotDeleteContact()));
- if (accountConnection->actualFeatures().contains(Tp::Connection::FeatureRosterGroups)) {
- QMenu* groupAddMenu = menu->addMenu(i18n("Move to Group"));
-
- QStringList groupList;
- QList<Tp::AccountPtr> accounts = m_accountManager->allAccounts();
- foreach (const Tp::AccountPtr &account, accounts) {
- if (!account->connection().isNull()) {
- groupList.append(account->connection()->contactManager()->allKnownGroups());
- }
- }
-
- groupList.removeDuplicates();
-
- QStringList currentGroups = contact->groups();
-
- foreach (const QString &group, currentGroups) {
- groupList.removeAll(group);
- }
-
- connect(groupAddMenu->addAction(i18n("Create New Group...")), SIGNAL(triggered(bool)),
- this, SLOT(onCreateNewGroup()));
-
- groupAddMenu->addSeparator();
-
- foreach (const QString &group, groupList) {
- connect(groupAddMenu->addAction(group), SIGNAL(triggered(bool)),
- SLOT(slotAddContactToGroupTriggered()));
- }
- } else {
- kDebug() << "Unable to support Groups";
- }
-
- //menu->addSeparator();
-
- // TODO: Remove when Telepathy actually supports blocking.
- /*if (contact->isBlocked()) {
- * action = menu->addAction(i18n("Unblock User"));
- * connect(action, SIGNAL(triggered(bool)),
- * SLOT(slotUnblockContactTriggered()));
-} else {
- action = menu->addAction(i18n("Blocked"));
- connect(action, SIGNAL(triggered(bool)),
- SLOT(slotBlockContactTriggered()));
-}*/
-
menu->addSeparator();
action = menu->addAction(i18n("Show Info..."));
- action->setIcon(KIcon(""));
connect(action, SIGNAL(triggered()), SLOT(slotShowInfo()));
return menu;
}
-KMenu* MainWidget::groupContextMenu(const QModelIndex &index)
-{
- if (!index.isValid()) {
- return 0;
- }
-
- GroupsModelItem *groupItem = index.data(AccountsModel::ItemRole).value<GroupsModelItem*>();
-
- Q_ASSERT(groupItem);
-
- KMenu *menu = new KMenu();
- menu->addTitle(groupItem->groupName());
-
- QAction *action = menu->addAction(i18n("Rename Group..."));
- action->setIcon(KIcon("edit-rename"));
-
- connect(action, SIGNAL(triggered(bool)),
- this, SLOT(onRenameGroup()));
-
- action = menu->addAction(i18n("Delete Group"));
- action->setIcon(KIcon("edit-delete"));
-
- connect(action, SIGNAL(triggered(bool)),
- this, SLOT(onDeleteGroup()));
-
- return menu;
-}
-
-void MainWidget::slotAddContactToGroupTriggered()
-{
- QModelIndex index = m_contactsListView->currentIndex();
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
-
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- QAction *action = qobject_cast<QAction*>(sender());
- if (!action) {
- kDebug() << "Invalid action";
- return;
- }
-
- const QStringList currentGroups = contact->groups();
-
- Tp::PendingOperation* operation = contact->addToGroup(action->text().remove('&'));
-
- if (operation) {
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-
- foreach (const QString &group, currentGroups) {
- Tp::PendingOperation* operation = contact->removeFromGroup(group);
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
- }
-}
-
-void MainWidget::onCreateNewGroup()
-{
- QString newGroupName = KInputDialog::getText(i18n("New Group Name"), i18n("Please enter the new group name"));
-
- QModelIndex index = m_contactsListView->currentIndex();
- ContactModelItem *contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
-
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
- Tp::PendingOperation *operation = contact->addToGroup(newGroupName);
-
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-}
-
-void MainWidget::onRenameGroup()
-{
- QModelIndex index = m_contactsListView->currentIndex();
-
- GroupsModelItem *groupItem = index.data(AccountsModel::ItemRole).value<GroupsModelItem*>();
-
- Q_ASSERT(groupItem);
-
- QString newGroupName = KInputDialog::getText(i18n("New Group Name"), i18n("Please enter the new group name"), groupItem->groupName());
-
- for(int i = 0; i < groupItem->size(); i++) {
- Tp::ContactPtr contact = qobject_cast<ProxyTreeNode*>(groupItem->childAt(i))
- ->data(AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
- Q_ASSERT(contact);
-
- Tp::PendingOperation *operation = contact->addToGroup(newGroupName);
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-
- operation = contact->removeFromGroup(groupItem->groupName());
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
-}
-
-void MainWidget::onDeleteGroup()
-{
- QModelIndex index = m_contactsListView->currentIndex();
-
- GroupsModelItem *groupItem = index.data(AccountsModel::ItemRole).value<GroupsModelItem*>();
-
- if (KMessageBox::warningContinueCancel(this,
- i18n("Do you really want to remove group %1?\n\n"
- "Note that all contacts will be moved to group 'Ungroupped'", groupItem->groupName()),
- i18n("Remove Group")) == KMessageBox::Continue) {
-
- for(int i = 0; i < groupItem->size(); i++) {
- Tp::ContactPtr contact = qobject_cast<ProxyTreeNode*>(groupItem->childAt(i))
- ->data(AccountsModel::ItemRole).value<ContactModelItem*>()->contact();
- Q_ASSERT(contact);
-
- Tp::PendingOperation *operation = contact->removeFromGroup(groupItem->groupName());
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
-
- foreach (const Tp::AccountPtr &account, m_accountManager->allAccounts()) {
- if (account->connection()) {
- Tp::PendingOperation *operation = account->connection()->contactManager()->removeGroup(groupItem->groupName());
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
- }
- }
-}
-
-
-void MainWidget::slotBlockContactTriggered()
-{
- QModelIndex index = m_contactsListView->currentIndex();
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
-
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- Tp::PendingOperation *operation = contact->block(true);
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-}
-
void MainWidget::slotDeleteContact()
{
- QModelIndex index = m_contactsListView->currentIndex();
- ContactModelItem* contactItem = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
-
- Q_ASSERT(contactItem);
- Tp::ContactPtr contact = contactItem->contact();
-
- QList<Tp::ContactPtr>contactList;
- contactList.append(contact);
+ QContact contact = currentContact();
// ask for confirmation
- QWeakPointer<RemoveContactDialog> removeDialog = new RemoveContactDialog(contact, this);
-
- if (removeDialog.data()->exec() == QDialog::Accepted) {
- // remove from contact list
- Tp::PendingOperation *deleteOp = contact->manager()->removeContacts(contactList);
- connect(deleteOp, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
-
- if (removeDialog.data()->blockContact()) {
- // block contact
- Tp::PendingOperation *blockOp = contact->manager()->blockContacts(contactList);
- connect(blockOp, SIGNAL(finished(Tp::PendingOperation*)), this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
- }
+ RemoveContactDialog removeDialog(contact, this);
- delete removeDialog.data();
-}
-
-void MainWidget::slotGenericOperationFinished(Tp::PendingOperation* operation)
-{
- if (operation->isError()) {
- QString errorMsg(operation->errorName() + ": " + operation->errorMessage());
- showMessageToUser(errorMsg, SystemMessageError);
+ if (removeDialog.exec() == QDialog::Accepted) {
+ // TODO: remove from contact list
}
}
void MainWidget::slotShowInfo()
{
- QModelIndex index = m_contactsListView->currentIndex();
- if (!index.isValid()) {
- kDebug() << "Invalid index provided.";
- return;
- }
-
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (item) {
- showInfo(item);
- }
-}
-
-void MainWidget::showInfo(ContactModelItem *contactItem)
-{
- ContactInfo contactInfoDialog(contactItem->contact(), this);
+ QContact contact = currentContact();
+ ContactInfo contactInfoDialog(contact, this);
contactInfoDialog.exec();
}
void MainWidget::slotStartTextChat()
{
- QModelIndex index = m_contactsListView->currentIndex();
- if (!index.isValid()) {
- kDebug() << "Invalid index provided.";
- return;
- }
-
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (item) {
- startTextChannel(item);
- }
+ startTextChannel(currentContact());
}
void MainWidget::slotStartAudioChat()
{
- QModelIndex index = m_contactsListView->currentIndex();
- if (!index.isValid()) {
- kDebug() << "Invalid index provided.";
- return;
- }
-
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (item) {
- startAudioChannel(item);
- }
+ startAudioChannel(currentContact());
}
void MainWidget::slotStartVideoChat()
{
- QModelIndex index = m_contactsListView->currentIndex();
- if (!index.isValid()) {
- kDebug() << "Invalid index provided.";
- return;
- }
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (item) {
- startVideoChannel(item);
- }
+ startVideoChannel(currentContact());
}
void MainWidget::slotStartFileTransfer()
{
- QModelIndex index = m_contactsListView->currentIndex();
- if (!index.isValid()) {
- kDebug() << "Invalid index provided.";
- return;
- }
-
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- if (item) {
- startFileTransferChannel(item);
- }
+ startFileTransferChannel(currentContact());
}
-void MainWidget::slotUnblockContactTriggered()
+QContact MainWidget::currentContact() const
{
- QModelIndex index = m_contactsListView->currentIndex();
- ContactModelItem* item = index.data(AccountsModel::ItemRole).value<ContactModelItem*>();
- Q_ASSERT(item);
-
- Tp::ContactPtr contact = item->contact();
-
- Tp::PendingOperation *operation = contact->block(false);
- connect(operation, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
+ QModelIndex index = m_contactList->currentIndex();
+ return index.data(ContactModel::ContactRole).value<QContact>();
}
-
-void MainWidget::setCustomPresenceMessage(const QString& message)
+void MainWidget::startAudioChannel(const QContact &contact)
{
- for (int i = 0; i < m_accountButtonsLayout->count() - 1; i++) {
- qobject_cast<AccountButton*>(m_accountButtonsLayout->itemAt(i)->widget())->setCustomPresenceMessage(message);
-
- }
-
- m_presenceMessageEdit->clearFocus();
+ m_actionInvoker->invoke("call", contact);
}
-void MainWidget::showSettingsKCM()
+void MainWidget::startFileTransferChannel(const QContact &contact)
{
- KSettings::Dialog *dialog = new KSettings::Dialog(this);
-
- dialog->addModule("kcm_telepathy_accounts");
-
- dialog->setAttribute(Qt::WA_DeleteOnClose);
- dialog->exec();
+ m_actionInvoker->invoke("file-transfer", contact);
}
-void MainWidget::loadAvatar(const Tp::AccountPtr &account)
+void MainWidget::startTextChannel(const QContact &contact)
{
- if (!account->avatar().avatarData.isEmpty()) {
- QIcon icon;
- Tp::Avatar avatar = account->avatar();
- icon.addPixmap(QPixmap::fromImage(QImage::fromData(avatar.avatarData)).scaled(48, 48));
-
- QToolButton *avatarButton = new QToolButton(this);
- avatarButton->setIcon(icon);
- avatarButton->setIconSize(QSize(48, 48));
- avatarButton->setText(i18nc("String in menu saying Use avatar from account X",
- "Use from %1", account->displayName()));
- avatarButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
-
- QWidgetAction *avatarAction = new QWidgetAction(m_avatarButtonMenu);
- avatarAction->setDefaultWidget(avatarButton);
- avatarAction->setData(account->uniqueIdentifier());
-
- connect(avatarButton, SIGNAL(clicked(bool)),
- avatarAction, SIGNAL(triggered(bool)));
-
- connect(avatarAction, SIGNAL(triggered(bool)),
- this, SLOT(selectAvatarFromAccount()));
-
-
- m_avatarButtonMenu->addAction(avatarAction);
- }
+ m_actionInvoker->invoke("chat", contact);
}
-void MainWidget::selectAvatarFromAccount()
+void MainWidget::startVideoChannel(const QContact &contact)
{
- selectAvatarFromAccount(qobject_cast<QWidgetAction*>(sender())->data().toString());
+ m_actionInvoker->invoke("video-call", contact);
}
-void MainWidget::selectAvatarFromAccount(const QString &accountUID)
+void MainWidget::onContactListClicked(const QModelIndex& index)
{
- if (accountUID.isEmpty()) {
- kDebug() << "Supplied accountUID is empty, aborting...";
- return;
- }
-
- if (m_model->accountItemForId(accountUID) == 0) {
- kDebug() << "Chosen account ID does not exist, aborting..";
-
- //no point of keeping the config if the previously set account ID does not exist
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup avatarGroup(config, "Avatar");
- avatarGroup.deleteGroup();
- avatarGroup.config()->sync();
-
+ if (!index.isValid()) {
return;
}
- Tp::Avatar avatar = qobject_cast<AccountsModelItem*>(m_model->accountItemForId(accountUID))->data(AccountsModel::AvatarRole).value<Tp::Avatar>();
-
- foreach (const Tp::AccountPtr &account, m_accountManager->allAccounts()) {
- //don't set the avatar for the account from where it was taken
- if (account->uniqueIdentifier() == accountUID) {
- continue;
- }
-
- account->setAvatar(avatar);
- }
-
- //add the selected avatar as the icon of avatar button
- QIcon icon;
- icon.addPixmap(QPixmap::fromImage(QImage::fromData(avatar.avatarData)).scaled(48, 48));
- m_userAccountIconButton->setIcon(icon);
-
- m_avatarButtonMenu->close();
-
- //save the selected account into config
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup avatarGroup(config, "Avatar");
- avatarGroup.writeEntry("method", "account");
- avatarGroup.writeEntry("source", accountUID);
- avatarGroup.config()->sync();
-
-}
-
-void MainWidget::loadAvatarFromFile()
-{
- if (m_accountManager->allAccounts().isEmpty()) {
- int returnCode = KMessageBox::warningYesNo(this,
- i18nc("Dialog text", "You have no accounts set. Would you like to set one now?"),
- i18nc("Dialog caption", "No accounts set"));
-
- if (returnCode == KMessageBox::Yes) {
- showSettingsKCM();
- loadAvatarFromFile();
- } else {
- return;
- }
- } else {
- KUrl fileUrl = KFileDialog::getImageOpenUrl(KUrl(), this,
- i18n("Please choose your avatar"));
-
- if (!fileUrl.isEmpty()) {
- FetchAvatarJob *job = new FetchAvatarJob(fileUrl, this);
-
- connect(job, SIGNAL(result(KJob*)),
- this, SLOT(onAvatarFetched(KJob*)));
-
- job->start();
+ if (index.model()->rowCount(index) > 0) {
+ if (m_contactList->isExpanded(index)) {
+ m_contactList->collapse(index);
} else {
- return;
+ m_contactList->expand(index);
}
}
}
-
-void MainWidget::onAvatarFetched(KJob *job)
-{
- if (job->error()) {
- KMessageBox::error(this, job->errorString());
- return;
- }
-
- //this should never be true, but better one "if" than a crash
- if (m_accountManager->allAccounts().isEmpty()) {
- int returnCode = KMessageBox::warningYesNo(this,
- i18nc("Dialog text", "You have no accounts set. Would you like to set one now?"),
- i18nc("Dialog caption", "No accounts set"));
-
- if (returnCode == KMessageBox::Yes) {
- showSettingsKCM();
- } else {
- return;
- }
- } else {
-
- FetchAvatarJob *fetchJob = qobject_cast< FetchAvatarJob* >(job);
-
- Q_ASSERT(fetchJob);
-
- foreach (const Tp::AccountPtr &account, m_accountManager->allAccounts()) {
- Tp::PendingOperation *op = account->setAvatar(fetchJob->avatar());
-
- //connect for eventual error displaying
- connect(op, SIGNAL(finished(Tp::PendingOperation*)),
- this, SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
-
- //add the selected avatar to the avatar button
- QIcon icon;
- icon.addPixmap(QPixmap::fromImage(QImage::fromData(fetchJob->avatar().avatarData)).scaled(48, 48));
- m_userAccountIconButton->setIcon(icon);
-
- //since all the accounts will have the same avatar,
- //we take simply the first in AM and use this in config
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup avatarGroup(config, "Avatar");
- avatarGroup.writeEntry("method", "account");
- avatarGroup.writeEntry("source", m_accountManager->allAccounts().first()->uniqueIdentifier());
- avatarGroup.config()->sync();
- }
-}
-
-void MainWidget::onAccountsPresenceStatusFiltered()
-{
- kDebug() << "Watcher is here";
- QFutureWatcher< Tp::ContactPtr > *watcher = dynamic_cast< QFutureWatcher< Tp::ContactPtr > * >(sender());
- kDebug() << "Watcher is casted";
- Tp::Contacts contacts = watcher->future().results().toSet();
- kDebug() << "Watcher is used";
- if (!contacts.isEmpty()) {
- onPresencePublicationRequested(contacts);
- }
- watcher->deleteLater();
-}
-
-void MainWidget::onPresencePublicationRequested(const Tp::Contacts& contacts)
-{
- foreach (const Tp::ContactPtr &contact, contacts) {
- Tp::ContactManagerPtr manager = contact->manager();
- Tp::PendingOperation *op = 0;
-
- if (contact->subscriptionState() == Tp::Contact::PresenceStateYes) {
- op = manager->authorizePresencePublication(QList< Tp::ContactPtr >() << contact);
- } else if (KMessageBox::questionYesNo(this, i18n("The contact %1 added you to their contact list. "
- "Do you want to allow this person to see your presence "
- "and add them to your contact list?", contact->id()),
- i18n("Subscription request")) == KMessageBox::Yes) {
-
- op = manager->authorizePresencePublication(QList< Tp::ContactPtr >() << contact);
-
- if (manager->canRequestPresenceSubscription() && contact->subscriptionState() == Tp::Contact::PresenceStateNo) {
- manager->requestPresenceSubscription(QList< Tp::ContactPtr >() << contact);
- }
- }
-
- if (op) {
- connect(op, SIGNAL(finished(Tp::PendingOperation*)),
- SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
- }
-}
-
-void MainWidget::handleConnectionError(const Tp::AccountPtr& account)
-{
- QString connectionError = account->connectionError();
-
- // ignore user disconnect
- if (connectionError == "org.freedesktop.Telepathy.Error.Cancelled") {
- return;
- }
-
- Tp::ConnectionStatusReason reason = account->connectionStatusReason();
-
- if (reason == Tp::ConnectionStatusReasonAuthenticationFailed) {
- showMessageToUser(i18n("Could not connect %1. Authentication failed (is your password correct?)", account->displayName()), MainWidget::SystemMessageError);
- } else if (reason == Tp::ConnectionStatusReasonNetworkError) {
- showMessageToUser(i18n("Could not connect %1. There was a network error, check your connection", account->displayName()), MainWidget::SystemMessageError);
- } else {
- // other errors
- showMessageToUser(i18n("An unexpected error has occurred with %1: '%2'", account->displayName(), account->connectionError()), MainWidget::SystemMessageError);
- }
-}
-
-void MainWidget::onGroupContacts(bool enabled)
-{
- if (enabled) {
- m_modelFilter->setSourceModel(m_groupsModel);
- } else {
- m_modelFilter->setSourceModel(m_model);
- }
-}
-
-void MainWidget::onJoinChatRoomRequested()
-{
- QWeakPointer<JoinChatRoomDialog> dialog = new JoinChatRoomDialog(m_accountManager);
-
- if (dialog.data()->exec() == QDialog::Accepted) {
- Tp::AccountPtr account = dialog.data()->selectedAccount();
-
- // check account validity. Should NEVER be invalid
- if (!account.isNull()) {
- // ensure chat room
- Tp::PendingChannelRequest *channelRequest = account->ensureTextChatroom(dialog.data()->selectedChatRoom(),
- QDateTime::currentDateTime(),
- PREFERRED_TEXTCHAT_HANDLER);
- connect(channelRequest, SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotGenericOperationFinished(Tp::PendingOperation*)));
- }
- }
-
- delete dialog.data();
-}
-
-void MainWidget::onSwitchToFullView()
-{
- m_contactsListView->setItemDelegate(m_delegate);
- m_contactsListView->doItemsLayout();
-
- emit enableOverlays(true);
-
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup guiConfigGroup(config, "GUI");
- guiConfigGroup.writeEntry("selected_delegate", "full");
- guiConfigGroup.config()->sync();
-}
-
-void MainWidget::onSwitchToCompactView()
-{
- m_contactsListView->setItemDelegate(m_compactDelegate);
- m_contactsListView->doItemsLayout();
-
- emit enableOverlays(false);
-
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup guiConfigGroup(config, "GUI");
- guiConfigGroup.writeEntry("selected_delegate", "compact");
- guiConfigGroup.config()->sync();
-}
-
-void MainWidget::closeEvent(QCloseEvent* e)
-{
- KSharedConfigPtr config = KGlobal::config();
- KConfigGroup generalConfigGroup(config, "General");
- KConfigGroup notifyConigGroup(config, "Notification Messages");
-
- ContactListApplication *app = qobject_cast<ContactListApplication*>(kapp);
- if (!app->isShuttingDown()) {
- //the standard KMessageBox control saves "true" if you select the checkbox, therefore the reversed var name
- bool dontCheckForPlasmoid = notifyConigGroup.readEntry("dont_check_for_plasmoid", false);
-
- if (isAnyAccountOnline() && !dontCheckForPlasmoid) {
- if (!isPresencePlasmoidPresent()) {
- switch (KMessageBox::warningYesNoCancel(this,
- i18n("You do not have any other presence controls active (a Presence widget for example).\n"
- "Do you want to stay online or would you rather go offline?"),
- i18n("No Other Presence Controls Found"),
- KGuiItem(i18n("Stay Online"), KIcon("user-online")),
- KGuiItem(i18n("Go Offline"), KIcon("user-offline")),
- KStandardGuiItem::cancel(),
- QString("dont_check_for_plasmoid"))) {
-
- case KMessageBox::No:
- generalConfigGroup.writeEntry("go_offline_when_closing", true);
- goOffline();
- break;
- case KMessageBox::Cancel:
- e->ignore();
- return;
- }
- }
- } else if (isAnyAccountOnline() && dontCheckForPlasmoid) {
- bool shouldGoOffline = generalConfigGroup.readEntry("go_offline_when_closing", false);
- if (shouldGoOffline) {
- goOffline();
- }
- }
-
- generalConfigGroup.config()->sync();
- }
-
- KMainWindow::closeEvent(e);
-}
-
-bool MainWidget::isPresencePlasmoidPresent() const
-{
- QDBusInterface plasmoidOnDbus("org.kde.Telepathy.PresenceEngineActive", "/PresenceEngineActive");
-
- if (plasmoidOnDbus.isValid()) {
- return true;
- } else {
- return false;
- }
-}
-
-void MainWidget::goOffline()
-{
- kDebug() << "Setting all accounts offline...";
- foreach (const Tp::AccountPtr &account, m_accountManager->allAccounts()) {
- if (account->isEnabled() && account->isValid()) {
- account->setRequestedPresence(Tp::Presence::offline());
- }
- }
-}
-
-bool MainWidget::isAnyAccountOnline() const
-{
- foreach (const Tp::AccountPtr &account, m_accountManager->allAccounts()) {
- if (account->isEnabled() && account->isValid() && account->isOnline()) {
- return true;
- }
- }
-
- return false;
-}
-
-#include "main-widget.moc"
diff --git a/main-widget.h b/main-widget.h
index bc3d1f8..5e7669d 100644
--- a/main-widget.h
+++ b/main-widget.h
@@ -5,6 +5,7 @@
* @Author George Goldberg <george.goldberg@collabora.co.uk>
* Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
* Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,135 +22,83 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef TELEPATHY_CONTACTSLIST_MAIN_WIDGET_H
-#define TELEPATHY_CONTACTSLIST_MAIN_WIDGET_H
+#ifndef MAIN_WIDGET_H
+#define MAIN_WIDGET_H
-#include <QtGui/QWidget>
-#include <QtGui/QStyledItemDelegate>
+#include <QSharedPointer>
+
+#include <KMainWindow>
+#include <KMenu>
#include <TelepathyQt4/AccountManager>
+#include <TelepathyQt4/AccountSet>
-#include <KXmlGuiWindow>
-#include <KAction>
#include "ui_main-widget.h"
-class ContactDelegateCompact;
-class GroupsModel;
-class KMenu;
-class KSelectAction;
-class AccountsModel;
-class AccountsFilterModel;
+class QModelIndex;
+
+class KAction;
+
+class ActionInvoker;
class ContactDelegate;
-class FilterBar;
-class KJob;
-class ContactModelItem;
+class ContactFilterModel;
+class ContactList;
+class ContactModel;
class MainWidget : public KMainWindow, Ui::MainWindow
{
Q_OBJECT
+
public:
+
MainWidget(QWidget *parent = 0);
~MainWidget();
- bool isPresencePlasmoidPresent() const;
- bool isAnyAccountOnline() const;
-
- enum SystemMessageType {
- /*
- * this will show a system message to the user
- * but it will fade after short timout,
- * thus it should be used for non-important messages
- * like "Connecting..." etc.
- */
- SystemMessageInfo,
-
- /*
- * message with this class will stay visible until user
- * closes it and will have light-red background
- */
- SystemMessageError
- };
-
-public Q_SLOTS:
+private Q_SLOTS:
+
void onAccountManagerReady(Tp::PendingOperation *op);
+ void onAccountAdded(const Tp::AccountPtr &account);
+ void onAccountRemoved(const Tp::AccountPtr &account);
- void onContactListClicked(const QModelIndex &index);
- void onContactListDoubleClick(const QModelIndex &index);
- void onConnectionChanged(const Tp::ConnectionPtr &connection);
- void onAccountConnectionStatusChanged(Tp::ConnectionStatus status);
- void showMessageToUser(const QString &text, const SystemMessageType type);
- void addOverlayButtons();
- void onNewAccountAdded(const Tp::AccountPtr &account);
- void onAccountStateChanged(bool enabled);
- void onAccountRemoved();
- void toggleSearchWidget(bool show);
- void setCustomPresenceMessage(const QString &message);
+ void setCustomPresenceMessage(const QString& message);
void showSettingsKCM();
- void onAddContactRequest();
- void onAddContactRequestFoundContacts(Tp::PendingOperation *operation);
void loadAvatar(const Tp::AccountPtr &account);
- void selectAvatarFromAccount(const QString &accountUID);
- void selectAvatarFromAccount();
- void loadAvatarFromFile();
- void showInfo(ContactModelItem *contactItem);
- void startTextChannel(ContactModelItem *contactItem);
- void startFileTransferChannel(ContactModelItem *contactItem);
- void startAudioChannel(ContactModelItem *contactItem);
- void startVideoChannel(ContactModelItem *contactItem);
- void onCustomContextMenuRequested(const QPoint &point);
- void onGroupContacts(bool enabled);
- void onJoinChatRoomRequested(); /** join chat room action is triggered */
- void goOffline();
+ void toggleSearchWidget(bool show);
+
+ void onCustomContextMenuRequested(const QPoint &pos);
+ void onContactListClicked(const QModelIndex& index);
-private Q_SLOTS:
- void slotAddContactToGroupTriggered();
- void slotBlockContactTriggered();
void slotDeleteContact();
- void slotGenericOperationFinished(Tp::PendingOperation *operation); /** called when a Tp::PendingOperation finishes. Used to check for errors */
void slotShowInfo();
void slotStartTextChat();
void slotStartAudioChat();
void slotStartVideoChat();
void slotStartFileTransfer();
- void slotUnblockContactTriggered();
- void onAvatarFetched(KJob*);
- void onAccountsPresenceStatusFiltered();
- void onPresencePublicationRequested(const Tp::Contacts &contacts);
- void monitorPresence(const Tp::ConnectionPtr &connection);
- void onContactManagerStateChanged(Tp::ContactListState state);
- void onContactManagerStateChanged(const Tp::ContactManagerPtr &contactManager, Tp::ContactListState state);
- void onSwitchToFullView();
- void onSwitchToCompactView();
- void onCreateNewGroup();
- void onRenameGroup();
- void onDeleteGroup();
-
-Q_SIGNALS:
- void enableOverlays(bool);
+
+ void startTextChannel(const QContact &contact);
+ void startAudioChannel(const QContact &contact);
+ void startVideoChannel(const QContact &contact);
+ void startFileTransferChannel(const QContact &contact);
private:
- /** handle connection errors for given account. This method provides visual notification */
- void handleConnectionError(const Tp::AccountPtr &account);
- void closeEvent(QCloseEvent *e);
-
- KMenu* contactContextMenu(const QModelIndex &index);
- KMenu* groupContextMenu(const QModelIndex &index);
-
- AccountsModel *m_model;
- GroupsModel *m_groupsModel;
- AccountsFilterModel *m_modelFilter;
- Tp::AccountManagerPtr m_accountManager;
- KMenu *m_accountMenu;
- KMenu *m_avatarButtonMenu;
- KSelectAction *m_setStatusAction;
- ContactDelegate *m_delegate;
- ContactDelegateCompact *m_compactDelegate;
- KAction *m_addContactAction;
- KAction *m_groupContactsAction;
- KAction *m_showOfflineAction;
- KAction *m_searchContactAction;
- KAction *m_sortByPresenceAction;
+ void setupToolBar();
+ QContact currentContact() const;
+ QSharedPointer<KMenu> contactContextMenu(const QContact &contact);
+
+ ContactDelegate *m_delegate;
+ QAbstractItemModel *m_model;
+ ContactFilterModel *m_filterModel;
+ KMenu *m_avatarButtonMenu;
+ KAction *m_addContactAction;
+ KAction *m_groupContactsAction;
+ KAction *m_showOfflineAction;
+ KAction *m_searchContactAction;
+ KAction *m_sortByPresenceAction;
+
+ Tp::AccountManagerPtr m_accountManager;
+ Tp::AccountSetPtr m_accounts;
+
+ ActionInvoker *m_actionInvoker;
};
-
-#endif // Header guard
+#endif // MAIN_WIDGET_H
diff --git a/main-widget.ui b/main-widget.ui
index 73c4333..dd019c7 100644
--- a/main-widget.ui
+++ b/main-widget.ui
@@ -91,7 +91,7 @@
</widget>
</item>
<item>
- <widget class="QTreeView" name="m_contactsListView"/>
+ <widget class="ContactList" name="m_contactList"/>
</item>
<item>
<widget class="FilterBar" name="m_filterBar" native="true"/>
@@ -111,6 +111,11 @@
<header>filter-bar.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>ContactList</class>
+ <extends>QTreeView</extends>
+ <header>contact-list.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>
diff --git a/main.cpp b/main.cpp
index 049d655..621f027 100644
--- a/main.cpp
+++ b/main.cpp
@@ -19,17 +19,15 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "main-widget.h"
-
#include <KAboutData>
#include <KCmdLineArgs>
#include <KDebug>
-#include <KUniqueApplication>
+#include <KApplication>
#include <TelepathyQt4/Types>
#include <TelepathyQt4/Debug>
-#include "contact-list-application.h"
+#include "main-widget.h"
int main(int argc, char *argv[])
{
@@ -48,7 +46,7 @@ int main(int argc, char *argv[])
options.add("debug", ki18n("Show Telepathy debugging information"));
KCmdLineArgs::addCmdLineOptions(options);
- ContactListApplication app;
+ KApplication app;
Tp::registerTypes();
Tp::enableDebug(KCmdLineArgs::parsedArgs()->isSet("debug"));
diff --git a/models/contact-filter-model.cpp b/models/contact-filter-model.cpp
new file mode 100644
index 0000000..651802a
--- /dev/null
+++ b/models/contact-filter-model.cpp
@@ -0,0 +1,150 @@
+/*
+ * Provide some filters on the account model
+ *
+ * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
+ * Copyright (C) 2011 Martin Klapetek <martin dot klapetek at gmail dot com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "contact-filter-model.h"
+
+#include "contact-model.h"
+
+#include <QContactPresence>
+
+#include <KDebug>
+
+QTM_USE_NAMESPACE
+
+ContactFilterModel::ContactFilterModel(QObject *parent)
+ : QSortFilterProxyModel(parent),
+ m_showOfflineUsers(false),
+ m_filterByName(false)
+{
+
+}
+
+void ContactFilterModel::showOfflineUsers(bool showOfflineUsers)
+{
+ m_showOfflineUsers = showOfflineUsers;
+ invalidateFilter();
+}
+
+bool ContactFilterModel::showOfflineUsers() const
+{
+ return m_showOfflineUsers;
+}
+
+bool ContactFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
+
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ if (contact.type() == QContactType::TypeContact) {
+ return filterAcceptsContact(contact);
+ }
+ else {
+ return filterAcceptsGroup(index);
+ return true;
+ }
+}
+
+bool ContactFilterModel::filterAcceptsAccount(const QModelIndex &index) const
+{
+ Q_UNUSED(index);
+ return true;
+}
+
+bool ContactFilterModel::filterAcceptsContact(const QContact &contact) const
+{
+ if (m_filterByName && !contact.displayLabel().contains(m_filterString, Qt::CaseInsensitive)) {
+ return false;
+ }
+
+ //filter offline users out
+ if (!m_showOfflineUsers) {
+ QContactPresence::PresenceState state = contact.detail<QContactPresence>().presenceState();
+ if (state == QContactPresence::PresenceUnknown ||
+ state == QContactPresence::PresenceOffline)
+ return false;
+ }
+
+ return true;
+}
+
+bool ContactFilterModel::filterAcceptsGroup(const QModelIndex &index) const
+{
+ return true;
+}
+
+void ContactFilterModel::setFilterString(const QString &str)
+{
+ m_filterString = str;
+ m_filterByName = true;
+ invalidateFilter();
+}
+
+void ContactFilterModel::clearFilterString()
+{
+ m_filterString.clear();
+ m_filterByName = false;
+ invalidateFilter();
+}
+
+bool ContactFilterModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const
+{
+ QContact leftContact = left.data(ContactModel::ContactRole).value<QContact>();
+ QContact rightContact = right.data(ContactModel::ContactRole).value<QContact>();
+
+ QString leftDisplayedName = leftContact.displayLabel();
+ QString rightDisplayedName = rightContact.displayLabel();
+
+ if (isSortedByPresence()) {
+ QContactPresence::PresenceState leftPresence = leftContact.detail<QContactPresence>().presenceState();
+ QContactPresence::PresenceState rightPresence = rightContact.detail<QContactPresence>().presenceState();
+
+ if (leftPresence == rightPresence) {
+ return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
+ } else {
+ if (leftPresence == QContactPresence::PresenceAvailable) {
+ return true;
+ }
+ if (leftPresence == QContactPresence::PresenceUnknown ||
+ leftPresence == QContactPresence::PresenceOffline) {
+ return false;
+ }
+
+ return static_cast<uint>(leftPresence) < static_cast<uint>(rightPresence);
+ }
+ } else {
+ return QString::localeAwareCompare(leftDisplayedName, rightDisplayedName) < 0;
+ }
+}
+
+void ContactFilterModel::setSortByPresence(bool enabled)
+{
+ if (enabled) {
+ setSortRole(ContactModel::ContactRole);
+ } else {
+ setSortRole(Qt::DisplayRole);
+ }
+}
+
+bool ContactFilterModel::isSortedByPresence() const
+{
+ return sortRole() == ContactModel::ContactRole;
+}
diff --git a/models/contact-filter-model.h b/models/contact-filter-model.h
new file mode 100644
index 0000000..1655484
--- /dev/null
+++ b/models/contact-filter-model.h
@@ -0,0 +1,88 @@
+/*
+ * Provide some filters on the account model
+ *
+ * Copyright (C) 2011 David Edmundson <kde@davidedmundson.co.uk>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 CONTACT_FILTER_MODEL_H
+#define CONTACT_FILTER_MODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include <QContact>
+
+QTM_USE_NAMESPACE
+
+/**
+ * \brief Class used to sort and filter the contacts.
+ *
+ * Filters:
+ * Hide offline contacts
+ * Hide contacts not matching a string in the search bar
+ * Sort contacts:
+ * By name
+ * By presence
+ */
+class ContactFilterModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ ContactFilterModel(QObject *parent = 0);
+
+ bool showOfflineUsers() const;
+
+ /**
+ * \brief Flag to sort the contactlist by presence.
+ *
+ * If set to false, the contact list is only sorted by name.
+ */
+ bool isSortedByPresence() const;
+
+public slots:
+ void showOfflineUsers(bool showOfflineUsers);
+ void setFilterString(const QString &str);
+ void clearFilterString();
+ /**
+ * \brief Lets the proxy know whether the model should get sorted by presence or not.
+ *
+ * \param enabled if true, the model will get sorted by presence, otherwise just by name.
+ */
+ void setSortByPresence(bool enabled);
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+ bool lessThan ( const QModelIndex &left, const QModelIndex &right ) const;
+
+private:
+
+ bool filterAcceptsAccount(const QModelIndex &index) const;
+ bool filterAcceptsContact(const QContact &contact) const;
+ bool filterAcceptsGroup(const QModelIndex &index) const;
+
+ /// Shows offline users
+ bool m_showOfflineUsers;
+
+ /// Used when searching for contact
+ bool m_filterByName;
+
+ /// Holds the string which is searched in the model
+ QString m_filterString;
+};
+
+#endif // CONTACT_FILTER_MODEL_H
diff --git a/models/contact-model.cpp b/models/contact-model.cpp
new file mode 100644
index 0000000..70f7537
--- /dev/null
+++ b/models/contact-model.cpp
@@ -0,0 +1,164 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "contact-model.h"
+
+#include <QContactLocalIdFilter>
+#include <QContactDetailFilter>
+
+#include <KDebug>
+#include <KLocalizedString>
+
+ContactModel::ContactModel(QContactManager *manager,
+ const QString &contactType,
+ QObject *parent)
+ : QAbstractListModel(parent)
+ , m_manager(manager)
+ , m_contactType(contactType)
+{
+ connect(m_manager, SIGNAL(contactsAdded(const QList<QContactLocalId>&)),
+ this, SLOT(contactsAdded(const QList<QContactLocalId>&)));
+ connect(m_manager, SIGNAL(contactsRemoved(const QList<QContactLocalId>&)),
+ this, SLOT(contactsRemoved(const QList<QContactLocalId>&)));
+ connect(m_manager, SIGNAL(contactsChanged(const QList<QContactLocalId>&)),
+ this, SLOT(contactsChanged(const QList<QContactLocalId>&)));
+}
+
+QVariant ContactModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ int i = index.row();
+
+ if (i >= 0 && i < m_contacts.size()) {
+ const QContact &contact = m_contacts.at(i);
+ switch (role) {
+ case Qt::DisplayRole:
+ return contact.displayLabel();
+ case ContactRole:
+ return QVariant::fromValue(contact);
+ }
+ }
+
+ return QVariant();
+}
+
+int ContactModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_contacts.size();
+}
+
+void ContactModel::contactsAdded(const QList<QContactLocalId> &ids)
+{
+ QList<QContact> contacts = contactsFromIds(ids);
+ kDebug() << m_contactType << ids;
+ if (!contacts.isEmpty()) {
+ beginInsertRows(QModelIndex(), m_contacts.size(), m_contacts.size() + contacts.size() - 1);
+ m_contacts << contacts;
+ endInsertRows();
+ }
+}
+
+void ContactModel::contactsChanged(const QList<QContactLocalId> &ids)
+{
+ QList<QContact> changedContacts = contactsFromIds(ids);
+ foreach (const QContact &contact, changedContacts) {
+ int i = indexOf(contact.localId());
+ if (i != -1) {
+ QModelIndex idx = index(i, 0);
+ m_contacts[i] = contact;
+ emit dataChanged(idx, idx);
+ }
+ }
+}
+
+void ContactModel::contactsRemoved(const QList<QContactLocalId> &ids)
+{
+ foreach (const QContactLocalId &id, ids) {
+ int i = indexOf(id);
+ if (i != -1) {
+ beginRemoveRows(QModelIndex(), i, i);
+ m_contacts.removeAt(i);
+ endRemoveRows();
+ }
+ }
+}
+
+int ContactModel::indexOf(const QContactLocalId &id)
+{
+ for (int i = 0; i < m_contacts.size(); i++) {
+ if (m_contacts[i].localId() == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+QList<QContact> ContactModel::contactsFromIds(const QList<QContactLocalId> &ids) const
+{
+ QContactLocalIdFilter idFilter;
+ idFilter.setIds(ids);
+
+ QContactDetailFilter typeFilter;
+ typeFilter.setDetailDefinitionName(QContactType::DefinitionName, QContactType::FieldType);
+ typeFilter.setValue(m_contactType);
+
+ return m_manager->contacts(idFilter & typeFilter);
+}
+
+ContactGrouping::ContactGrouping(ContactModel *groups, QObject *parent)
+ : Grouping(groups, parent)
+ , m_groupModel(groups)
+{
+ m_ungroupedGroup.setType(QContactType::TypeGroup);
+}
+
+QList<int> ContactGrouping::groupsOf(const QModelIndex &index) const
+{
+ QContact contact = index.data(ContactModel::ContactRole).value<QContact>();
+ QContactManager *manager = m_groupModel->manager();
+ QList<QContactRelationship> relationships =
+ manager->relationships(QContactRelationship::HasMember,
+ contact.id(),
+ QContactRelationship::Second);
+ kDebug() << relationships.size() << "relationships";
+ QList<int> result;
+ foreach (const QContactRelationship &rel, relationships) {
+ int groupId = m_groupModel->indexOf(rel.first().localId());
+ if (groupId != -1) {
+ result << groupId;
+ }
+ }
+ return result;
+}
+
+QVariant ContactGrouping::ungrouped(int role) const
+{
+ if (role == Qt::DisplayRole) {
+ return i18n("Ungrouped");
+ } else if (role == ContactModel::ContactRole) {
+ return QVariant::fromValue(m_ungroupedGroup);
+ } else {
+ return QVariant();
+ }
+}
diff --git a/models/contact-model.h b/models/contact-model.h
new file mode 100644
index 0000000..1f50e16
--- /dev/null
+++ b/models/contact-model.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 CONTACT_MODEL_H
+#define CONTACT_MODEL_H
+
+#include <QAbstractListModel>
+#include <QString>
+
+#include <QContactManager>
+#include <QContact>
+
+#include "grouping-model.h"
+
+QTM_USE_NAMESPACE
+
+class ContactModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+
+ enum {
+ ContactRole = Qt::UserRole
+ };
+
+ explicit ContactModel(QContactManager *manager, const QString &contactType, QObject *parent = 0);
+
+ virtual int rowCount(const QModelIndex &parent) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int indexOf(const QContactLocalId &id);
+
+ QContactManager *manager() const { return m_manager; }
+
+private Q_SLOTS:
+
+ void contactsAdded(const QList<QContactLocalId> &ids);
+ void contactsRemoved(const QList<QContactLocalId> &ids);
+ void contactsChanged(const QList<QContactLocalId> &ids);
+
+private:
+
+ QList<QContact> contactsFromIds(const QList<QContactLocalId> &ids) const;
+
+ QContactManager *m_manager;
+ QList<QContact> m_contacts;
+
+ QString m_contactType;
+};
+
+class ContactGrouping : public Grouping
+{
+ Q_OBJECT
+
+public:
+
+ explicit ContactGrouping(ContactModel *groups, QObject *parent);
+
+ virtual QList<int> groupsOf(const QModelIndex &index) const;
+ virtual QVariant ungrouped(int role) const;
+
+private:
+
+ ContactModel *m_groupModel;
+ QContact m_ungroupedGroup;
+};
+
+Q_DECLARE_METATYPE(QContact);
+
+#endif // CONTACT_MODEL_H
diff --git a/models/grouping-model.cpp b/models/grouping-model.cpp
new file mode 100644
index 0000000..e434499
--- /dev/null
+++ b/models/grouping-model.cpp
@@ -0,0 +1,282 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "grouping-model.h"
+
+#include <KDebug>
+
+Grouping::Grouping(QAbstractItemModel *model, QObject *parent)
+ : QObject(parent)
+ , mModel(model)
+{
+}
+
+Grouping::~Grouping()
+{
+}
+
+QAbstractItemModel *Grouping::model() const
+{
+ return mModel;
+}
+
+GroupingModel::Group::Group()
+{
+}
+
+int GroupingModel::Group::toSource(int index) const
+{
+ if (index >= 0 && index < m_sourceIndices.size()) {
+ return m_sourceIndices[index];
+ } else {
+ return -1;
+ }
+}
+
+int GroupingModel::Group::size() const
+{
+ return m_sourceIndices.size();
+}
+
+void GroupingModel::Group::clear()
+{
+ m_sourceIndices.clear();
+}
+
+void GroupingModel::Group::addIndex(int index)
+{
+ m_sourceIndices << index;
+}
+
+GroupingModel::GroupingModel(QAbstractItemModel *source, Grouping *grouping, QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_source(source)
+ , m_grouping(grouping)
+{
+ regroup();
+
+ connect(m_source, SIGNAL(rowsInserted(QModelIndex, int, int)),
+ this, SLOT(onSourceRowsInserted(QModelIndex, int, int)));
+ connect(m_source, SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(onSourceRowsRemoved(QModelIndex, int, int)));
+
+ connect(m_grouping->model(), SIGNAL(rowsInserted(QModelIndex, int, int)),
+ this, SLOT(onBaseRowsInserted(QModelIndex, int, int)));
+ connect(m_grouping->model(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
+ this, SLOT(onBaseRowsRemoved(QModelIndex, int, int)));
+
+ connect(m_grouping, SIGNAL(groupsChanged()),
+ this, SLOT(onGroupsChanged()));
+}
+
+GroupingModel::~GroupingModel()
+{
+ qDeleteAll(m_groups);
+}
+
+void GroupingModel::regroup()
+{
+ // clear groups
+ qDeleteAll(m_groups);
+ m_groups.clear();
+ const int numGroups = m_grouping->model()->rowCount(QModelIndex());
+ for (int i = 0; i < numGroups; i++) {
+ m_groups << new Group;
+ }
+ m_ungrouped.clear();
+
+ // populate groups
+ const int numItems = m_source->rowCount(QModelIndex());
+ for (int i = 0; i < numItems; i++) {
+ foreach (IndexedGroup group, groupsOf(i)) {
+ group.first->addIndex(i);
+ }
+ }
+}
+
+QModelIndex GroupingModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!parent.isValid()) {
+ return createIndex(row, column, -1);
+ } else {
+ return createIndex(row, column, parent.row());
+ }
+}
+
+QModelIndex GroupingModel::parent(const QModelIndex &index) const
+{
+ int groupId = groupIdFromIndex(index);
+ if (groupId != -1) {
+ return createIndex(groupId, 0, -1);
+ }
+ else {
+ return QModelIndex();
+ }
+}
+
+QVariant GroupingModel::data(const QModelIndex &index, int role) const
+{
+
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ int groupId = groupIdFromIndex(index);
+ if (groupId != -1) {
+ const Group *group = getGroup(groupId);
+ QModelIndex sourceIndex = m_source->index(group->toSource(index.row()), 0);
+ return sourceIndex.data(role);
+ } else if (index.row() < m_groups.size()) {
+ QModelIndex baseIndex = m_grouping->model()->index(index.row(), 0);
+ return baseIndex.data(role);
+ } else {
+ return m_grouping->ungrouped(role);
+ }
+}
+
+int GroupingModel::columnCount(const QModelIndex &index) const
+{
+ Q_UNUSED(index);
+ return 1;
+}
+
+int GroupingModel::rowCount(const QModelIndex &index) const
+{
+ if (index.isValid()) {
+ int groupId = groupIdFromIndex(index);
+ if (groupId == -1) {
+ const Group *group = getGroup(index.row());
+ return group->size();
+ } else {
+ return 0;
+ }
+ } else {
+ int count = m_groups.size();
+ if (m_ungrouped.size() > 0) {
+ count++;
+ }
+
+ return count;
+ }
+}
+
+void GroupingModel::onSourceRowsInserted(const QModelIndex &, int start, int end)
+{
+ beginResetModel();
+ regroup();
+ endResetModel();
+
+// typedef QList<int>::const_iterator Iterator;
+// for (int i = start; i <= end; i++) {
+// kDebug() << "item" << i;
+// foreach (IndexedGroup group, groupsOf(i)) {
+// const QModelIndex parent = index(group.second, 0, QModelIndex());
+//
+// Iterator it = qLowerBound(group.first->sourceIndices(), i);
+// int insertionIndex = it - group.first->sourceIndices().begin();
+// beginInsertRows(parent, insertionIndex, insertionIndex);
+// group.first->sourceIndices().insert(insertionIndex, i);
+// endInsertRows();
+// }
+// }
+}
+
+void GroupingModel::onSourceRowsRemoved(const QModelIndex &, int start, int end)
+{
+ beginResetModel();
+ regroup();
+ endResetModel();
+// typedef QList<int>::const_iterator Iterator;
+//
+// // we assume that an item is removed before the grouping is updated
+// for (int i = start; i <= end; i++) {
+// foreach (IndexedGroup group, groupsOf(i)) {
+// const QModelIndex parent = index(group.second, 0, QModelIndex());
+//
+// Iterator it = qBinaryFind(group.first->sourceIndices(), i);
+// Q_ASSERT(it != group->sourceIndices().end());
+//
+// int relativeIndex = it - group.first->sourceIndices().begin();
+//
+// beginRemoveRows(parent, relativeIndex, relativeIndex);
+// group.first->sourceIndices().removeAt(relativeIndex);
+// endInsertRows();
+// }
+// }
+}
+
+QList<GroupingModel::IndexedGroup> GroupingModel::groupsOf(int i)
+{
+ QList<int> groupIds = m_grouping->groupsOf(m_source->index(i, 0));
+ if (groupIds.isEmpty()) {
+ return QList<IndexedGroup>() << qMakePair(&m_ungrouped, m_groups.size());
+ } else {
+ QList<IndexedGroup> result;
+ foreach (int groupId, groupIds) {
+ result << qMakePair(m_groups[groupId], groupId);
+ }
+ return result;
+ }
+}
+
+GroupingModel::Group *GroupingModel::getGroup(int groupId)
+{
+ if (groupId < m_groups.size()) {
+ return m_groups[groupId];
+ } else {
+ return &m_ungrouped;
+ }
+}
+
+const GroupingModel::Group *GroupingModel::getGroup(int groupId) const
+{
+ return const_cast<GroupingModel *>(this)->getGroup(groupId);
+}
+
+void GroupingModel::onBaseRowsInserted(const QModelIndex &, int start, int end)
+{
+ kDebug() << start << end;
+ beginResetModel();
+ regroup();
+ endResetModel();
+}
+
+void GroupingModel::onBaseRowsRemoved(const QModelIndex &, int start, int end)
+{
+ beginResetModel();
+ regroup();
+ endResetModel();
+}
+
+void GroupingModel::onGroupsChanged()
+{
+ beginResetModel();
+ regroup();
+ endResetModel();
+}
+
+int GroupingModel::groupIdFromIndex(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return -1;
+ }
+ quint64 id = index.internalId();
+ return static_cast<int>(id);
+}
diff --git a/models/grouping-model.h b/models/grouping-model.h
new file mode 100644
index 0000000..22cd204
--- /dev/null
+++ b/models/grouping-model.h
@@ -0,0 +1,126 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 GROUPING_MODEL_H
+#define GROUPING_MODEL_H
+
+#include <QAbstractItemModel>
+
+class Grouping : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit Grouping(QAbstractItemModel *model, QObject *parent = 0);
+
+ virtual ~Grouping();
+ virtual QList<int> groupsOf(const QModelIndex &index) const = 0;
+ virtual QVariant ungrouped(int role) const = 0;
+
+ QAbstractItemModel *model() const;
+
+Q_SIGNALS:
+
+ void groupsChanged();
+
+private:
+ QAbstractItemModel *mModel;
+};
+
+
+/**
+ * GroupingModel is a proxy model which turns a flat model into a 2-level
+ * nested model.
+ *
+ * GroupingModel needs a *source* model and a *base* model. Both have to be
+ * flat (i.e. non-hierarchical) models. The items of the base model will turn
+ * into the first-level items of the grouped model, while those of the source
+ * model become second-level items.
+ *
+ * To perform the grouping, GroupingModel uses an instance of the abstract
+ * class Grouping, encapsulating the grouping logic through the groupsOf
+ * function, which takes an index in the source model and returns a list of
+ * groups it belongs to.
+ *
+ * Changes to the source and base model are handled automatically by
+ * GroupingModel, but changes to the grouping itself need to be signalled by
+ * the Grouping object by emitting the groupsChanged signal.
+ **/
+class GroupingModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+ class Group
+ {
+ public:
+ Group();
+
+ int toSource(int index) const;
+ int size() const;
+
+ void clear();
+ void addIndex(int index);
+
+ QList<int>& sourceIndices() { return m_sourceIndices; }
+
+ private:
+ QList<int> m_sourceIndices;
+ };
+
+ typedef QPair<Group *, int> IndexedGroup;
+
+public:
+
+ GroupingModel(QAbstractItemModel *source, Grouping *grouping, QObject *parent = 0);
+ ~GroupingModel();
+
+ virtual int rowCount(const QModelIndex &index) const;
+ virtual int columnCount(const QModelIndex &index) const;
+
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ virtual QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const;
+
+ virtual QModelIndex parent(const QModelIndex &index) const;
+
+private Q_SLOTS:
+
+ void onSourceRowsInserted(const QModelIndex &index, int start, int end);
+ void onSourceRowsRemoved(const QModelIndex &index, int start, int end);
+ void onBaseRowsInserted(const QModelIndex &index, int start, int end);
+ void onBaseRowsRemoved(const QModelIndex &index, int start, int end);
+ void onGroupsChanged();
+
+private:
+
+ void regroup();
+ int groupIdFromIndex(const QModelIndex &index) const;
+ QList<IndexedGroup> groupsOf(int i);
+ const Group *getGroup(int groupId) const;
+ Group *getGroup(int groupId);
+
+ QList<Group *> m_groups;
+ Group m_ungrouped;
+ QAbstractItemModel *m_source;
+ Grouping *m_grouping;
+};
+
+#endif // GROUPING_MODEL_H
diff --git a/telepathy-utils.cpp b/telepathy-utils.cpp
new file mode 100644
index 0000000..a3789d3
--- /dev/null
+++ b/telepathy-utils.cpp
@@ -0,0 +1,57 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info@collabora.co.uk>
+ * @Author George Goldberg <george.goldberg@collabora.co.uk>
+ * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
+ * Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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 "telepathy-utils.h"
+
+Tp::AccountManagerPtr TelepathyUtils::createAccountManager()
+{
+ Tp::AccountFactoryPtr accountFactory(Tp::AccountFactory::create(
+ QDBusConnection::sessionBus(), Tp::Features()
+ << Tp::Account::FeatureCore
+ << Tp::Account::FeatureAvatar
+ << Tp::Account::FeatureCapabilities
+ << Tp::Account::FeatureProtocolInfo
+ << Tp::Account::FeatureProfile));
+
+ Tp::ConnectionFactoryPtr connectionFactory(Tp::ConnectionFactory::create(
+ QDBusConnection::sessionBus(), Tp::Features()
+ << Tp::Connection::FeatureCore
+ << Tp::Connection::FeatureRosterGroups
+ << Tp::Connection::FeatureRoster
+ << Tp::Connection::FeatureSelfContact
+ << Tp::Connection::FeatureConnected));
+
+ Tp::ChannelFactoryPtr channelFactory(Tp::ChannelFactory::create(
+ QDBusConnection::sessionBus()));
+
+ Tp::ContactFactoryPtr contactFactory(Tp::ContactFactory::create(
+ Tp::Features()
+ << Tp::Contact::FeatureAlias
+ << Tp::Contact::FeatureAvatarData
+ << Tp::Contact::FeatureSimplePresence
+ << Tp::Contact::FeatureCapabilities));
+
+ return Tp::AccountManagerPtr(Tp::AccountManager::create(
+ accountFactory, connectionFactory, channelFactory, contactFactory));
+}
diff --git a/telepathy-utils.h b/telepathy-utils.h
new file mode 100644
index 0000000..583d9d5
--- /dev/null
+++ b/telepathy-utils.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of telepathy-contactslist-prototype
+ *
+ * Copyright (C) 2009-2010 Collabora Ltd. <info@collabora.co.uk>
+ * @Author George Goldberg <george.goldberg@collabora.co.uk>
+ * Copyright (C) 2011 Martin Klapetek <martin.klapetek@gmail.com>
+ * Copyright (C) 2011 Keith Rusler <xzekecomax@gmail.com>
+ * Copyright (C) 2011 Paolo Capriotti <p.capriotti@gmail.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/AccountManager>
+
+class TelepathyUtils
+{
+public:
+ static Tp::AccountManagerPtr createAccountManager();
+};