Commit ef82b39a authored by Emmanuel Lepage Vallee's avatar Emmanuel Lepage Vallee
Browse files

[ #13690 ] Add new IM widget

parent 8c4a246c
......@@ -189,7 +189,7 @@ on_focus_out(GtkEntry *entry UNUSED, gpointer user_data UNUSED)
}
static void
on_clicked(GtkTextBuffer *textbuffer UNUSED, GtkTextIter *location UNUSED, GtkTextMark *mark UNUSED, gpointer user_data UNUSED)
on_clicked(GtkTextBuffer *textbuffer, GtkTextIter *location UNUSED, GtkTextMark *mark UNUSED, gpointer user_data UNUSED)
{
if (start_link && end_link && gtk_text_iter_compare(start_link,location) <= 0 && gtk_text_iter_compare(location,end_link) <= 0) {
gchar* text = gtk_text_buffer_get_text(textbuffer,start_link,end_link,FALSE);
......@@ -201,6 +201,9 @@ on_clicked(GtkTextBuffer *textbuffer UNUSED, GtkTextIter *location UNUSED, GtkTe
url_command = "xdg-open";
const gchar* argv[3] = {url_command,text,(char*)NULL};
g_spawn_async(NULL,(gchar**)argv,NULL,G_SPAWN_SEARCH_PATH|G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL,NULL,NULL,NULL,NULL);
gtk_text_buffer_remove_all_tags(textbuffer,start_link,end_link );
start_link = NULL;
end_link = NULL;
}
}
}
......
......@@ -55,6 +55,8 @@ SET(
widgets/CategorizedTreeWidget.cpp
widgets/VideoDock.cpp
widgets/VideoWidget.cpp
widgets/IMManager.cpp
widgets/IMTab.cpp
# widgets/AcceleratedVideoWidget.cpp
Codec.cpp
CallView.cpp
......
......@@ -46,6 +46,7 @@
#include "lib/configurationmanager_interface_singleton.h"
#include "lib/Contact.h"
#include "lib/AccountList.h"
#include "lib/InstantMessagingModel.h"
//SFLPhone
#include "klib/AkonadiBackend.h"
......@@ -357,6 +358,7 @@ TreeWidgetCallModel* SFLPhone::model()
m_pModel = new TreeWidgetCallModel();
m_pModel->initCall();
Call::setContactBackend(AkonadiBackend::getInstance());
InstantMessagingModelManager::init(m_pModel);
AccountList::getInstance()->setDefaultAccount(AccountList::getInstance()->getAccountById(ConfigurationSkeleton::defaultAccountId()));
#ifdef ENABLE_VIDEO
VideoModel::getInstance();
......
......@@ -53,6 +53,8 @@
#include "lib/Contact.h"
#include "klib/HelperFunctions.h"
#define IM_ACTIVE m_pMessageTabBox->isVisible()
//ConfigurationDialog* SFLPhoneView::configDialog;
class ColorVisitor : public AccountListColorVisitor {
......@@ -412,7 +414,7 @@ void SFLPhoneView::updateWindowCallState()
buttonIconFiles [ SFLPhone::Refuse ] = ICON_REFUSE ;
actionTexts [ SFLPhone::Accept ] = ACTION_LABEL_ACCEPT ;
actionTexts [ SFLPhone::Refuse ] = ACTION_LABEL_REFUSE ;
m_pMessageBoxW->setVisible(false) ;
m_pMessageBoxW->setVisible(false || IM_ACTIVE) ;
break;
case CALL_STATE_RINGING:
enabledActions [ SFLPhone::Hold ] = false ;
......@@ -421,7 +423,7 @@ void SFLPhoneView::updateWindowCallState()
break;
case CALL_STATE_CURRENT:
buttonIconFiles [ SFLPhone::Record ] = ICON_REC_DEL_ON ;
m_pMessageBoxW->setVisible(true && ConfigurationSkeleton::displayMessageBox());
m_pMessageBoxW->setVisible((true && ConfigurationSkeleton::displayMessageBox()) || IM_ACTIVE);
break;
case CALL_STATE_DIALING:
enabledActions [ SFLPhone::Hold ] = false ;
......@@ -434,7 +436,7 @@ void SFLPhoneView::updateWindowCallState()
case CALL_STATE_HOLD:
buttonIconFiles [ SFLPhone::Hold ] = ICON_UNHOLD ;
actionTexts [ SFLPhone::Hold ] = ACTION_LABEL_UNHOLD ;
m_pMessageBoxW->setVisible(true && ConfigurationSkeleton::displayMessageBox());
m_pMessageBoxW->setVisible(false) ;
break;
case CALL_STATE_FAILURE:
enabledActions [ SFLPhone::Accept ] = false ;
......@@ -454,7 +456,7 @@ void SFLPhoneView::updateWindowCallState()
buttonIconFiles [ SFLPhone::Accept ] = ICON_EXEC_TRANSF ;
actionTexts [ SFLPhone::Transfer ] = ACTION_LABEL_GIVE_UP_TRANSF ;
buttonIconFiles [ SFLPhone::Record ] = ICON_REC_DEL_ON ;
m_pMessageBoxW->setVisible(false) ;
m_pMessageBoxW->setVisible(false || IM_ACTIVE) ;
transfer = true;
break;
case CALL_STATE_TRANSF_HOLD:
......@@ -467,13 +469,15 @@ void SFLPhoneView::updateWindowCallState()
break;
case CALL_STATE_OVER:
kDebug() << "Error : Reached CALL_STATE_OVER with call " << call->getCallId() << "!";
m_pMessageBoxW->setVisible(false) ;
break;
case CALL_STATE_ERROR:
kDebug() << "Error : Reached CALL_STATE_ERROR with call " << call->getCallId() << "!";
m_pMessageBoxW->setVisible(false) ;
break;
case CALL_STATE_CONFERENCE:
enabledActions [ SFLPhone::Transfer ] = false ;
m_pMessageBoxW->setVisible(false) ;
m_pMessageBoxW->setVisible(false || IM_ACTIVE) ;
break;
case CALL_STATE_CONFERENCE_HOLD:
enabledActions [ SFLPhone::Transfer ] = false ;
......@@ -886,6 +890,7 @@ void SFLPhoneView::sendMessage()
if (dynamic_cast<Call*>(call) && !m_pSendMessageLE->text().isEmpty()) {
call->sendTextMessage(m_pSendMessageLE->text());
}
m_pSendMessageLE->clear();
}
#include "SFLPhoneView.moc"
\ No newline at end of file
......@@ -213,7 +213,6 @@ void DlgAccounts::saveAccount(QModelIndex item)
// /
if (m_pDefaultAccount->isChecked()) {
kDebug() << "\n\n\n\n\nIS CHECKED\n\n\n\n\n";
ConfigurationSkeleton::setDefaultAccountId(account->getAccountId());
AccountList::getInstance()->setDefaultAccount(account);
}
......
......@@ -29,6 +29,7 @@
#include "Account.h"
#include "AccountList.h"
#include "VideoModel.h"
#include "InstantMessagingModel.h"
const call_state Call::actionPerformedStateMap [13][5] =
......@@ -118,7 +119,7 @@ void Call::setContactBackend(ContactBackend* be)
///Constructor
Call::Call(call_state startState, QString callId, QString peerName, QString peerNumber, QString account)
: m_isConference(false),m_pStopTime(nullptr),m_pStartTime(nullptr),
m_ContactChanged(false),m_pContact(nullptr)
m_ContactChanged(false),m_pContact(nullptr),m_pImModel(nullptr)
{
this->m_CallId = callId ;
this->m_PeerPhoneNumber = peerNumber ;
......@@ -148,7 +149,8 @@ Call::~Call()
}
///Constructor
Call::Call(QString confId, QString account)
Call::Call(QString confId, QString account): m_isConference(false),m_pStopTime(nullptr),m_pStartTime(nullptr),
m_ContactChanged(false),m_pContact(nullptr),m_pImModel(nullptr)
{
m_isConference = m_ConfId.isEmpty();
this->m_ConfId = confId ;
......@@ -420,6 +422,19 @@ const QString& Call::getPeerName() const
return m_PeerName;
}
///Generate the best possible peer name
const QString Call::getFormattedName()
{
if (isConference())
return "Conference";
else if (m_pContact && !m_pContact->getFormattedName().isEmpty())
return m_pContact->getFormattedName();
else if (!getPeerName().isEmpty())
return m_PeerName;
else
return m_PeerPhoneNumber;
}
///Get the current state
call_state Call::getCurrentState() const
{
......@@ -629,7 +644,13 @@ void Call::changeCurrentState(call_state newState)
void Call::sendTextMessage(QString message)
{
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
Q_NOREPLY callManager.sendTextMessage(m_CallId,message);
Q_NOREPLY callManager.sendTextMessage(isConference()?m_ConfId:m_CallId,message);
qDebug() << "MODEL IS" << m_pImModel;
if (!m_pImModel) {
m_pImModel = InstantMessagingModelManager::getInstance()->getModel(this);
}
qDebug() << "MODEL IS2" << m_pImModel;
m_pImModel->addOutgoingMessage(message);
}
QDateTime* Call::setStartTime_private(QDateTime* time)
......
......@@ -36,6 +36,7 @@ class ContactBackend;
class Contact;
class Account;
class VideoRenderer;
class InstantMessagingModel;
/** @enum daemon_call_state_t
......@@ -159,6 +160,7 @@ public:
const QString toHumanStateName () const;
Contact* getContact () ;
VideoRenderer* getVideoRenderer () ;
const QString getFormattedName () ;
//Automated function
call_state stateChanged(const QString & newState);
......@@ -199,7 +201,8 @@ private:
bool m_Recording ;
static Call* m_sSelectedCall ;
bool m_ContactChanged ;
Contact* m_pContact;
Contact* m_pContact ;
InstantMessagingModel* m_pImModel ;
//State machine
/**
......
/************************************************************************************
* Copyright (C) 2009 by Savoir-Faire Linux *
* Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> *
* Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
* Copyright (C) 2012 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
......@@ -18,10 +17,47 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***********************************************************************************/
#include "InstantMessagingModel.h"
#include "CallModel.h"
#include "callmanager_interface_singleton.h"
#include "Call.h"
InstantMessagingModel::InstantMessagingModel(QObject* parent) : QAbstractListModel(parent)
InstantMessagingModelManager* InstantMessagingModelManager::m_spInstance = nullptr;
CallModelBase* InstantMessagingModelManager::m_spCallModel = nullptr;
void InstantMessagingModelManager::newMessage(QString callId, QString from, QString message)
{
if (!m_lModels[callId] && m_spCallModel) {
Call* call = m_spCallModel->getCall(callId);
if (call) {
qDebug() << "Creating messaging model for call" << callId;
m_lModels[callId] = new InstantMessagingModel(call);
emit newMessagingModel(call,m_lModels[callId]);
m_lModels[callId]->addIncommingMessage(from,message);
}
}
else if (m_lModels[callId]) {
m_lModels[callId]->addIncommingMessage(from,message);
}
}
InstantMessagingModelManager::InstantMessagingModelManager() : QObject(0)
{
CallManagerInterface& callManager = CallManagerInterfaceSingleton::getInstance();
connect(&callManager, SIGNAL(incomingMessage(const QString &, const QString &, const QString &)), this, SLOT(newMessage(const QString &, const QString &, const QString &)));
}
InstantMessagingModel* InstantMessagingModelManager::getModel(Call* call) {
QString key = call->isConference()?call->getConfId():call->getCallId();
if (!m_lModels[key]) {
m_lModels[key] = new InstantMessagingModel(call);
emit newMessagingModel(call,m_lModels[key]);
}
return m_lModels[key];
}
InstantMessagingModel::InstantMessagingModel(Call* call, QObject* parent) : QAbstractListModel(parent),m_pCall(call)
{
//QStringList callList = callManager.getCallList();
}
QVariant InstantMessagingModel::data( const QModelIndex& index, int role) const
......@@ -34,8 +70,17 @@ QVariant InstantMessagingModel::data( const QModelIndex& index, int role) const
return QVariant(m_lMessages[index.row()].from);
else if (index.column() == 0 && role == MESSAGE_TEXT_ROLE )
return INCOMMING_IM;
else if (index.column() == 0 && role == MESSAGE_CONTACT_ROLE )
else if (index.column() == 0 && role == MESSAGE_CONTACT_ROLE && m_pCall->getContact())
return QVariant();
else if (index.column() == 0 && role == MESSAGE_IMAGE_ROLE ) {
if (m_lImages.find(index) != m_lImages.end())
return m_lImages[index];
Contact* c =m_pCall->getContact();
if (c && c->getPhoto()) {
return QVariant::fromValue<void*>((void*)c->getPhoto());
}
return QVariant();
}
return QVariant();
}
......@@ -56,5 +101,26 @@ bool InstantMessagingModel::setData(const QModelIndex& index, const QVariant &va
Q_UNUSED(index)
Q_UNUSED(value)
Q_UNUSED(role)
if (index.column() == 0 && role == MESSAGE_IMAGE_ROLE ) {
m_lImages[index] = value;
}
return false;
}
void InstantMessagingModel::addIncommingMessage(QString from, QString message)
{
InternalIM im;
im.from = from;
im.message = message;
m_lMessages << im;
emit dataChanged(index(m_lMessages.size() -1,0), index(m_lMessages.size()-1,0));
}
void InstantMessagingModel::addOutgoingMessage(QString message)
{
InternalIM im;
im.from = "Me";
im.message = message;
m_lMessages << im;
emit dataChanged(index(m_lMessages.size() -1,0), index(m_lMessages.size()-1,0));
}
\ No newline at end of file
......@@ -23,6 +23,8 @@
#include <QtCore/QAbstractListModel>
#include <QtCore/QModelIndex>
#include "typedefs.h"
#include <QtCore/QDebug>
enum MessageRole {
INCOMMING_IM,
......@@ -30,27 +32,67 @@ enum MessageRole {
MIME_TRANSFER,
};
class InstantMessagingModel : public QAbstractListModel
class Call;
class CallModelBase;
class InstantMessagingModel;
class LIB_EXPORT InstantMessagingModelManager : public QObject
{
Q_OBJECT
public:
static InstantMessagingModelManager* getInstance() {
if (!m_spInstance) {
m_spInstance = new InstantMessagingModelManager();
}
return m_spInstance;
}
static void init(CallModelBase* model) {
m_spCallModel = model;
getInstance();
}
InstantMessagingModel* getModel(Call* call);
private:
InstantMessagingModelManager();
static InstantMessagingModelManager* m_spInstance;
static CallModelBase* m_spCallModel;
QHash<QString,InstantMessagingModel*> m_lModels;
private slots:
void newMessage(QString callId, QString from, QString message);
signals:
void newMessagingModel(Call*,InstantMessagingModel*);
};
class LIB_EXPORT InstantMessagingModel : public QAbstractListModel
{
Q_OBJECT
friend class InstantMessagingModelManager;
friend class Call;
public:
static const int MESSAGE_TYPE_ROLE = 100;
static const int MESSAGE_FROM_ROLE = 101;
static const int MESSAGE_TEXT_ROLE = 102;
static const int MESSAGE_CONTACT_ROLE = 103;
static const int MESSAGE_IMAGE_ROLE = 103;
static const int MESSAGE_CONTACT_ROLE = 104;
InstantMessagingModel(QObject* parent);
InstantMessagingModel(Call* call, QObject* parent = nullptr);
QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const;
int rowCount ( const QModelIndex& parent = QModelIndex() ) const;
Qt::ItemFlags flags ( const QModelIndex& index ) const;
virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) ;
private:
void addIncommingMessage(QString from, QString message);
void addOutgoingMessage(QString message);
struct InternalIM {
QString from;
QString message;
};
QList<InternalIM> m_lMessages;
QHash<QModelIndex,QVariant> m_lImages;
Call* m_pCall;
};
#endif
\ No newline at end of file
......@@ -15,13 +15,23 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="CallView" name="callView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="CallView" name="callView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>3</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="IMManager" name="m_pMessageTabBox">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</widget>
</item>
<item>
......@@ -199,6 +209,12 @@
<header location="global">CallView.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>IMManager</class>
<extends>QTabWidget</extends>
<header>widgets/IMManager.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../qrc/resources.qrc"/>
......
/***************************************************************************
* Copyright (C) 2012 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
**************************************************************************/
#include "IMManager.h"
#include "../lib/InstantMessagingModel.h"
#include "../lib/Call.h"
#include "IMTab.h"
#include <KDebug>
#include <KLocale>
IMManager::IMManager(QWidget* parent) : QTabWidget(parent)
{
setVisible(false);
setTabsClosable(true);
connect(InstantMessagingModelManager::getInstance(),SIGNAL(newMessagingModel(Call*,InstantMessagingModel*)),this,SLOT(newConversation(Call*,InstantMessagingModel*)));
connect(this,SIGNAL(tabCloseRequested(int)),this,SLOT(closeRequest(int)));
}
void IMManager::newConversation(Call* call, InstantMessagingModel* model)
{
IMTab* newTab = new IMTab(model,this);
m_lTabs[call] = newTab;
setVisible(true);
QString name = call->getFormattedName();
addTab(newTab,name);
}
void IMManager::closeRequest(int index)
{
QWidget* wdg = widget(index);
Call* call = m_lTabs.key(qobject_cast<IMTab*>(wdg));
if (call) {
m_lTabs[call] = nullptr;
delete wdg;
if (!count())
setVisible(false);
}
}
\ No newline at end of file
/***************************************************************************
* Copyright (C) 2012 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
**************************************************************************/
#ifndef IM_MANAGER_H
#define IM_MANAGER_H
#include <QtCore/QHash>
#include <QtGui/QTabWidget>
//SFLPhone
class IMTab;
class InstantMessagingModel;
class Call;
class IMManager : public QTabWidget
{
Q_OBJECT
public:
IMManager(QWidget* parent = nullptr);
private:
QHash<Call*,IMTab*> m_lTabs;
private slots:
void newConversation(Call* call, InstantMessagingModel* model);
void closeRequest(int index);
};
#endif // IM_MANAGER
\ No newline at end of file
/***************************************************************************
* Copyright (C) 2012 by Savoir-Faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
**************************************************************************/
#include "IMTab.h"
#include "../lib/InstantMessagingModel.h"
#include "../lib/Call.h"
#include <QtGui/QPainter>
#include <KDebug>
#include <KIcon>
#include <QtGui/QFont>
ImDelegates::ImDelegates(IMTab* parent) : QStyledItemDelegate(parent),m_pParent(parent)
{
}
QSize ImDelegates::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const {
// QSize orig = QStyledItemDelegate::sizeHint(option,index);
int height = 0;
QPixmap* icon = (QPixmap*)index.data(InstantMessagingModel::MESSAGE_IMAGE_ROLE).value<void*>();
QFontMetrics metric( option.font);
QRect requiredRect = metric.boundingRect(0,0,m_pParent->width()-30 - 48 - 10 /*margin*/,500,Qt::TextWordWrap|Qt::AlignLeft,index.data(InstantMessagingModel::MESSAGE_TYPE_ROLE).toString());
height+=requiredRect.height();
height+=metric.height()+10;
if (icon && dynamic_cast<QPixmap*>(icon) && height < icon->height()) {
height = icon->height();
}
return QSize(m_pParent->width()-30,height);
}
void ImDelegates::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
Q_ASSERT(index.isValid());
// const QRegion cl = painter->clipRegion();
// painter->setClipRect(option.rect);
QPixmap* icon = (QPixmap*)index.data(InstantMessagingModel::MESSAGE_IMAGE_ROLE).value<void*>();
int icnWidth = 50;
if (icon && dynamic_cast<QPixmap*>(icon)) {
painter->drawPixmap(option.rect.x()+5,option.rect.y()+(option.rect.height()/2)-(icon->height()/2),*icon);
icnWidth = icon->width();
}
else {
((QAbstractListModel*) index.model())->setData(index,QPixmap(KIcon("user-identity").pixmap(QSize(48,48))),InstantMessagingModel::MESSAGE_IMAGE_ROLE);
}
QFontMetrics metric(painter->font());
QString text = index.data(InstantMessagingModel::MESSAGE_TYPE_ROLE).toString();
QRect requiredRect = metric.boundingRect(option.rect.x()+icnWidth+10,option.rect.y()+metric.height()+5,option.rect.width() - icnWidth - 10 /*margin*/,500,Qt::TextWordWrap|Qt::AlignLeft,text);
painter->drawText(requiredRect,Qt::AlignLeft|Qt::TextWordWrap,text);