2019-09-01 19:46:12 +00:00
/*
* Squawk messenger .
* Copyright ( C ) 2019 Yury Gubich < blue @ macaw . me >
*
* 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 , see < http : //www.gnu.org/licenses/>.
*/
2019-03-31 21:05:09 +00:00
# include "roster.h"
2019-04-03 21:23:51 +00:00
# include <QDebug>
2019-04-02 21:58:43 +00:00
# include <QIcon>
2019-04-05 15:12:59 +00:00
# include <QFont>
2019-03-31 21:05:09 +00:00
Models : : Roster : : Roster ( QObject * parent ) :
QAbstractItemModel ( parent ) ,
2019-04-03 18:15:36 +00:00
accountsModel ( new Accounts ( ) ) ,
root ( new Item ( Item : : root , { { " name " , " root " } } ) ) ,
accounts ( ) ,
2019-04-03 21:23:51 +00:00
groups ( ) ,
2019-04-05 15:12:59 +00:00
contacts ( )
2019-03-31 21:05:09 +00:00
{
2019-10-23 14:49:56 +00:00
connect ( accountsModel , & Accounts : : dataChanged , this , & Roster : : onAccountDataChanged ) ;
connect ( root , & Item : : childChanged , this , & Roster : : onChildChanged ) ;
connect ( root , & Item : : childIsAboutToBeInserted , this , & Roster : : onChildIsAboutToBeInserted ) ;
connect ( root , & Item : : childInserted , this , & Roster : : onChildInserted ) ;
connect ( root , & Item : : childIsAboutToBeRemoved , this , & Roster : : onChildIsAboutToBeRemoved ) ;
connect ( root , & Item : : childRemoved , this , & Roster : : onChildRemoved ) ;
connect ( root , & Item : : childIsAboutToBeMoved , this , & Roster : : onChildIsAboutToBeMoved ) ;
connect ( root , & Item : : childMoved , this , & Roster : : onChildMoved ) ;
2019-03-31 21:05:09 +00:00
}
Models : : Roster : : ~ Roster ( )
{
2019-04-03 18:15:36 +00:00
delete accountsModel ;
2019-03-31 21:05:09 +00:00
delete root ;
}
void Models : : Roster : : addAccount ( const QMap < QString , QVariant > & data )
{
2019-04-07 14:02:41 +00:00
Account * acc = new Account ( data ) ;
2019-03-31 21:05:09 +00:00
root - > appendChild ( acc ) ;
2019-04-03 15:09:29 +00:00
accounts . insert ( std : : make_pair ( acc - > getName ( ) , acc ) ) ;
2019-04-03 18:15:36 +00:00
accountsModel - > addAccount ( acc ) ;
2019-03-31 21:05:09 +00:00
}
QVariant Models : : Roster : : data ( const QModelIndex & index , int role ) const
{
if ( ! index . isValid ( ) ) {
return QVariant ( ) ;
}
QVariant result ;
2019-04-02 21:58:43 +00:00
Item * item = static_cast < Item * > ( index . internalPointer ( ) ) ;
2019-03-31 21:05:09 +00:00
switch ( role ) {
case Qt : : DisplayRole :
{
2019-10-16 19:38:35 +00:00
if ( index . column ( ) ! = 0 ) {
2019-12-30 20:22:04 +00:00
result = " " ;
2019-10-16 19:38:35 +00:00
break ;
}
2019-06-22 20:37:22 +00:00
switch ( item - > type ) {
case Item : : group : {
Group * gr = static_cast < Group * > ( item ) ;
QString str ( " " ) ;
str + = gr - > getName ( ) ;
unsigned int amount = gr - > getUnreadMessages ( ) ;
if ( amount > 0 ) {
2019-10-05 11:27:39 +00:00
str + = QString ( " ( " ) + tr ( " New messages " ) + " ) " ;
2019-06-22 20:37:22 +00:00
}
result = str ;
}
break ;
default :
result = item - > data ( index . column ( ) ) ;
break ;
}
2019-03-31 21:05:09 +00:00
}
break ;
2019-04-02 21:58:43 +00:00
case Qt : : DecorationRole :
switch ( item - > type ) {
2019-07-11 08:51:52 +00:00
case Item : : account : {
2019-10-16 19:38:35 +00:00
quint8 col = index . column ( ) ;
2019-04-03 18:15:36 +00:00
Account * acc = static_cast < Account * > ( item ) ;
2019-10-16 19:38:35 +00:00
if ( col = = 0 ) {
result = acc - > getStatusIcon ( false ) ;
} else if ( col = = 1 ) {
QString path = acc - > getAvatarPath ( ) ;
2019-10-24 09:42:38 +00:00
2019-10-16 19:38:35 +00:00
if ( path . size ( ) > 0 ) {
result = QIcon ( path ) ;
}
}
2019-04-02 21:58:43 +00:00
}
break ;
2019-07-11 08:51:52 +00:00
case Item : : contact : {
2019-04-05 15:12:59 +00:00
Contact * contact = static_cast < Contact * > ( item ) ;
2019-10-16 19:38:35 +00:00
quint8 col = index . column ( ) ;
if ( col = = 0 ) {
result = contact - > getStatusIcon ( false ) ;
} else if ( col = = 1 ) {
if ( contact - > getAvatarState ( ) ! = Shared : : Avatar : : empty ) {
result = QIcon ( contact - > getAvatarPath ( ) ) ;
}
}
2019-04-07 14:02:41 +00:00
}
break ;
2019-07-11 08:51:52 +00:00
case Item : : presence : {
2019-10-16 19:38:35 +00:00
if ( index . column ( ) ! = 0 ) {
break ;
}
2019-04-07 14:02:41 +00:00
Presence * presence = static_cast < Presence * > ( item ) ;
2019-06-23 21:09:39 +00:00
result = presence - > getStatusIcon ( false ) ;
2019-04-05 15:12:59 +00:00
}
break ;
2019-07-11 08:51:52 +00:00
case Item : : room : {
2019-12-17 16:54:53 +00:00
quint8 col = index . column ( ) ;
2019-07-11 08:51:52 +00:00
Room * room = static_cast < Room * > ( item ) ;
2019-12-17 16:54:53 +00:00
if ( col = = 0 ) {
result = room - > getStatusIcon ( false ) ;
} else if ( col = = 1 ) {
QString path = room - > getAvatarPath ( ) ;
if ( path . size ( ) > 0 ) {
result = QIcon ( path ) ;
}
}
2019-07-11 08:51:52 +00:00
}
break ;
2019-09-03 20:28:58 +00:00
case Item : : participant : {
2019-12-30 20:22:04 +00:00
quint8 col = index . column ( ) ;
Participant * p = static_cast < Participant * > ( item ) ;
if ( col = = 0 ) {
result = p - > getStatusIcon ( false ) ;
} else if ( col = = 1 ) {
QString path = p - > getAvatarPath ( ) ;
if ( path . size ( ) > 0 ) {
result = QIcon ( path ) ;
}
}
2019-10-16 19:38:35 +00:00
if ( index . column ( ) ! = 0 ) {
break ;
}
2019-12-30 20:22:04 +00:00
2019-09-03 20:28:58 +00:00
}
break ;
2019-04-02 21:58:43 +00:00
default :
break ;
}
break ;
2019-04-05 15:12:59 +00:00
case Qt : : FontRole :
switch ( item - > type ) {
case Item : : account : {
QFont font ;
font . setBold ( true ) ;
result = font ;
}
break ;
case Item : : group : {
QFont font ;
font . setItalic ( true ) ;
result = font ;
}
break ;
default :
break ;
}
2019-06-21 19:33:38 +00:00
break ;
case Qt : : ToolTipRole :
switch ( item - > type ) {
case Item : : account : {
Account * acc = static_cast < Account * > ( item ) ;
2019-10-05 11:27:39 +00:00
result = QCoreApplication : : translate ( " Global " , Shared : : availabilityNames [ acc - > getAvailability ( ) ] . toLatin1 ( ) ) ;
2019-06-21 19:33:38 +00:00
}
break ;
case Item : : contact : {
Contact * contact = static_cast < Contact * > ( item ) ;
2019-06-22 20:37:22 +00:00
QString str ( " " ) ;
2019-06-21 19:33:38 +00:00
int mc = contact - > getMessagesCount ( ) ;
if ( mc > 0 ) {
2019-10-05 11:27:39 +00:00
str + = QString ( tr ( " New messages: " ) ) + std : : to_string ( mc ) . c_str ( ) + " \n " ;
2019-06-21 19:33:38 +00:00
}
2019-10-05 11:27:39 +00:00
str + = tr ( " Jabber ID: " ) + contact - > getJid ( ) + " \n " ;
2019-06-21 19:33:38 +00:00
Shared : : SubscriptionState ss = contact - > getState ( ) ;
2019-12-17 16:54:53 +00:00
if ( ss = = Shared : : both | | ss = = Shared : : to ) {
2019-06-21 19:33:38 +00:00
Shared : : Availability av = contact - > getAvailability ( ) ;
2019-10-05 11:27:39 +00:00
str + = tr ( " Availability: " ) + QCoreApplication : : translate ( " Global " , Shared : : availabilityNames [ av ] . toLatin1 ( ) ) ;
2019-06-21 19:33:38 +00:00
if ( av ! = Shared : : offline ) {
QString s = contact - > getStatus ( ) ;
if ( s . size ( ) > 0 ) {
2019-10-05 11:27:39 +00:00
str + = " \n " + tr ( " Status: " ) + s ;
2019-06-21 19:33:38 +00:00
}
}
2019-10-05 11:27:39 +00:00
str + = " \n " + tr ( " Subscription: " ) + QCoreApplication : : translate ( " Global " , Shared : : subscriptionStateNames [ ss ] . toLatin1 ( ) ) ;
2019-06-21 19:33:38 +00:00
} else {
2019-10-05 11:27:39 +00:00
str + = tr ( " Subscription: " ) + QCoreApplication : : translate ( " Global " , Shared : : subscriptionStateNames [ ss ] . toLatin1 ( ) ) ;
2019-06-21 19:33:38 +00:00
}
result = str ;
}
break ;
case Item : : presence : {
Presence * contact = static_cast < Presence * > ( item ) ;
2019-06-22 20:37:22 +00:00
QString str ( " " ) ;
2019-06-21 19:33:38 +00:00
int mc = contact - > getMessagesCount ( ) ;
if ( mc > 0 ) {
2019-10-05 11:27:39 +00:00
str + = tr ( " New messages: " ) + std : : to_string ( mc ) . c_str ( ) + " \n " ;
2019-06-21 19:33:38 +00:00
}
Shared : : Availability av = contact - > getAvailability ( ) ;
2019-10-05 11:27:39 +00:00
str + = tr ( " Availability: " ) + QCoreApplication : : translate ( " Global " , Shared : : availabilityNames [ av ] . toLatin1 ( ) ) ;
2019-06-21 19:33:38 +00:00
QString s = contact - > getStatus ( ) ;
if ( s . size ( ) > 0 ) {
2019-10-05 11:27:39 +00:00
str + = " \n " + tr ( " Status: " ) + s ;
2019-06-21 19:33:38 +00:00
}
2019-09-03 20:28:58 +00:00
result = str ;
}
break ;
case Item : : participant : {
Participant * p = static_cast < Participant * > ( item ) ;
QString str ( " " ) ;
Shared : : Availability av = p - > getAvailability ( ) ;
2019-10-05 11:27:39 +00:00
str + = tr ( " Availability: " ) + QCoreApplication : : translate ( " Global " , Shared : : availabilityNames [ av ] . toLatin1 ( ) ) + " \n " ;
2019-09-03 20:28:58 +00:00
QString s = p - > getStatus ( ) ;
if ( s . size ( ) > 0 ) {
2019-10-05 11:27:39 +00:00
str + = tr ( " Status: " ) + s + " \n " ;
2019-09-03 20:28:58 +00:00
}
2019-10-05 11:27:39 +00:00
str + = tr ( " Affiliation: " ) +
QCoreApplication : : translate ( " Global " ,
Shared : : affiliationNames [ static_cast < unsigned int > ( p - > getAffiliation ( ) ) ] . toLatin1 ( ) ) + " \n " ;
str + = tr ( " Role: " ) +
QCoreApplication : : translate ( " Global " ,
Shared : : roleNames [ static_cast < unsigned int > ( p - > getRole ( ) ) ] . toLatin1 ( ) ) ;
2019-09-03 20:28:58 +00:00
2019-06-22 20:37:22 +00:00
result = str ;
}
break ;
case Item : : group : {
Group * gr = static_cast < Group * > ( item ) ;
unsigned int count = gr - > getUnreadMessages ( ) ;
QString str ( " " ) ;
if ( count > 0 ) {
2019-10-05 11:27:39 +00:00
str + = tr ( " New messages: " ) + std : : to_string ( count ) . c_str ( ) + " \n " ;
2019-06-22 20:37:22 +00:00
}
2019-10-05 11:27:39 +00:00
str + = tr ( " Online contacts: " ) + std : : to_string ( gr - > getOnlineContacts ( ) ) . c_str ( ) + " \n " ;
str + = tr ( " Total contacts: " ) + std : : to_string ( gr - > childCount ( ) ) . c_str ( ) ;
2019-06-21 19:33:38 +00:00
result = str ;
}
break ;
2019-07-11 08:51:52 +00:00
case Item : : room : {
Room * rm = static_cast < Room * > ( item ) ;
unsigned int count = rm - > getUnreadMessagesCount ( ) ;
QString str ( " " ) ;
if ( count > 0 ) {
2019-10-05 11:27:39 +00:00
str + = tr ( " New messages: " ) + std : : to_string ( count ) . c_str ( ) + " \n " ;
2019-07-11 08:51:52 +00:00
}
2019-12-17 16:54:53 +00:00
str + = tr ( " Jabber ID: " ) + rm - > getJid ( ) + " \n " ;
2019-10-05 11:27:39 +00:00
str + = tr ( " Subscription: " ) + rm - > getStatusText ( ) ;
2019-09-03 20:28:58 +00:00
if ( rm - > getJoined ( ) ) {
2019-10-05 11:27:39 +00:00
str + = QString ( " \n " ) + tr ( " Members: " ) + std : : to_string ( rm - > childCount ( ) ) . c_str ( ) ;
2019-09-03 20:28:58 +00:00
}
2019-07-11 08:51:52 +00:00
result = str ;
}
break ;
2019-06-21 19:33:38 +00:00
default :
result = " " ;
break ;
}
break ;
2019-03-31 21:05:09 +00:00
default :
break ;
}
return result ;
}
int Models : : Roster : : columnCount ( const QModelIndex & parent ) const
{
if ( parent . isValid ( ) ) {
return static_cast < Item * > ( parent . internalPointer ( ) ) - > columnCount ( ) ;
} else {
return root - > columnCount ( ) ;
}
}
2019-04-02 21:58:43 +00:00
void Models : : Roster : : updateAccount ( const QString & account , const QString & field , const QVariant & value )
{
std : : map < QString , Account * > : : iterator itr = accounts . find ( account ) ;
if ( itr ! = accounts . end ( ) ) {
Account * acc = itr - > second ;
2019-04-03 18:15:36 +00:00
acc - > update ( field , value ) ;
2019-04-02 21:58:43 +00:00
}
}
2019-03-31 21:05:09 +00:00
Qt : : ItemFlags Models : : Roster : : flags ( const QModelIndex & index ) const
{
if ( ! index . isValid ( ) ) {
return 0 ;
}
return QAbstractItemModel : : flags ( index ) ;
}
int Models : : Roster : : rowCount ( const QModelIndex & parent ) const
{
Item * parentItem ;
if ( ! parent . isValid ( ) ) {
parentItem = root ;
} else {
parentItem = static_cast < Item * > ( parent . internalPointer ( ) ) ;
}
return parentItem - > childCount ( ) ;
}
QVariant Models : : Roster : : headerData ( int section , Qt : : Orientation orientation , int role ) const
{
return QVariant ( ) ;
}
QModelIndex Models : : Roster : : parent ( const QModelIndex & child ) const
{
if ( ! child . isValid ( ) ) {
return QModelIndex ( ) ;
}
Item * childItem = static_cast < Item * > ( child . internalPointer ( ) ) ;
2019-04-02 21:58:43 +00:00
if ( childItem = = root ) {
return QModelIndex ( ) ;
}
2019-03-31 21:05:09 +00:00
Item * parentItem = childItem - > parentItem ( ) ;
if ( parentItem = = root ) {
2019-05-30 09:36:21 +00:00
return createIndex ( 0 , 0 , parentItem ) ;
2019-03-31 21:05:09 +00:00
}
return createIndex ( parentItem - > row ( ) , 0 , parentItem ) ;
}
QModelIndex Models : : Roster : : index ( int row , int column , const QModelIndex & parent ) const
{
if ( ! hasIndex ( row , column , parent ) ) {
return QModelIndex ( ) ;
}
Item * parentItem ;
if ( ! parent . isValid ( ) ) {
parentItem = root ;
} else {
parentItem = static_cast < Item * > ( parent . internalPointer ( ) ) ;
}
Item * childItem = parentItem - > child ( row ) ;
if ( childItem ) {
return createIndex ( row , column , childItem ) ;
} else {
return QModelIndex ( ) ;
}
}
Models : : Roster : : ElId : : ElId ( const QString & p_account , const QString & p_name ) :
account ( p_account ) ,
name ( p_name )
2019-04-03 18:15:36 +00:00
{ }
2019-03-31 21:05:09 +00:00
bool Models : : Roster : : ElId : : operator < ( const Models : : Roster : : ElId & other ) const
{
if ( account = = other . account ) {
return name < other . name ;
} else {
return account < other . account ;
}
}
2019-04-02 21:58:43 +00:00
2019-04-03 18:15:36 +00:00
void Models : : Roster : : onAccountDataChanged ( const QModelIndex & tl , const QModelIndex & br , const QVector < int > & roles )
{
if ( tl . column ( ) = = 0 ) {
emit dataChanged ( tl , br , roles ) ;
} else if ( tl . column ( ) = = 2 ) {
int row = tl . row ( ) ;
Account * acc = accountsModel - > getAccount ( row ) ;
emit dataChanged ( createIndex ( row , 0 , acc ) , createIndex ( br . row ( ) , 0 , acc ) , roles ) ;
}
}
2019-04-03 21:23:51 +00:00
void Models : : Roster : : addGroup ( const QString & account , const QString & name )
{
2019-04-05 15:12:59 +00:00
ElId id ( account , name ) ;
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : const_iterator gItr = groups . find ( id ) ;
2019-04-05 15:12:59 +00:00
if ( gItr ! = groups . end ( ) ) {
qDebug ( ) < < " An attempt to add group " < < name < < " to account " < < account < < " which already exists there, skipping " ;
return ;
}
2019-04-03 21:23:51 +00:00
std : : map < QString , Account * > : : iterator itr = accounts . find ( account ) ;
if ( itr ! = accounts . end ( ) ) {
Account * acc = itr - > second ;
2019-06-22 20:37:22 +00:00
Group * group = new Group ( { { " name " , name } } ) ;
2019-04-05 15:12:59 +00:00
groups . insert ( std : : make_pair ( id , group ) ) ;
2019-07-11 08:51:52 +00:00
acc - > appendChild ( group ) ;
2019-04-03 21:23:51 +00:00
} else {
qDebug ( ) < < " An attempt to add group " < < name < < " to non existing account " < < account < < " , skipping " ;
}
}
2019-04-07 20:14:15 +00:00
void Models : : Roster : : addContact ( const QString & account , const QString & jid , const QString & group , const QMap < QString , QVariant > & data )
2019-04-03 21:23:51 +00:00
{
Item * parent ;
2019-04-05 15:12:59 +00:00
Account * acc ;
2019-09-28 14:30:16 +00:00
Contact * sample = 0 ;
2019-04-05 15:12:59 +00:00
ElId id ( account , jid ) ;
{
2019-04-03 21:23:51 +00:00
std : : map < QString , Account * > : : iterator itr = accounts . find ( account ) ;
if ( itr = = accounts . end ( ) ) {
2019-09-28 14:30:16 +00:00
qDebug ( ) < < " An attempt to add a contact " < < jid < < " to non existing account " < < account < < " , skipping " ;
2019-04-03 21:23:51 +00:00
return ;
}
2019-04-05 15:12:59 +00:00
acc = itr - > second ;
}
2019-09-28 14:30:16 +00:00
for ( std : : multimap < ElId , Contact * > : : iterator itr = contacts . lower_bound ( id ) , eItr = contacts . upper_bound ( id ) ; itr ! = eItr ; + + itr ) {
sample = itr - > second ; //need to find if this contact is already added somewhere
break ; //so one iteration is enough
}
if ( group = = " " ) { //this means this contact is already added somewhere and there is no sense to add it ungrouped
if ( sample ! = 0 ) {
qDebug ( ) < < " An attempt to add a contact " < < jid < < " to the ungrouped contact set of account " < < account < < " for the second time, skipping " ;
return ;
} else {
parent = acc ;
2019-04-05 15:12:59 +00:00
}
2019-04-03 21:23:51 +00:00
} else {
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : iterator itr = groups . find ( { account , group } ) ;
2019-04-03 21:23:51 +00:00
if ( itr = = groups . end ( ) ) {
2019-09-28 14:30:16 +00:00
qDebug ( ) < < " An attempt to add a contact " < < jid < < " to non existing group " < < group < < " , adding group " ;
addGroup ( account , group ) ;
itr = groups . find ( { account , group } ) ;
2019-04-03 21:23:51 +00:00
}
2019-04-05 15:12:59 +00:00
2019-04-03 21:23:51 +00:00
parent = itr - > second ;
2019-04-05 15:12:59 +00:00
2019-09-28 14:30:16 +00:00
for ( int i = 0 ; i < parent - > childCount ( ) ; + + i ) { //checking if the contact is already added to that group
2019-04-05 15:12:59 +00:00
Item * item = parent - > child ( i ) ;
if ( item - > type = = Item : : contact ) {
Contact * ca = static_cast < Contact * > ( item ) ;
if ( ca - > getJid ( ) = = jid ) {
2019-09-28 14:30:16 +00:00
qDebug ( ) < < " An attempt to add a contact " < < jid < < " to the group " < < group < < " for the second time, skipping " ;
2019-04-05 15:12:59 +00:00
return ;
}
}
}
2019-09-28 14:30:16 +00:00
for ( int i = 0 ; i < acc - > childCount ( ) ; + + i ) { //checking if that contact is among ugrouped
2019-04-05 15:12:59 +00:00
Item * item = acc - > child ( i ) ;
if ( item - > type = = Item : : contact ) {
Contact * ca = static_cast < Contact * > ( item ) ;
if ( ca - > getJid ( ) = = jid ) {
2019-04-07 20:14:15 +00:00
qDebug ( ) < < " An attempt to add a already existing contact " < < jid < < " to the group " < < group < < " , contact will be moved from ungrouped contacts of " < < account ;
2019-04-05 15:12:59 +00:00
parent - > appendChild ( ca ) ;
return ;
}
}
}
2019-04-03 21:23:51 +00:00
}
2019-09-28 14:30:16 +00:00
Contact * contact ;
if ( sample = = 0 ) {
contact = new Contact ( jid , data ) ;
} else {
contact = sample - > copy ( ) ;
}
2019-04-05 15:12:59 +00:00
contacts . insert ( std : : make_pair ( id , contact ) ) ;
2019-07-11 08:51:52 +00:00
parent - > appendChild ( contact ) ;
2019-04-03 21:23:51 +00:00
}
void Models : : Roster : : removeGroup ( const QString & account , const QString & name )
{
2019-04-05 15:12:59 +00:00
ElId id ( account , name ) ;
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : const_iterator gItr = groups . find ( id ) ;
2019-04-05 15:12:59 +00:00
if ( gItr = = groups . end ( ) ) {
qDebug ( ) < < " An attempt to remove group " < < name < < " from account " < < account < < " which doesn't exist there, skipping " ;
return ;
}
2019-06-22 20:37:22 +00:00
Group * item = gItr - > second ;
2019-04-05 15:12:59 +00:00
Item * parent = item - > parentItem ( ) ;
int row = item - > row ( ) ;
parent - > removeChild ( row ) ;
std : : deque < Contact * > toInsert ;
for ( int i = 0 ; item - > childCount ( ) > 0 ; + + i ) {
Contact * cont = static_cast < Contact * > ( item - > child ( 0 ) ) ;
item - > removeChild ( 0 ) ;
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( { account , cont - > getJid ( ) } ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( { account , cont - > getJid ( ) } ) ;
int count = std : : distance ( cBeg , cEnd ) ;
if ( count > 1 ) {
for ( ; cBeg ! = cEnd ; + + count , + + cBeg ) {
if ( cBeg - > second = = cont ) {
delete cont ;
contacts . erase ( cBeg ) ;
break ;
}
}
} else {
toInsert . push_back ( cont ) ;
}
}
if ( toInsert . size ( ) > 0 ) {
Account * acc = accounts . find ( " account " ) - > second ;
2019-11-17 10:24:12 +00:00
for ( std : : deque < Contact * > : : size_type i = 0 ; i < toInsert . size ( ) ; + + i ) {
2019-04-05 15:12:59 +00:00
Contact * cont = toInsert [ i ] ;
2019-04-07 14:02:41 +00:00
acc - > appendChild ( cont ) ; //TODO optimisation
2019-04-05 15:12:59 +00:00
}
}
2019-06-15 15:29:15 +00:00
item - > deleteLater ( ) ;
groups . erase ( gItr ) ;
2019-04-03 21:23:51 +00:00
}
2019-04-02 21:58:43 +00:00
2019-04-07 20:14:15 +00:00
void Models : : Roster : : changeContact ( const QString & account , const QString & jid , const QMap < QString , QVariant > & data )
2019-04-06 10:14:32 +00:00
{
ElId id ( account , jid ) ;
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( id ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( id ) ;
for ( ; cBeg ! = cEnd ; + + cBeg ) {
2019-04-07 20:14:15 +00:00
for ( QMap < QString , QVariant > : : const_iterator itr = data . begin ( ) , end = data . end ( ) ; itr ! = end ; + + itr ) {
cBeg - > second - > update ( itr . key ( ) , itr . value ( ) ) ; ;
}
2019-04-06 10:14:32 +00:00
}
2019-08-21 09:35:07 +00:00
std : : map < ElId , Room * > : : iterator rItr = rooms . find ( id ) ;
if ( rItr ! = rooms . end ( ) ) {
for ( QMap < QString , QVariant > : : const_iterator itr = data . begin ( ) , end = data . end ( ) ; itr ! = end ; + + itr ) {
rItr - > second - > update ( itr . key ( ) , itr . value ( ) ) ; ;
}
}
2019-04-06 10:14:32 +00:00
}
void Models : : Roster : : removeContact ( const QString & account , const QString & jid )
{
ElId id ( account , jid ) ;
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( id ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( id ) ;
2019-06-15 15:29:15 +00:00
std : : multimap < ElId , Contact * > : : iterator cpBeg = cBeg ;
2019-04-06 10:14:32 +00:00
QSet < QString > toRemove ;
for ( ; cBeg ! = cEnd ; + + cBeg ) {
Contact * contact = cBeg - > second ;
Item * parent = contact - > parentItem ( ) ;
if ( parent - > type = = Item : : group & & parent - > childCount ( ) = = 1 ) {
toRemove . insert ( parent - > getName ( ) ) ;
}
2019-04-07 14:02:41 +00:00
parent - > removeChild ( contact - > row ( ) ) ;
2019-06-15 15:29:15 +00:00
contact - > deleteLater ( ) ;
2019-04-06 10:14:32 +00:00
}
2019-06-15 15:29:15 +00:00
contacts . erase ( cpBeg , cEnd ) ;
2019-04-06 10:14:32 +00:00
for ( QSet < QString > : : const_iterator itr = toRemove . begin ( ) , end = toRemove . end ( ) ; itr ! = end ; + + itr ) {
removeGroup ( account , * itr ) ;
}
}
void Models : : Roster : : removeContact ( const QString & account , const QString & jid , const QString & group )
{
ElId contactId ( account , jid ) ;
ElId groupId ( account , group ) ;
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : iterator gItr = groups . find ( groupId ) ;
2019-04-06 10:14:32 +00:00
if ( gItr = = groups . end ( ) ) {
qDebug ( ) < < " An attempt to remove contact " < < jid < < " from non existing group " < < group < < " of account " < < account < < " , skipping " ;
return ;
}
2019-09-28 14:30:16 +00:00
Account * acc = accounts . find ( account ) - > second ; //I assume the account is found, otherwise there will be no groups with that ElId;
2019-06-22 20:37:22 +00:00
Group * gr = gItr - > second ;
2019-04-06 10:14:32 +00:00
Contact * cont = 0 ;
2019-09-28 14:30:16 +00:00
unsigned int entries ( 0 ) ;
unsigned int ungroupped ( 0 ) ;
for ( std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( contactId ) , cEnd = contacts . upper_bound ( contactId ) ; cBeg ! = cEnd ; + + cBeg ) {
+ + entries ;
Contact * elem = cBeg - > second ;
if ( elem - > parentItem ( ) = = acc ) {
+ + ungroupped ;
2019-04-06 10:14:32 +00:00
}
}
2019-09-28 14:30:16 +00:00
if ( ungroupped = = 0 & & entries = = 1 ) {
for ( std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( contactId ) , cEnd = contacts . upper_bound ( contactId ) ; cBeg ! = cEnd ; + + cBeg ) {
if ( cBeg - > second - > parentItem ( ) = = gr ) {
cont = cBeg - > second ;
break ;
}
}
if ( cont = = 0 ) {
qDebug ( ) < < " An attempt to remove contact " < < jid < < " of account " < < account < < " from group " < < group < < " , but there is no such contact in that group, skipping " ;
return ;
}
qDebug ( ) < < " An attempt to remove last instance of contact " < < jid < < " from the group " < < group < < " , contact will be moved to ungrouped contacts of " < < account ;
acc - > appendChild ( cont ) ;
if ( gr - > childCount ( ) = = 0 ) {
removeGroup ( account , group ) ;
}
} else {
for ( std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( contactId ) , cEnd = contacts . upper_bound ( contactId ) ; cBeg ! = cEnd ; + + cBeg ) {
if ( cBeg - > second - > parentItem ( ) = = gr ) {
cont = cBeg - > second ;
contacts . erase ( cBeg ) ;
break ;
}
}
if ( cont = = 0 ) {
qDebug ( ) < < " An attempt to remove contact " < < jid < < " of account " < < account < < " from group " < < group < < " , but there is no such contact in that group, skipping " ;
return ;
}
gr - > removeChild ( cont - > row ( ) ) ;
cont - > deleteLater ( ) ;
if ( gr - > childCount ( ) = = 0 ) {
removeGroup ( account , group ) ;
}
2019-04-06 10:14:32 +00:00
}
}
2019-04-07 14:02:41 +00:00
void Models : : Roster : : onChildChanged ( Models : : Item * item , int row , int col )
{
2019-04-07 20:14:15 +00:00
QModelIndex index = createIndex ( row , 0 , item ) ;
2019-10-24 09:42:38 +00:00
QModelIndex index2 = createIndex ( row , 1 , item ) ;
emit dataChanged ( index , index2 ) ;
2019-04-07 14:02:41 +00:00
}
void Models : : Roster : : onChildIsAboutToBeInserted ( Models : : Item * parent , int first , int last )
{
int row = 0 ;
if ( parent ! = root ) {
row = parent - > row ( ) ;
beginInsertRows ( createIndex ( row , 0 , parent ) , first , last ) ;
} else {
beginInsertRows ( QModelIndex ( ) , first , last ) ;
}
}
void Models : : Roster : : onChildIsAboutToBeMoved ( Models : : Item * source , int first , int last , Models : : Item * destination , int newIndex )
{
int oldRow = 0 ;
if ( source ! = root ) {
oldRow = source - > row ( ) ;
}
int newRow = 0 ;
if ( destination ! = root ) {
newRow = destination - > row ( ) ;
}
beginMoveRows ( createIndex ( oldRow , 0 , source ) , first , last , createIndex ( newRow , 0 , destination ) , newIndex ) ;
}
void Models : : Roster : : onChildIsAboutToBeRemoved ( Models : : Item * parent , int first , int last )
{
int row = 0 ;
if ( parent ! = root ) {
row = parent - > row ( ) ;
}
beginRemoveRows ( createIndex ( row , 0 , parent ) , first , last ) ;
}
void Models : : Roster : : onChildInserted ( )
{
endInsertRows ( ) ;
}
void Models : : Roster : : onChildMoved ( )
{
endMoveRows ( ) ;
}
void Models : : Roster : : onChildRemoved ( )
{
endRemoveRows ( ) ;
}
void Models : : Roster : : addPresence ( const QString & account , const QString & jid , const QString & name , const QMap < QString , QVariant > & data )
{
ElId contactId ( account , jid ) ;
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( contactId ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( contactId ) ;
for ( ; cBeg ! = cEnd ; + + cBeg ) {
cBeg - > second - > addPresence ( name , data ) ;
}
}
void Models : : Roster : : removePresence ( const QString & account , const QString & jid , const QString & name )
{
ElId contactId ( account , jid ) ;
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( contactId ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( contactId ) ;
for ( ; cBeg ! = cEnd ; + + cBeg ) {
cBeg - > second - > removePresence ( name ) ;
}
}
2019-04-09 22:01:25 +00:00
2019-04-11 14:58:59 +00:00
void Models : : Roster : : addMessage ( const QString & account , const Shared : : Message & data )
2019-04-09 22:01:25 +00:00
{
2019-04-11 14:58:59 +00:00
ElId id ( account , data . getPenPalJid ( ) ) ;
2019-04-09 22:01:25 +00:00
std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( id ) ;
std : : multimap < ElId , Contact * > : : iterator cEnd = contacts . upper_bound ( id ) ;
for ( ; cBeg ! = cEnd ; + + cBeg ) {
cBeg - > second - > addMessage ( data ) ;
}
2019-08-31 20:50:05 +00:00
std : : map < ElId , Room * > : : const_iterator rItr = rooms . find ( id ) ;
if ( rItr ! = rooms . end ( ) ) {
rItr - > second - > addMessage ( data ) ;
}
2019-04-09 22:01:25 +00:00
}
void Models : : Roster : : dropMessages ( const QString & account , const QString & jid )
{
ElId id ( account , jid ) ;
for ( std : : multimap < ElId , Contact * > : : iterator cBeg = contacts . lower_bound ( id ) , cEnd = contacts . upper_bound ( id ) ; cBeg ! = cEnd ; + + cBeg ) {
cBeg - > second - > dropMessages ( ) ;
}
2019-08-31 20:50:05 +00:00
std : : map < ElId , Room * > : : const_iterator rItr = rooms . find ( id ) ;
if ( rItr ! = rooms . end ( ) ) {
rItr - > second - > dropMessages ( ) ;
}
2019-04-09 22:01:25 +00:00
}
2019-05-29 15:05:54 +00:00
void Models : : Roster : : removeAccount ( const QString & account )
{
std : : map < QString , Account * > : : const_iterator itr = accounts . find ( account ) ;
if ( itr = = accounts . end ( ) ) {
qDebug ( ) < < " An attempt to remove non existing account " < < account < < " , skipping " ;
return ;
}
Account * acc = itr - > second ;
int index = acc - > row ( ) ;
root - > removeChild ( index ) ;
accountsModel - > removeAccount ( index ) ;
2019-05-30 09:36:21 +00:00
accounts . erase ( itr ) ;
2019-05-29 15:05:54 +00:00
std : : multimap < ElId , Contact * > : : const_iterator cItr = contacts . begin ( ) ;
while ( cItr ! = contacts . end ( ) ) {
if ( cItr - > first . account = = account ) {
std : : multimap < ElId , Contact * > : : const_iterator lItr = cItr ;
+ + cItr ;
contacts . erase ( lItr ) ;
} else {
+ + cItr ;
}
}
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : const_iterator gItr = groups . begin ( ) ;
2019-05-29 15:05:54 +00:00
while ( gItr ! = groups . end ( ) ) {
if ( gItr - > first . account = = account ) {
2019-06-22 20:37:22 +00:00
std : : map < ElId , Group * > : : const_iterator lItr = gItr ;
2019-05-29 15:05:54 +00:00
+ + gItr ;
groups . erase ( lItr ) ;
} else {
+ + gItr ;
}
}
2019-07-11 08:51:52 +00:00
std : : map < ElId , Room * > : : const_iterator rItr = rooms . begin ( ) ;
while ( rItr ! = rooms . end ( ) ) {
if ( rItr - > first . account = = account ) {
std : : map < ElId , Room * > : : const_iterator lItr = rItr ;
+ + rItr ;
rooms . erase ( lItr ) ;
} else {
+ + rItr ;
}
}
2019-05-30 09:36:21 +00:00
acc - > deleteLater ( ) ;
2019-05-29 15:05:54 +00:00
}
2019-06-18 15:08:03 +00:00
QString Models : : Roster : : getContactName ( const QString & account , const QString & jid )
{
2019-08-31 20:50:05 +00:00
ElId id ( account , jid ) ;
std : : multimap < ElId , Contact * > : : const_iterator cItr = contacts . find ( id ) ;
QString name = " " ;
2019-06-18 15:08:03 +00:00
if ( cItr = = contacts . end ( ) ) {
2019-08-31 20:50:05 +00:00
std : : map < ElId , Room * > : : const_iterator rItr = rooms . find ( id ) ;
if ( rItr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to get a name of non existing contact/room " < < account < < " : " < < jid < < " , skipping " ;
} else {
2019-09-24 09:21:29 +00:00
name = rItr - > second - > getRoomName ( ) ;
2019-08-31 20:50:05 +00:00
}
} else {
name = cItr - > second - > getContactName ( ) ;
2019-06-18 15:08:03 +00:00
}
2019-08-31 20:50:05 +00:00
return name ;
2019-06-18 15:08:03 +00:00
}
2019-07-11 08:51:52 +00:00
void Models : : Roster : : addRoom ( const QString & account , const QString jid , const QMap < QString , QVariant > & data )
{
Account * acc ;
{
std : : map < QString , Account * > : : iterator itr = accounts . find ( account ) ;
if ( itr = = accounts . end ( ) ) {
qDebug ( ) < < " An attempt to add a room " < < jid < < " to non existing account " < < account < < " , skipping " ;
return ;
}
acc = itr - > second ;
}
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr ! = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to add already existing room " < < jid < < " , skipping " ;
return ;
}
Room * room = new Room ( jid , data ) ;
rooms . insert ( std : : make_pair ( id , room ) ) ;
acc - > appendChild ( room ) ;
}
void Models : : Roster : : changeRoom ( const QString & account , const QString jid , const QMap < QString , QVariant > & data )
{
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to change non existing room " < < jid < < " , skipping " ;
return ;
}
Room * room = itr - > second ;
for ( QMap < QString , QVariant > : : const_iterator dItr = data . begin ( ) , dEnd = data . end ( ) ; dItr ! = dEnd ; + + dItr ) {
room - > update ( dItr . key ( ) , dItr . value ( ) ) ;
}
}
void Models : : Roster : : removeRoom ( const QString & account , const QString jid )
{
Account * acc ;
{
std : : map < QString , Account * > : : iterator itr = accounts . find ( account ) ;
if ( itr = = accounts . end ( ) ) {
qDebug ( ) < < " An attempt to remove a room " < < jid < < " from non existing account " < < account < < " , skipping " ;
return ;
}
acc = itr - > second ;
}
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to remove non existing room " < < jid < < " , skipping " ;
return ;
}
Room * room = itr - > second ;
acc - > removeChild ( room - > row ( ) ) ;
room - > deleteLater ( ) ;
rooms . erase ( itr ) ;
}
2019-09-02 11:17:28 +00:00
void Models : : Roster : : addRoomParticipant ( const QString & account , const QString & jid , const QString & name , const QMap < QString , QVariant > & data )
{
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to add participant " < < name < < " non existing room " < < jid < < " of an account " < < account < < " , skipping " ;
return ;
} else {
itr - > second - > addParticipant ( name , data ) ;
}
}
void Models : : Roster : : changeRoomParticipant ( const QString & account , const QString & jid , const QString & name , const QMap < QString , QVariant > & data )
{
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt change participant " < < name < < " of non existing room " < < jid < < " of an account " < < account < < " , skipping " ;
return ;
} else {
itr - > second - > changeParticipant ( name , data ) ;
}
}
void Models : : Roster : : removeRoomParticipant ( const QString & account , const QString & jid , const QString & name )
{
ElId id = { account , jid } ;
std : : map < ElId , Room * > : : const_iterator itr = rooms . find ( id ) ;
if ( itr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt remove participant " < < name < < " from non existing room " < < jid < < " of an account " < < account < < " , skipping " ;
return ;
} else {
itr - > second - > removeParticipant ( name ) ;
}
}
2019-09-28 14:30:16 +00:00
std : : deque < QString > Models : : Roster : : groupList ( const QString & account ) const
{
std : : deque < QString > answer ;
for ( std : : pair < ElId , Group * > pair : groups ) {
if ( pair . first . account = = account ) {
answer . push_back ( pair . first . name ) ;
}
}
return answer ;
}
bool Models : : Roster : : groupHasContact ( const QString & account , const QString & group , const QString & contact ) const
{
ElId grId ( { account , group } ) ;
std : : map < ElId , Group * > : : const_iterator gItr = groups . find ( grId ) ;
if ( gItr = = groups . end ( ) ) {
return false ;
} else {
const Group * gr = gItr - > second ;
return gr - > hasContact ( contact ) ;
}
}
2019-10-25 13:38:48 +00:00
QString Models : : Roster : : getContactIconPath ( const QString & account , const QString & jid )
{
ElId id ( account , jid ) ;
std : : multimap < ElId , Contact * > : : const_iterator cItr = contacts . find ( id ) ;
QString path = " " ;
if ( cItr = = contacts . end ( ) ) {
std : : map < ElId , Room * > : : const_iterator rItr = rooms . find ( id ) ;
if ( rItr = = rooms . end ( ) ) {
qDebug ( ) < < " An attempt to get an icon path of non existing contact " < < account < < " : " < < jid < < " , returning empty value " ;
} else {
//path = rItr->second->getRoomName();
}
} else {
if ( cItr - > second - > getAvatarState ( ) ! = Shared : : Avatar : : empty ) {
path = cItr - > second - > getAvatarPath ( ) ;
}
}
return path ;
}
2019-12-20 15:41:20 +00:00
Models : : Account * Models : : Roster : : getAccount ( const QString & name )
{
return accounts . find ( name ) - > second ;
}
2019-12-25 10:24:20 +00:00
QModelIndex Models : : Roster : : getAccountIndex ( const QString & name )
{
std : : map < QString , Account * > : : const_iterator itr = accounts . find ( name ) ;
if ( itr = = accounts . end ( ) ) {
return QModelIndex ( ) ;
} else {
return index ( itr - > second - > row ( ) , 0 , QModelIndex ( ) ) ;
}
}
QModelIndex Models : : Roster : : getGroupIndex ( const QString & account , const QString & name )
{
std : : map < QString , Account * > : : const_iterator itr = accounts . find ( account ) ;
if ( itr = = accounts . end ( ) ) {
return QModelIndex ( ) ;
} else {
std : : map < ElId , Group * > : : const_iterator gItr = groups . find ( { account , name } ) ;
if ( gItr = = groups . end ( ) ) {
return QModelIndex ( ) ;
} else {
QModelIndex accIndex = index ( itr - > second - > row ( ) , 0 , QModelIndex ( ) ) ;
return index ( gItr - > second - > row ( ) , 0 , accIndex ) ;
}
}
}