2019-04-11 14:58:59 +00:00
/*
2019-08-14 14:54:46 +00:00
* Squawk messenger .
2019-04-12 15:22:10 +00:00
* Copyright ( C ) 2019 Yury Gubich < blue @ macaw . me >
2019-04-11 14:58:59 +00:00
*
* 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/>.
*/
# include "messageline.h"
2019-04-13 20:38:20 +00:00
# include <QDebug>
2019-09-05 23:44:20 +00:00
# include <cmath>
2019-04-11 14:58:59 +00:00
2019-08-29 14:19:35 +00:00
MessageLine : : MessageLine ( bool p_room , QWidget * parent ) :
2019-04-11 14:58:59 +00:00
QWidget ( parent ) ,
messageIndex ( ) ,
messageOrder ( ) ,
2019-09-10 14:33:39 +00:00
myMessages ( ) ,
palMessages ( ) ,
2019-11-11 15:19:54 +00:00
uploadPaths ( ) ,
2019-12-23 06:28:23 +00:00
palAvatars ( ) ,
2019-09-10 14:33:39 +00:00
layout ( new QVBoxLayout ( this ) ) ,
2019-04-12 15:22:10 +00:00
myName ( ) ,
2019-12-20 15:41:20 +00:00
myAvatarPath ( ) ,
2019-04-13 20:38:20 +00:00
palNames ( ) ,
2019-11-11 15:19:54 +00:00
uploading ( ) ,
downloading ( ) ,
2019-09-05 15:25:31 +00:00
room ( p_room ) ,
busyShown ( false ) ,
2019-10-30 13:47:21 +00:00
progress ( )
2019-04-11 14:58:59 +00:00
{
2020-02-04 15:14:51 +00:00
setContentsMargins ( 0 , 0 , 0 , 0 ) ;
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
layout - > setSpacing ( 0 ) ;
2019-04-12 05:51:36 +00:00
layout - > addStretch ( ) ;
2019-04-11 14:58:59 +00:00
}
MessageLine : : ~ MessageLine ( )
{
2019-04-13 20:38:20 +00:00
for ( Index : : const_iterator itr = messageIndex . begin ( ) , end = messageIndex . end ( ) ; itr ! = end ; + + itr ) {
delete itr - > second ;
}
2019-04-11 14:58:59 +00:00
}
2019-11-15 13:30:29 +00:00
MessageLine : : Position MessageLine : : message ( const Shared : : Message & msg , bool forceOutgoing )
2019-04-11 14:58:59 +00:00
{
2019-04-13 20:38:20 +00:00
QString id = msg . getId ( ) ;
Index : : iterator itr = messageIndex . find ( id ) ;
if ( itr ! = messageIndex . end ( ) ) {
qDebug ( ) < < " received more then one message with the same id, skipping yet the new one " ;
return invalid ;
}
2019-09-10 14:33:39 +00:00
QString sender ;
2019-12-20 15:41:20 +00:00
QString aPath ;
2019-09-10 14:33:39 +00:00
bool outgoing ;
2019-11-15 13:30:29 +00:00
if ( forceOutgoing ) {
sender = myName ;
2019-12-20 15:41:20 +00:00
aPath = myAvatarPath ;
2019-11-15 13:30:29 +00:00
outgoing = true ;
2019-09-10 14:33:39 +00:00
} else {
2019-11-15 13:30:29 +00:00
if ( room ) {
if ( msg . getFromResource ( ) = = myName ) {
sender = myName ;
2019-12-20 15:41:20 +00:00
aPath = myAvatarPath ;
2019-11-15 13:30:29 +00:00
outgoing = true ;
} else {
sender = msg . getFromResource ( ) ;
2019-12-31 18:14:12 +00:00
std : : map < QString , QString > : : iterator aItr = palAvatars . find ( sender ) ;
if ( aItr ! = palAvatars . end ( ) ) {
aPath = aItr - > second ;
}
2019-11-15 13:30:29 +00:00
outgoing = false ;
}
2019-09-10 14:33:39 +00:00
} else {
2019-11-15 13:30:29 +00:00
if ( msg . getOutgoing ( ) ) {
sender = myName ;
2019-12-20 15:41:20 +00:00
aPath = myAvatarPath ;
2019-11-15 13:30:29 +00:00
outgoing = true ;
2019-09-10 14:33:39 +00:00
} else {
2019-11-15 13:30:29 +00:00
QString jid = msg . getFromJid ( ) ;
std : : map < QString , QString > : : iterator itr = palNames . find ( jid ) ;
if ( itr ! = palNames . end ( ) ) {
sender = itr - > second ;
} else {
sender = jid ;
}
2019-12-23 06:28:23 +00:00
std : : map < QString , QString > : : iterator aItr = palAvatars . find ( jid ) ;
if ( aItr ! = palAvatars . end ( ) ) {
aPath = aItr - > second ;
}
2019-11-15 13:30:29 +00:00
outgoing = false ;
2019-09-10 14:33:39 +00:00
}
}
}
2019-12-20 15:41:20 +00:00
Message * message = new Message ( msg , outgoing , sender , aPath ) ;
2019-09-10 14:33:39 +00:00
std : : pair < Order : : const_iterator , bool > result = messageOrder . insert ( std : : make_pair ( msg . getTime ( ) , message ) ) ;
2019-04-13 20:38:20 +00:00
if ( ! result . second ) {
qDebug ( ) < < " Error appending a message into a message list - seems like the time of that message exactly matches the time of some other message, can't put them in order, skipping yet " ;
2019-09-10 14:33:39 +00:00
delete message ;
2019-04-13 20:38:20 +00:00
return invalid ;
}
2019-09-10 14:33:39 +00:00
if ( outgoing ) {
2019-11-12 13:38:01 +00:00
myMessages . insert ( std : : make_pair ( id , message ) ) ;
} else {
2019-12-31 18:14:12 +00:00
QString senderId ;
2019-09-10 14:33:39 +00:00
if ( room ) {
2019-12-31 18:14:12 +00:00
senderId = sender ;
2019-09-10 14:33:39 +00:00
} else {
2020-02-08 11:44:15 +00:00
senderId = msg . getFromJid ( ) ;
2019-09-10 14:33:39 +00:00
}
2019-12-31 18:14:12 +00:00
std : : map < QString , Index > : : iterator pItr = palMessages . find ( senderId ) ;
if ( pItr = = palMessages . end ( ) ) {
pItr = palMessages . insert ( std : : make_pair ( senderId , Index ( ) ) ) . first ;
}
pItr - > second . insert ( std : : make_pair ( id , message ) ) ;
2019-09-10 14:33:39 +00:00
}
messageIndex . insert ( std : : make_pair ( id , message ) ) ;
2019-11-17 10:24:12 +00:00
unsigned long index = std : : distance < Order : : const_iterator > ( messageOrder . begin ( ) , result . first ) ; //need to make with binary indexed tree
2019-04-13 20:38:20 +00:00
Position res = invalid ;
if ( index = = 0 ) {
res = beggining ;
} else if ( index = = messageIndex . size ( ) - 1 ) {
res = end ;
} else {
res = middle ;
}
2019-09-05 15:25:31 +00:00
if ( busyShown ) {
index + = 1 ;
}
2019-08-28 11:40:55 +00:00
2019-04-13 20:38:20 +00:00
if ( res = = end ) {
2020-02-04 15:14:51 +00:00
layout - > addWidget ( message ) ;
2019-04-13 20:38:20 +00:00
} else {
2020-02-04 15:14:51 +00:00
layout - > insertWidget ( index + 1 , message ) ;
2019-04-13 20:38:20 +00:00
}
2019-11-11 15:19:54 +00:00
if ( msg . hasOutOfBandUrl ( ) ) {
2019-09-12 20:54:44 +00:00
emit requestLocalFile ( msg . getId ( ) , msg . getOutOfBandUrl ( ) ) ;
2019-11-12 13:38:01 +00:00
connect ( message , & Message : : buttonClicked , this , & MessageLine : : onDownload ) ;
2019-09-12 20:54:44 +00:00
}
2019-04-13 20:38:20 +00:00
return res ;
2019-04-11 14:58:59 +00:00
}
2020-02-08 11:44:15 +00:00
void MessageLine : : changeMessage ( const QString & id , const QMap < QString , QVariant > & data )
{
Index : : const_iterator itr = messageIndex . find ( id ) ;
if ( itr ! = messageIndex . end ( ) ) {
Message * msg = itr - > second ;
if ( msg - > change ( data ) ) { //if ID changed (stanza in replace of another)
QString newId = msg - > getId ( ) ; //need to updated IDs of that message in all maps
messageIndex . erase ( itr ) ;
messageIndex . insert ( std : : make_pair ( newId , msg ) ) ;
if ( msg - > outgoing ) {
QString senderId ;
if ( room ) {
senderId = msg - > getSenderResource ( ) ;
} else {
senderId = msg - > getSenderJid ( ) ;
}
std : : map < QString , Index > : : iterator pItr = palMessages . find ( senderId ) ;
if ( pItr ! = palMessages . end ( ) ) {
Index : : const_iterator sItr = pItr - > second . find ( id ) ;
if ( sItr ! = pItr - > second . end ( ) ) {
pItr - > second . erase ( sItr ) ;
pItr - > second . insert ( std : : make_pair ( newId , msg ) ) ;
} else {
qDebug ( ) < < " Was trying to replace message in open conversations, couldn't find it among pal's messages, probably an error " ;
}
} else {
qDebug ( ) < < " Was trying to replace message in open conversations, couldn't find pal messages, probably an error " ;
}
} else {
Index : : const_iterator mItr = myMessages . find ( id ) ;
if ( mItr ! = myMessages . end ( ) ) {
myMessages . erase ( mItr ) ;
myMessages . insert ( std : : make_pair ( newId , msg ) ) ;
} else {
qDebug ( ) < < " Was trying to replace message in open conversations, couldn't find it among my messages, probably an error " ;
}
}
}
}
}
2019-11-11 15:19:54 +00:00
void MessageLine : : onDownload ( )
{
Message * msg = static_cast < Message * > ( sender ( ) ) ;
QString messageId = msg - > getId ( ) ;
Index : : const_iterator itr = downloading . find ( messageId ) ;
if ( itr = = downloading . end ( ) ) {
downloading . insert ( std : : make_pair ( messageId , msg ) ) ;
2019-11-12 13:38:01 +00:00
msg - > setProgress ( 0 ) ;
msg - > showComment ( tr ( " Downloading... " ) ) ;
2019-11-11 15:19:54 +00:00
emit downloadFile ( messageId , msg - > getFileUrl ( ) ) ;
} else {
qDebug ( ) < < " An attempt to initiate download for already downloading file " < < msg - > getFileUrl ( ) < < " , skipping " ;
}
}
2019-04-12 15:22:10 +00:00
void MessageLine : : setMyName ( const QString & name )
{
myName = name ;
2019-09-10 14:33:39 +00:00
for ( Index : : const_iterator itr = myMessages . begin ( ) , end = myMessages . end ( ) ; itr ! = end ; + + itr ) {
itr - > second - > setSender ( name ) ;
}
2019-04-12 15:22:10 +00:00
}
void MessageLine : : setPalName ( const QString & jid , const QString & name )
{
std : : map < QString , QString > : : iterator itr = palNames . find ( jid ) ;
if ( itr = = palNames . end ( ) ) {
palNames . insert ( std : : make_pair ( jid , name ) ) ;
} else {
itr - > second = name ;
}
2019-09-10 14:33:39 +00:00
std : : map < QString , Index > : : iterator pItr = palMessages . find ( jid ) ;
if ( pItr ! = palMessages . end ( ) ) {
for ( Index : : const_iterator itr = pItr - > second . begin ( ) , end = pItr - > second . end ( ) ; itr ! = end ; + + itr ) {
itr - > second - > setSender ( name ) ;
}
}
2019-04-12 15:22:10 +00:00
}
2019-04-13 20:38:20 +00:00
2019-12-23 06:28:23 +00:00
void MessageLine : : setPalAvatar ( const QString & jid , const QString & path )
{
std : : map < QString , QString > : : iterator itr = palAvatars . find ( jid ) ;
if ( itr = = palAvatars . end ( ) ) {
palAvatars . insert ( std : : make_pair ( jid , path ) ) ;
} else {
itr - > second = path ;
}
std : : map < QString , Index > : : iterator pItr = palMessages . find ( jid ) ;
if ( pItr ! = palMessages . end ( ) ) {
for ( Index : : const_iterator itr = pItr - > second . begin ( ) , end = pItr - > second . end ( ) ; itr ! = end ; + + itr ) {
itr - > second - > setAvatarPath ( path ) ;
}
}
}
void MessageLine : : dropPalAvatar ( const QString & jid )
{
std : : map < QString , QString > : : iterator itr = palAvatars . find ( jid ) ;
2019-12-24 08:42:46 +00:00
if ( itr ! = palAvatars . end ( ) ) {
palAvatars . erase ( itr ) ;
2019-12-23 06:28:23 +00:00
std : : map < QString , Index > : : iterator pItr = palMessages . find ( jid ) ;
if ( pItr ! = palMessages . end ( ) ) {
for ( Index : : const_iterator itr = pItr - > second . begin ( ) , end = pItr - > second . end ( ) ; itr ! = end ; + + itr ) {
itr - > second - > setAvatarPath ( " " ) ;
}
}
}
}
2019-04-13 20:38:20 +00:00
void MessageLine : : resizeEvent ( QResizeEvent * event )
{
QWidget : : resizeEvent ( event ) ;
emit resize ( event - > size ( ) . height ( ) - event - > oldSize ( ) . height ( ) ) ;
}
2019-05-15 17:36:37 +00:00
QString MessageLine : : firstMessageId ( ) const
{
if ( messageOrder . size ( ) = = 0 ) {
return " " ;
} else {
return messageOrder . begin ( ) - > second - > getId ( ) ;
}
}
2019-09-05 15:25:31 +00:00
void MessageLine : : showBusyIndicator ( )
{
if ( ! busyShown ) {
2019-10-30 13:47:21 +00:00
layout - > insertWidget ( 0 , & progress ) ;
progress . start ( ) ;
2019-09-05 15:25:31 +00:00
busyShown = true ;
}
}
void MessageLine : : hideBusyIndicator ( )
{
if ( busyShown ) {
2019-10-30 13:47:21 +00:00
progress . stop ( ) ;
layout - > removeWidget ( & progress ) ;
2019-09-05 15:25:31 +00:00
busyShown = false ;
}
}
2019-11-11 15:19:54 +00:00
void MessageLine : : fileProgress ( const QString & messageId , qreal progress )
2019-09-12 20:54:44 +00:00
{
2019-11-12 13:38:01 +00:00
Index : : const_iterator itr = messageIndex . find ( messageId ) ;
if ( itr = = messageIndex . end ( ) ) {
//TODO may be some logging, that's not normal
2019-09-12 20:54:44 +00:00
} else {
2019-11-12 13:38:01 +00:00
itr - > second - > setProgress ( progress ) ;
2019-09-12 20:54:44 +00:00
}
}
void MessageLine : : responseLocalFile ( const QString & messageId , const QString & path )
{
Index : : const_iterator itr = messageIndex . find ( messageId ) ;
if ( itr = = messageIndex . end ( ) ) {
} else {
2019-11-12 13:38:01 +00:00
Index : : const_iterator uItr = uploading . find ( messageId ) ;
2019-09-12 20:54:44 +00:00
if ( path . size ( ) > 0 ) {
2019-11-12 13:38:01 +00:00
Index : : const_iterator dItr = downloading . find ( messageId ) ;
if ( dItr ! = downloading . end ( ) ) {
downloading . erase ( dItr ) ;
itr - > second - > showFile ( path ) ;
} else {
if ( uItr ! = uploading . end ( ) ) {
uploading . erase ( uItr ) ;
std : : map < QString , QString > : : const_iterator muItr = uploadPaths . find ( messageId ) ;
if ( muItr ! = uploadPaths . end ( ) ) {
uploadPaths . erase ( muItr ) ;
}
if ( room ) {
removeMessage ( messageId ) ;
} else {
Shared : : Message msg = itr - > second - > getMessage ( ) ;
removeMessage ( messageId ) ;
msg . setCurrentTime ( ) ;
message ( msg ) ;
itr = messageIndex . find ( messageId ) ;
itr - > second - > showFile ( path ) ;
}
} else {
itr - > second - > showFile ( path ) ; //then it is already cached file
}
}
2019-09-12 20:54:44 +00:00
} else {
2019-11-14 11:43:43 +00:00
if ( uItr = = uploading . end ( ) ) {
const Shared : : Message & msg = itr - > second - > getMessage ( ) ;
itr - > second - > addButton ( QIcon : : fromTheme ( " download " ) , tr ( " Download " ) , " <a href= \" " + msg . getOutOfBandUrl ( ) + " \" > " + msg . getOutOfBandUrl ( ) + " </a> " ) ;
2019-11-12 13:38:01 +00:00
itr - > second - > showComment ( tr ( " Push the button to daownload the file " ) ) ;
} else {
qDebug ( ) < < " An unhandled state for file uploading - empty path " ;
}
2019-09-12 20:54:44 +00:00
}
}
}
2019-09-18 13:27:47 +00:00
2019-11-12 13:38:01 +00:00
void MessageLine : : removeMessage ( const QString & messageId )
{
Index : : const_iterator itr = messageIndex . find ( messageId ) ;
if ( itr ! = messageIndex . end ( ) ) {
Message * ui = itr - > second ;
const Shared : : Message & msg = ui - > getMessage ( ) ;
messageIndex . erase ( itr ) ;
Order : : const_iterator oItr = messageOrder . find ( msg . getTime ( ) ) ;
if ( oItr ! = messageOrder . end ( ) ) {
messageOrder . erase ( oItr ) ;
} else {
qDebug ( ) < < " An attempt to remove message from messageLine, but it wasn't found in order " ;
}
if ( msg . getOutgoing ( ) ) {
Index : : const_iterator mItr = myMessages . find ( messageId ) ;
if ( mItr ! = myMessages . end ( ) ) {
myMessages . erase ( mItr ) ;
} else {
qDebug ( ) < < " Error removing message: it seems to be outgoing yet it wasn't found in outgoing messages " ;
}
} else {
if ( room ) {
} else {
QString jid = msg . getFromJid ( ) ;
std : : map < QString , Index > : : iterator pItr = palMessages . find ( jid ) ;
if ( pItr ! = palMessages . end ( ) ) {
Index & pMsgs = pItr - > second ;
Index : : const_iterator pmitr = pMsgs . find ( messageId ) ;
if ( pmitr ! = pMsgs . end ( ) ) {
pMsgs . erase ( pmitr ) ;
} else {
qDebug ( ) < < " Error removing message: it seems to be incoming yet it wasn't found among messages from that penpal " ;
}
}
}
}
ui - > deleteLater ( ) ;
qDebug ( ) < < " message " < < messageId < < " has been removed " ;
} else {
qDebug ( ) < < " An attempt to remove non existing message from messageLine " ;
}
}
2019-11-11 15:19:54 +00:00
void MessageLine : : fileError ( const QString & messageId , const QString & error )
2019-09-18 13:27:47 +00:00
{
2019-11-11 15:19:54 +00:00
Index : : const_iterator itr = downloading . find ( messageId ) ;
if ( itr = = downloading . end ( ) ) {
Index : : const_iterator itr = uploading . find ( messageId ) ;
if ( itr = = uploading . end ( ) ) {
//TODO may be some logging, that's not normal
} else {
2019-11-12 13:38:01 +00:00
itr - > second - > showComment ( tr ( " Error uploading file: %1 \n You can try again " ) . arg ( QCoreApplication : : translate ( " NetworkErrors " , error . toLatin1 ( ) ) ) , true ) ;
itr - > second - > addButton ( QIcon : : fromTheme ( " upload " ) , tr ( " Upload " ) ) ;
2019-11-11 15:19:54 +00:00
}
2019-09-18 13:27:47 +00:00
} else {
2019-11-14 11:43:43 +00:00
const Shared : : Message & msg = itr - > second - > getMessage ( ) ;
itr - > second - > addButton ( QIcon : : fromTheme ( " download " ) , tr ( " Download " ) , " <a href= \" " + msg . getOutOfBandUrl ( ) + " \" > " + msg . getOutOfBandUrl ( ) + " </a> " ) ;
2019-11-12 13:38:01 +00:00
itr - > second - > showComment ( tr ( " Error downloading file: %1 \n You can try again " ) . arg ( QCoreApplication : : translate ( " NetworkErrors " , error . toLatin1 ( ) ) ) , true ) ;
2019-09-18 13:27:47 +00:00
}
}
2019-11-11 15:19:54 +00:00
void MessageLine : : appendMessageWithUpload ( const Shared : : Message & msg , const QString & path )
{
2019-11-15 13:30:29 +00:00
message ( msg , true ) ;
2019-11-12 13:38:01 +00:00
QString id = msg . getId ( ) ;
Message * ui = messageIndex . find ( id ) - > second ;
connect ( ui , & Message : : buttonClicked , this , & MessageLine : : onUpload ) ; //this is in case of retry;
ui - > setProgress ( 0 ) ;
2019-11-14 11:43:43 +00:00
ui - > showComment ( tr ( " Uploading... " ) ) ;
2019-11-12 13:38:01 +00:00
uploading . insert ( std : : make_pair ( id , ui ) ) ;
uploadPaths . insert ( std : : make_pair ( id , path ) ) ;
emit uploadFile ( msg , path ) ;
2019-11-11 15:19:54 +00:00
}
2019-11-12 13:38:01 +00:00
void MessageLine : : onUpload ( )
{
//TODO retry
}
2019-12-20 15:41:20 +00:00
void MessageLine : : setMyAvatarPath ( const QString & p_path )
{
if ( myAvatarPath ! = p_path ) {
myAvatarPath = p_path ;
for ( std : : pair < QString , Message * > pair : myMessages ) {
pair . second - > setAvatarPath ( myAvatarPath ) ;
}
}
}