2014-05-30 12:53:19 +04:00
/*
This file is part of Telegram Desktop ,
2014-12-01 13:47:38 +03:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 12:53:19 +04:00
Telegram Desktop 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 .
It 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 .
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2014-12-01 13:47:38 +03:00
Copyright ( c ) 2014 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# include "stdafx.h"
# include "style.h"
# include "lang.h"
# include "history.h"
# include "mainwidget.h"
# include "application.h"
# include "fileuploader.h"
# include "window.h"
# include "gui/filedialog.h"
2014-09-04 11:33:44 +04:00
# include "audio.h"
2014-11-22 12:45:04 +03:00
# include "localstorage.h"
2014-09-04 11:33:44 +04:00
2014-05-30 12:53:19 +04:00
TextParseOptions _textNameOptions = {
0 , // flags
4096 , // maxw
1 , // maxh
Qt : : LayoutDirectionAuto , // lang-dependent
} ;
TextParseOptions _textDlgOptions = {
0 , // flags
0 , // maxw is style-dependent
1 , // maxh
Qt : : LayoutDirectionAuto , // lang-dependent
} ;
2015-06-10 18:54:24 +03:00
TextParseOptions _historyTextOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _historyBotOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
2014-05-30 12:53:19 +04:00
2014-08-22 18:55:23 +04:00
namespace {
2014-05-30 12:53:19 +04:00
TextParseOptions _historySrvOptions = {
2015-04-08 02:03:32 +03:00
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText , // flags
2014-05-30 12:53:19 +04:00
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // lang-dependent
} ;
2015-04-04 23:01:34 +03:00
TextParseOptions _webpageTitleOptions = {
TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _webpageDescriptionOptions = {
2015-04-08 02:03:32 +03:00
TextParseLinks | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _twitterDescriptionOptions = {
TextParseLinks | TextParseMentions | TextTwitterMentions | TextParseHashtags | TextTwitterHashtags | TextParseMultiline | TextParseRichText , // flags
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
TextParseOptions _instagramDescriptionOptions = {
TextParseLinks | TextParseMentions | TextInstagramMentions | TextParseHashtags | TextInstagramHashtags | TextParseMultiline | TextParseRichText , // flags
2015-04-04 23:01:34 +03:00
0 , // maxw
0 , // maxh
Qt : : LayoutDirectionAuto , // dir
} ;
2014-05-30 12:53:19 +04:00
inline void _initTextOptions ( ) {
2015-04-19 13:29:19 +03:00
_historySrvOptions . dir = _textNameOptions . dir = _textDlgOptions . dir = cLangDir ( ) ;
2014-05-30 12:53:19 +04:00
_textDlgOptions . maxw = st : : dlgMaxWidth * 2 ;
2015-04-07 01:15:29 +03:00
_webpageTitleOptions . maxw = st : : msgMaxWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) - st : : webPageLeft ;
2015-04-04 23:01:34 +03:00
_webpageTitleOptions . maxh = st : : webPageTitleFont - > height * 2 ;
2015-04-07 01:15:29 +03:00
_webpageDescriptionOptions . maxw = st : : msgMaxWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) - st : : webPageLeft ;
2015-04-04 23:01:34 +03:00
_webpageDescriptionOptions . maxh = st : : webPageDescriptionFont - > height * 3 ;
2014-05-30 12:53:19 +04:00
}
2014-10-10 16:46:20 +04:00
AnimatedGif animated ;
2015-03-19 12:18:19 +03:00
inline HistoryReply * toHistoryReply ( HistoryItem * item ) {
return item ? item - > toHistoryReply ( ) : 0 ;
}
inline const HistoryReply * toHistoryReply ( const HistoryItem * item ) {
return item ? item - > toHistoryReply ( ) : 0 ;
}
2015-04-23 18:50:11 +03:00
inline HistoryForwarded * toHistoryForwarded ( HistoryItem * item ) {
return item ? item - > toHistoryForwarded ( ) : 0 ;
}
inline const HistoryForwarded * toHistoryForwarded ( const HistoryItem * item ) {
return item ? item - > toHistoryForwarded ( ) : 0 ;
}
2015-06-15 20:19:24 +03:00
inline const TextParseOptions & itemTextParseOptions ( HistoryItem * item ) {
History * h = item - > history ( ) ;
UserData * f = item - > from ( ) ;
if ( ( ! h - > peer - > chat & & h - > peer - > asUser ( ) - > botInfo ) | | ( ! f - > chat & & f - > asUser ( ) - > botInfo ) | | ( h - > peer - > chat & & h - > peer - > asChat ( ) - > botStatus > = 0 ) ) {
return _historyBotOptions ;
}
return _historyTextOptions ;
}
2014-05-30 12:53:19 +04:00
}
void historyInit ( ) {
_initTextOptions ( ) ;
}
2014-10-10 16:46:20 +04:00
void startGif ( HistoryItem * row , const QString & file ) {
if ( row = = animated . msg ) {
stopGif ( ) ;
} else {
animated . start ( row , file ) ;
}
}
void itemReplacedGif ( HistoryItem * oldItem , HistoryItem * newItem ) {
if ( oldItem = = animated . msg ) {
animated . msg = newItem ;
}
}
void itemRemovedGif ( HistoryItem * item ) {
if ( item = = animated . msg ) {
animated . stop ( true ) ;
}
}
void stopGif ( ) {
animated . stop ( ) ;
}
2014-05-30 12:53:19 +04:00
void DialogRow : : paint ( QPainter & p , int32 w , bool act , bool sel ) const {
QRect fullRect ( 0 , 0 , w , st : : dlgHeight ) ;
p . fillRect ( fullRect , ( act ? st : : dlgActiveBG : ( sel ? st : : dlgHoverBG : st : : dlgBG ) ) - > b ) ;
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > photo - > pix ( st : : dlgPhotoSize ) ) ;
int32 nameleft = st : : dlgPaddingHor + st : : dlgPhotoSize + st : : dlgPhotoPadding ;
int32 namewidth = w - nameleft - st : : dlgPaddingHor ;
QRect rectForName ( nameleft , st : : dlgPaddingVer + st : : dlgNameTop , namewidth , st : : msgNameFont - > height ) ;
// draw chat icon
if ( history - > peer - > chat ) {
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChatImgLeft , rectForName . top ( ) + st : : dlgChatImgTop ) , App : : sprite ( ) , ( act ? st : : dlgActiveChatImg : st : : dlgChatImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgChatImgSkip ) ;
}
2015-06-15 20:19:24 +03:00
HistoryItem * last = history - > lastMsg ;
2014-07-04 15:12:54 +04:00
if ( ! last ) {
2014-05-30 12:53:19 +04:00
p . setFont ( st : : dlgHistFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
if ( history - > typing . isEmpty ( ) ) {
p . drawText ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgFont - > ascent + st : : dlgSep , lang ( lng_empty_history ) ) ;
} else {
history - > typingText . drawElided ( p , nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , namewidth ) ;
}
} else {
// draw date
QDateTime now ( QDateTime : : currentDateTime ( ) ) , lastTime ( last - > date ) ;
QDate nowDate ( now . date ( ) ) , lastDate ( lastTime . date ( ) ) ;
QString dt ;
if ( lastDate = = nowDate ) {
2015-02-10 18:55:04 +00:00
dt = lastTime . toString ( cTimeFormat ( ) ) ;
2014-05-30 12:53:19 +04:00
} else if ( lastDate . year ( ) = = nowDate . year ( ) & & lastDate . weekNumber ( ) = = nowDate . weekNumber ( ) ) {
dt = langDayOfWeek ( lastDate ) ;
} else {
dt = lastDate . toString ( qsl ( " d.MM.yy " ) ) ;
}
int32 dtWidth = st : : dlgDateFont - > m . width ( dt ) ;
rectForName . setWidth ( rectForName . width ( ) - dtWidth - st : : dlgDateSkip ) ;
p . setFont ( st : : dlgDateFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveDateColor : st : : dlgDateColor ) - > p ) ;
p . drawText ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgDateSkip , rectForName . top ( ) + st : : msgNameFont - > height - st : : msgDateFont - > descent , dt ) ;
// draw check
if ( last - > out ( ) & & last - > needCheck ( ) ) {
2014-06-25 11:25:55 +04:00
const style : : sprite * check ;
2014-05-30 12:53:19 +04:00
if ( last - > id > 0 ) {
if ( last - > unread ( ) ) {
check = act ? & st : : dlgActiveCheckImg : & st : : dlgCheckImg ;
} else {
check = act ? & st : : dlgActiveDblCheckImg : & st : : dlgDblCheckImg ;
}
} else {
check = act ? & st : : dlgActiveSendImg : & st : : dlgSendImg ;
}
2014-06-25 11:25:55 +04:00
rectForName . setWidth ( rectForName . width ( ) - check - > pxWidth ( ) - st : : dlgCheckSkip ) ;
2014-05-30 12:53:19 +04:00
p . drawPixmap ( QPoint ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgCheckLeft , rectForName . top ( ) + st : : dlgCheckTop ) , App : : sprite ( ) , * check ) ;
}
// draw unread
int32 lastWidth = namewidth , unread = history - > unreadCount ;
if ( unread ) {
QString unreadStr = QString : : number ( unread ) ;
int32 unreadWidth = st : : dlgUnreadFont - > m . width ( unreadStr ) ;
int32 unreadRectWidth = unreadWidth + 2 * st : : dlgUnreadPaddingHor ;
int32 unreadRectHeight = st : : dlgUnreadFont - > height + 2 * st : : dlgUnreadPaddingVer ;
int32 unreadRectLeft = w - st : : dlgPaddingHor - unreadRectWidth ;
int32 unreadRectTop = st : : dlgHeight - st : : dlgPaddingVer - unreadRectHeight ;
lastWidth - = unreadRectWidth + st : : dlgUnreadPaddingHor ;
2015-04-30 16:53:36 +03:00
p . setBrush ( ( act ? st : : dlgActiveUnreadBG : ( history - > mute ? st : : dlgUnreadMutedBG : st : : dlgUnreadBG ) ) - > b ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( Qt : : NoPen ) ;
p . drawRoundedRect ( unreadRectLeft , unreadRectTop , unreadRectWidth , unreadRectHeight , st : : dlgUnreadRadius , st : : dlgUnreadRadius ) ;
p . setFont ( st : : dlgUnreadFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveUnreadColor : st : : dlgUnreadColor ) - > p ) ;
p . drawText ( unreadRectLeft + st : : dlgUnreadPaddingHor , unreadRectTop + st : : dlgUnreadPaddingVer + st : : dlgUnreadFont - > ascent , unreadStr ) ;
}
if ( history - > typing . isEmpty ( ) ) {
last - > drawInDialog ( p , QRect ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth , st : : dlgFont - > height ) , act , history - > textCachedFor , history - > lastItemTextCache ) ;
} else {
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
history - > typingText . drawElided ( p , nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth ) ;
}
}
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgNameColor ) - > p ) ;
history - > nameText . drawElided ( p , rectForName . left ( ) , rectForName . top ( ) , rectForName . width ( ) ) ;
}
2014-07-04 15:12:54 +04:00
void FakeDialogRow : : paint ( QPainter & p , int32 w , bool act , bool sel ) const {
QRect fullRect ( 0 , 0 , w , st : : dlgHeight ) ;
p . fillRect ( fullRect , ( act ? st : : dlgActiveBG : ( sel ? st : : dlgHoverBG : st : : dlgBG ) ) - > b ) ;
History * history = _item - > history ( ) ;
p . drawPixmap ( st : : dlgPaddingHor , st : : dlgPaddingVer , history - > peer - > photo - > pix ( st : : dlgPhotoSize ) ) ;
int32 nameleft = st : : dlgPaddingHor + st : : dlgPhotoSize + st : : dlgPhotoPadding ;
int32 namewidth = w - nameleft - st : : dlgPaddingHor ;
QRect rectForName ( nameleft , st : : dlgPaddingVer + st : : dlgNameTop , namewidth , st : : msgNameFont - > height ) ;
// draw chat icon
if ( history - > peer - > chat ) {
p . drawPixmap ( QPoint ( rectForName . left ( ) + st : : dlgChatImgLeft , rectForName . top ( ) + st : : dlgChatImgTop ) , App : : sprite ( ) , ( act ? st : : dlgActiveChatImg : st : : dlgChatImg ) ) ;
rectForName . setLeft ( rectForName . left ( ) + st : : dlgChatImgSkip ) ;
}
// draw date
QDateTime now ( QDateTime : : currentDateTime ( ) ) , lastTime ( _item - > date ) ;
QDate nowDate ( now . date ( ) ) , lastDate ( lastTime . date ( ) ) ;
QString dt ;
if ( lastDate = = nowDate ) {
2015-02-10 18:55:04 +00:00
dt = lastTime . toString ( cTimeFormat ( ) ) ;
2014-07-04 15:12:54 +04:00
} else if ( lastDate . year ( ) = = nowDate . year ( ) & & lastDate . weekNumber ( ) = = nowDate . weekNumber ( ) ) {
dt = langDayOfWeek ( lastDate ) ;
} else {
dt = lastDate . toString ( qsl ( " d.MM.yy " ) ) ;
}
int32 dtWidth = st : : dlgDateFont - > m . width ( dt ) ;
rectForName . setWidth ( rectForName . width ( ) - dtWidth - st : : dlgDateSkip ) ;
p . setFont ( st : : dlgDateFont - > f ) ;
p . setPen ( ( act ? st : : dlgActiveDateColor : st : : dlgDateColor ) - > p ) ;
p . drawText ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgDateSkip , rectForName . top ( ) + st : : msgNameFont - > height - st : : msgDateFont - > descent , dt ) ;
// draw check
if ( _item - > out ( ) & & _item - > needCheck ( ) ) {
const style : : sprite * check ;
if ( _item - > id > 0 ) {
if ( _item - > unread ( ) ) {
check = act ? & st : : dlgActiveCheckImg : & st : : dlgCheckImg ;
} else {
check = act ? & st : : dlgActiveDblCheckImg : & st : : dlgDblCheckImg ;
}
} else {
check = act ? & st : : dlgActiveSendImg : & st : : dlgSendImg ;
}
rectForName . setWidth ( rectForName . width ( ) - check - > pxWidth ( ) - st : : dlgCheckSkip ) ;
p . drawPixmap ( QPoint ( rectForName . left ( ) + rectForName . width ( ) + st : : dlgCheckLeft , rectForName . top ( ) + st : : dlgCheckTop ) , App : : sprite ( ) , * check ) ;
}
// draw unread
int32 lastWidth = namewidth , unread = history - > unreadCount ;
_item - > drawInDialog ( p , QRect ( nameleft , st : : dlgPaddingVer + st : : dlgFont - > height + st : : dlgSep , lastWidth , st : : dlgFont - > height ) , act , _cacheFor , _cache ) ;
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgNameColor ) - > p ) ;
history - > nameText . drawElided ( p , rectForName . left ( ) , rectForName . top ( ) , rectForName . width ( ) ) ;
}
2014-06-16 13:31:10 +04:00
History : : History ( const PeerId & peerId ) : width ( 0 ) , height ( 0 )
, msgCount ( 0 )
, unreadCount ( 0 )
, inboxReadTill ( 0 )
, outboxReadTill ( 0 )
, showFrom ( 0 )
, unreadBar ( 0 )
, peer ( App : : peer ( peerId ) )
2014-07-04 15:12:54 +04:00
, oldLoaded ( false )
, newLoaded ( true )
2015-06-15 20:19:24 +03:00
, lastMsg ( 0 )
2015-03-19 14:24:23 +03:00
, draftToId ( 0 )
2014-06-16 13:31:10 +04:00
, lastWidth ( 0 )
, lastScrollTop ( History : : ScrollMax )
2015-07-17 22:17:37 +03:00
, lastShowAtMsgId ( ShowAtUnreadMsgId )
2014-06-16 13:31:10 +04:00
, mute ( isNotifyMuted ( peer - > notify ) )
2015-06-17 22:43:03 +03:00
, lastKeyboardInited ( false )
, lastKeyboardUsed ( false )
2015-06-15 20:36:16 +03:00
, lastKeyboardId ( 0 )
, lastKeyboardFrom ( 0 )
2014-11-05 20:43:32 +03:00
, sendRequestId ( 0 )
2014-06-16 13:31:10 +04:00
, textCachedFor ( 0 )
, lastItemTextCache ( st : : dlgRichMinWidth )
, posInDialogs ( 0 )
, typingText ( st : : dlgRichMinWidth )
, myTyping ( 0 )
{
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
_overviewCount [ i ] = - 1 ; // not loaded yet
}
2014-05-30 12:53:19 +04:00
}
2015-06-24 20:24:48 +03:00
void History : : clearLastKeyboard ( ) {
lastKeyboardInited = true ;
lastKeyboardId = 0 ;
lastKeyboardFrom = 0 ;
}
2014-05-30 12:53:19 +04:00
void History : : updateNameText ( ) {
nameText . setText ( st : : msgNameFont , peer - > nameOrPhone . isEmpty ( ) ? peer - > name : peer - > nameOrPhone , _textNameOptions ) ;
}
bool History : : updateTyping ( uint64 ms , uint32 dots , bool force ) {
2014-11-12 23:30:26 +03:00
if ( ! ms ) ms = getms ( true ) ;
2014-05-30 12:53:19 +04:00
bool changed = force ;
for ( TypingUsers : : iterator i = typing . begin ( ) , e = typing . end ( ) ; i ! = e ; ) {
if ( ms > = i . value ( ) ) {
i = typing . erase ( i ) ;
changed = true ;
} else {
+ + i ;
}
}
if ( changed ) {
QString newTypingStr ;
int32 cnt = typing . size ( ) ;
if ( cnt > 2 ) {
2014-12-18 21:40:49 +03:00
newTypingStr = lng_many_typing ( lt_count , cnt ) ;
2014-05-30 12:53:19 +04:00
} else if ( cnt > 1 ) {
2014-12-18 21:40:49 +03:00
newTypingStr = lng_users_typing ( lt_user , typing . begin ( ) . key ( ) - > firstName , lt_second_user , ( typing . end ( ) - 1 ) . key ( ) - > firstName ) ;
2014-05-30 12:53:19 +04:00
} else if ( cnt ) {
2014-12-18 21:40:49 +03:00
newTypingStr = peer - > chat ? lng_user_typing ( lt_user , typing . begin ( ) . key ( ) - > firstName ) : lang ( lng_typing ) ;
2014-05-30 12:53:19 +04:00
}
if ( ! newTypingStr . isEmpty ( ) ) {
newTypingStr + = qsl ( " ... " ) ;
}
if ( typingStr ! = newTypingStr ) {
typingText . setText ( st : : dlgHistFont , ( typingStr = newTypingStr ) , _textNameOptions ) ;
}
}
if ( ! typingStr . isEmpty ( ) ) {
if ( typingText . lastDots ( dots % 4 ) ) {
changed = true ;
}
}
return changed ;
}
2015-07-03 11:47:16 +03:00
void History : : eraseFromOverview ( MediaOverviewType type , MsgId msgId ) {
if ( _overviewIds [ type ] . isEmpty ( ) ) return ;
History : : MediaOverviewIds : : iterator i = _overviewIds [ type ] . find ( msgId ) ;
if ( i = = _overviewIds [ type ] . cend ( ) ) return ;
_overviewIds [ type ] . erase ( i ) ;
for ( History : : MediaOverview : : iterator i = _overview [ type ] . begin ( ) , e = _overview [ type ] . end ( ) ; i ! = e ; + + i ) {
if ( ( * i ) = = msgId ) {
_overview [ type ] . erase ( i ) ;
if ( _overviewCount [ type ] > 0 ) {
- - _overviewCount [ type ] ;
if ( ! _overviewCount [ type ] ) {
_overviewCount [ type ] = - 1 ;
}
}
break ;
}
}
if ( App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , type ) ;
}
2014-05-30 12:53:19 +04:00
bool DialogsList : : del ( const PeerId & peerId , DialogRow * replacedBy ) {
RowByPeer : : iterator i = rowByPeer . find ( peerId ) ;
if ( i = = rowByPeer . cend ( ) ) return false ;
DialogRow * row = i . value ( ) ;
emit App : : main ( ) - > dialogRowReplaced ( row , replacedBy ) ;
if ( row = = current ) {
current = row - > next ;
}
for ( DialogRow * change = row - > next ; change ! = end ; change = change - > next ) {
change - > pos - - ;
}
end - > pos - - ;
remove ( row ) ;
delete row ;
- - count ;
rowByPeer . erase ( i ) ;
return true ;
}
void DialogsIndexed : : peerNameChanged ( PeerData * peer , const PeerData : : Names & oldNames , const PeerData : : NameFirstChars & oldChars ) {
2015-06-15 20:19:24 +03:00
if ( sortMode = = DialogsSortByName ) {
2014-05-30 12:53:19 +04:00
DialogRow * mainRow = list . adjustByName ( peer ) ;
if ( ! mainRow ) return ;
History * history = mainRow - > history ;
PeerData : : NameFirstChars toRemove = oldChars , toAdd ;
for ( PeerData : : NameFirstChars : : const_iterator i = peer - > chars . cbegin ( ) , e = peer - > chars . cend ( ) ; i ! = e ; + + i ) {
PeerData : : NameFirstChars : : iterator j = toRemove . find ( * i ) ;
if ( j = = toRemove . cend ( ) ) {
toAdd . insert ( * i ) ;
} else {
toRemove . erase ( j ) ;
DialogsIndex : : iterator k = index . find ( * i ) ;
if ( k ! = index . cend ( ) ) {
k . value ( ) - > adjustByName ( peer ) ;
}
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toRemove . cbegin ( ) , e = toRemove . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j ! = index . cend ( ) ) {
j . value ( ) - > del ( peer - > id , mainRow ) ;
}
}
if ( ! toAdd . isEmpty ( ) ) {
for ( PeerData : : NameFirstChars : : const_iterator i = toAdd . cbegin ( ) , e = toAdd . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j = = index . cend ( ) ) {
2015-06-15 20:19:24 +03:00
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
2014-05-30 12:53:19 +04:00
}
j . value ( ) - > addByName ( history ) ;
}
}
} else {
DialogsList : : RowByPeer : : const_iterator i = list . rowByPeer . find ( peer - > id ) ;
if ( i = = list . rowByPeer . cend ( ) ) return ;
DialogRow * mainRow = i . value ( ) ;
History * history = mainRow - > history ;
PeerData : : NameFirstChars toRemove = oldChars , toAdd ;
for ( PeerData : : NameFirstChars : : const_iterator i = peer - > chars . cbegin ( ) , e = peer - > chars . cend ( ) ; i ! = e ; + + i ) {
PeerData : : NameFirstChars : : iterator j = toRemove . find ( * i ) ;
if ( j = = toRemove . cend ( ) ) {
toAdd . insert ( * i ) ;
} else {
toRemove . erase ( j ) ;
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toRemove . cbegin ( ) , e = toRemove . cend ( ) ; i ! = e ; + + i ) {
2015-06-15 20:19:24 +03:00
if ( sortMode = = DialogsSortByDate ) history - > dialogs . remove ( * i ) ;
2014-05-30 12:53:19 +04:00
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j ! = index . cend ( ) ) {
j . value ( ) - > del ( peer - > id , mainRow ) ;
}
}
for ( PeerData : : NameFirstChars : : const_iterator i = toAdd . cbegin ( ) , e = toAdd . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j = = index . cend ( ) ) {
2015-06-15 20:19:24 +03:00
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
}
if ( sortMode = = DialogsSortByDate ) {
history - > dialogs . insert ( * i , j . value ( ) - > addByPos ( history ) ) ;
} else {
j . value ( ) - > addToEnd ( history ) ;
2014-05-30 12:53:19 +04:00
}
}
}
}
void DialogsIndexed : : clear ( ) {
for ( DialogsIndex : : iterator i = index . begin ( ) , e = index . end ( ) ; i ! = e ; + + i ) {
delete i . value ( ) ;
}
index . clear ( ) ;
list . clear ( ) ;
}
void Histories : : clear ( ) {
App : : historyClearMsgs ( ) ;
for ( Parent : : const_iterator i = cbegin ( ) , e = cend ( ) ; i ! = e ; + + i ) {
delete i . value ( ) ;
}
App : : historyClearItems ( ) ;
typing . clear ( ) ;
Parent : : clear ( ) ;
}
2014-12-12 19:27:03 +03:00
void Histories : : regTyping ( History * history , UserData * user ) {
uint64 ms = getms ( true ) ;
history - > typing [ user ] = ms + 6000 ;
2015-06-10 15:48:26 +03:00
user - > madeAction ( ) ;
2014-12-12 19:27:03 +03:00
TypingHistories : : const_iterator i = typing . find ( history ) ;
if ( i = = typing . cend ( ) ) {
typing . insert ( history , ms ) ;
history - > typingFrame = 0 ;
}
history - > updateTyping ( ms , history - > typingFrame , true ) ;
anim : : start ( this ) ;
}
bool Histories : : animStep ( float64 ) {
uint64 ms = getms ( true ) ;
for ( TypingHistories : : iterator i = typing . begin ( ) , e = typing . end ( ) ; i ! = e ; ) {
uint32 typingFrame = ( ms - i . value ( ) ) / 150 ;
if ( i . key ( ) - > updateTyping ( ms , typingFrame ) ) {
App : : main ( ) - > dlgUpdated ( i . key ( ) ) ;
App : : main ( ) - > topBar ( ) - > update ( ) ;
}
if ( i . key ( ) - > typing . isEmpty ( ) ) {
i = typing . erase ( i ) ;
} else {
+ + i ;
}
}
return ! typing . isEmpty ( ) ;
}
2014-05-30 12:53:19 +04:00
Histories : : Parent : : iterator Histories : : erase ( Histories : : Parent : : iterator i ) {
2015-04-04 23:01:34 +03:00
typing . remove ( i . value ( ) ) ;
2014-05-30 12:53:19 +04:00
delete i . value ( ) ;
return Parent : : erase ( i ) ;
}
2014-12-18 21:40:49 +03:00
void Histories : : remove ( const PeerId & peer ) {
iterator i = find ( peer ) ;
if ( i ! = cend ( ) ) {
erase ( i ) ;
}
2015-04-04 23:01:34 +03:00
2014-12-18 21:40:49 +03:00
}
2014-07-04 15:12:54 +04:00
HistoryItem * Histories : : addToBack ( const MTPmessage & msg , int msgState ) {
2014-05-30 12:53:19 +04:00
PeerId from_id = 0 , to_id = 0 ;
switch ( msg . type ( ) ) {
case mtpc_message :
from_id = App : : peerFromUser ( msg . c_message ( ) . vfrom_id ) ;
to_id = App : : peerFromMTP ( msg . c_message ( ) . vto_id ) ;
break ;
case mtpc_messageService :
from_id = App : : peerFromUser ( msg . c_messageService ( ) . vfrom_id ) ;
to_id = App : : peerFromMTP ( msg . c_messageService ( ) . vto_id ) ;
break ;
}
PeerId peer = ( to_id = = App : : peerFromUser ( MTP : : authedId ( ) ) ) ? from_id : to_id ;
if ( ! peer ) return 0 ;
iterator h = find ( peer ) ;
if ( h = = end ( ) ) {
h = insert ( peer , new History ( peer ) ) ;
}
2014-07-04 15:12:54 +04:00
if ( msgState < 0 ) {
return h . value ( ) - > addToHistory ( msg ) ;
}
if ( ! h . value ( ) - > loadedAtBottom ( ) ) {
HistoryItem * item = h . value ( ) - > addToHistory ( msg ) ;
if ( item ) {
2015-06-15 20:19:24 +03:00
h . value ( ) - > lastMsg = item ;
2014-07-04 15:12:54 +04:00
if ( msgState > 0 ) {
h . value ( ) - > newItemAdded ( item ) ;
}
}
return item ;
}
return h . value ( ) - > addToBack ( msg , msgState > 0 ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
HistoryItem * History : : createItem ( HistoryBlock * block , const MTPmessage & msg , bool newMsg , bool returnExisting ) {
2014-05-30 12:53:19 +04:00
HistoryItem * result = 0 ;
2015-04-30 16:53:36 +03:00
MsgId msgId = 0 ;
switch ( msg . type ( ) ) {
case mtpc_messageEmpty : msgId = msg . c_messageEmpty ( ) . vid . v ; break ;
case mtpc_message : msgId = msg . c_message ( ) . vid . v ; break ;
case mtpc_messageService : msgId = msg . c_messageService ( ) . vid . v ; break ;
}
HistoryItem * existing = App : : histItemById ( msgId ) ;
if ( existing ) {
2015-05-01 02:05:19 +03:00
bool regged = false ;
if ( existing - > detached ( ) & & block ) {
existing - > attach ( block ) ;
regged = true ;
}
2015-04-30 16:53:36 +03:00
const MTPMessageMedia * media = 0 ;
switch ( msg . type ( ) ) {
case mtpc_message : media = & msg . c_message ( ) . vmedia ; break ;
}
if ( media ) {
existing - > updateMedia ( * media ) ;
}
2015-05-01 02:05:19 +03:00
return ( returnExisting | | regged ) ? existing : 0 ;
2015-04-30 16:53:36 +03:00
}
2014-05-30 12:53:19 +04:00
switch ( msg . type ( ) ) {
case mtpc_messageEmpty :
result = new HistoryServiceMsg ( this , block , msg . c_messageEmpty ( ) . vid . v , date ( ) , lang ( lng_message_empty ) ) ;
break ;
2015-07-15 14:23:59 +03:00
case mtpc_message : {
const MTPDmessage m ( msg . c_message ( ) ) ;
int badMedia = 0 ; // 1 - unsupported, 2 - empty
switch ( m . vmedia . type ( ) ) {
case mtpc_messageMediaEmpty : break ;
case mtpc_messageMediaGeo :
switch ( m . vmedia . c_messageMediaGeo ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
case mtpc_geoPointEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaVenue :
switch ( m . vmedia . c_messageMediaVenue ( ) . vgeo . type ( ) ) {
case mtpc_geoPoint : break ;
case mtpc_geoPointEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaPhoto :
switch ( m . vmedia . c_messageMediaPhoto ( ) . vphoto . type ( ) ) {
case mtpc_photo : break ;
case mtpc_photoEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaVideo :
switch ( m . vmedia . c_messageMediaVideo ( ) . vvideo . type ( ) ) {
case mtpc_video : break ;
case mtpc_videoEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaAudio :
switch ( m . vmedia . c_messageMediaAudio ( ) . vaudio . type ( ) ) {
case mtpc_audio : break ;
case mtpc_audioEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaDocument :
switch ( m . vmedia . c_messageMediaDocument ( ) . vdocument . type ( ) ) {
case mtpc_document : break ;
case mtpc_documentEmpty : badMedia = 2 ; break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaWebPage :
switch ( m . vmedia . c_messageMediaWebPage ( ) . vwebpage . type ( ) ) {
case mtpc_webPage :
case mtpc_webPageEmpty :
case mtpc_webPagePending : break ;
default : badMedia = 1 ; break ;
}
break ;
case mtpc_messageMediaUnsupported :
default : badMedia = 1 ; break ;
2015-03-13 16:01:25 +03:00
}
2015-07-15 14:23:59 +03:00
if ( badMedia ) {
result = new HistoryServiceMsg ( this , block , m . vid . v , date ( m . vdate ) , lang ( ( badMedia = = 2 ) ? lng_message_empty : lng_media_unsupported ) , m . vflags . v , 0 , m . vfrom_id . v ) ;
} else {
if ( ( m . has_fwd_date ( ) & & m . vfwd_date . v > 0 ) | | ( m . has_fwd_from_id ( ) & & m . vfwd_from_id . v ! = 0 ) ) {
result = new HistoryForwarded ( this , block , m ) ;
} else if ( m . has_reply_to_msg_id ( ) & & m . vreply_to_msg_id . v > 0 ) {
result = new HistoryReply ( this , block , m ) ;
} else {
result = new HistoryMessage ( this , block , m ) ;
}
if ( m . has_reply_markup ( ) ) {
App : : feedReplyMarkup ( msgId , m . vreply_markup ) ;
}
2015-06-15 20:19:24 +03:00
}
2015-07-15 14:23:59 +03:00
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageService : {
const MTPDmessageService & d ( msg . c_messageService ( ) ) ;
result = new HistoryServiceMsg ( this , block , d ) ;
if ( newMsg ) {
const MTPmessageAction & action ( d . vaction ) ;
switch ( d . vaction . type ( ) ) {
case mtpc_messageActionChatAddUser : {
const MTPDmessageActionChatAddUser & d ( action . c_messageActionChatAddUser ( ) ) ;
// App::user(App::peerFromUser(d.vuser_id)); added
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageActionChatJoinedByLink : {
const MTPDmessageActionChatJoinedByLink & d ( action . c_messageActionChatJoinedByLink ( ) ) ;
// App::user(App::peerFromUser(d.vuser_id)); added
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageActionChatDeletePhoto : {
ChatData * chat = peer - > asChat ( ) ;
if ( chat ) chat - > setPhoto ( MTP_chatPhotoEmpty ( ) ) ;
} break ;
case mtpc_messageActionChatDeleteUser : {
const MTPDmessageActionChatDeleteUser & d ( action . c_messageActionChatDeleteUser ( ) ) ;
2015-06-18 20:24:54 +03:00
if ( lastKeyboardFrom = = App : : peerFromUser ( d . vuser_id ) ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-18 20:24:54 +03:00
}
2014-05-30 12:53:19 +04:00
// App::peer(App::peerFromUser(d.vuser_id)); left
} break ;
case mtpc_messageActionChatEditPhoto : {
const MTPDmessageActionChatEditPhoto & d ( action . c_messageActionChatEditPhoto ( ) ) ;
if ( d . vphoto . type ( ) = = mtpc_photo ) {
const QVector < MTPPhotoSize > & sizes ( d . vphoto . c_photo ( ) . vsizes . c_vector ( ) . v ) ;
if ( ! sizes . isEmpty ( ) ) {
ChatData * chat = peer - > asChat ( ) ;
if ( chat ) {
PhotoData * photo = App : : feedPhoto ( d . vphoto . c_photo ( ) ) ;
if ( photo ) photo - > chat = chat ;
const MTPPhotoSize & smallSize ( sizes . front ( ) ) , & bigSize ( sizes . back ( ) ) ;
const MTPFileLocation * smallLoc = 0 , * bigLoc = 0 ;
switch ( smallSize . type ( ) ) {
case mtpc_photoSize : smallLoc = & smallSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : smallLoc = & smallSize . c_photoCachedSize ( ) . vlocation ; break ;
}
switch ( bigSize . type ( ) ) {
case mtpc_photoSize : bigLoc = & bigSize . c_photoSize ( ) . vlocation ; break ;
case mtpc_photoCachedSize : bigLoc = & bigSize . c_photoCachedSize ( ) . vlocation ; break ;
}
if ( smallLoc & & bigLoc ) {
chat - > setPhoto ( MTP_chatPhoto ( * smallLoc , * bigLoc ) , photo ? photo - > id : 0 ) ;
chat - > photo - > load ( ) ;
}
}
}
}
} break ;
case mtpc_messageActionChatEditTitle : {
const MTPDmessageActionChatEditTitle & d ( action . c_messageActionChatEditTitle ( ) ) ;
ChatData * chat = peer - > asChat ( ) ;
2014-11-15 02:23:35 +03:00
if ( chat ) chat - > updateName ( qs ( d . vtitle ) , QString ( ) , QString ( ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
}
}
} break ;
}
2015-04-30 16:53:36 +03:00
return regItem ( result , returnExisting ) ;
2014-05-30 12:53:19 +04:00
}
HistoryItem * History : : createItemForwarded ( HistoryBlock * block , MsgId id , HistoryMessage * msg ) {
HistoryItem * result = 0 ;
result = new HistoryForwarded ( this , block , id , msg ) ;
return regItem ( result ) ;
}
2015-03-19 12:18:19 +03:00
HistoryItem * History : : createItemDocument ( HistoryBlock * block , MsgId id , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc ) {
2014-05-30 12:53:19 +04:00
HistoryItem * result = 0 ;
2015-03-19 12:18:19 +03:00
if ( flags & MTPDmessage : : flag_reply_to_msg_id & & replyTo > 0 ) {
result = new HistoryReply ( this , block , id , flags , replyTo , date , from , doc ) ;
} else {
result = new HistoryMessage ( this , block , id , flags , date , from , doc ) ;
}
2014-05-30 12:53:19 +04:00
return regItem ( result ) ;
}
2015-01-02 17:55:24 +03:00
2015-03-19 12:18:19 +03:00
HistoryItem * History : : addToBackService ( MsgId msgId , QDateTime date , const QString & text , int32 flags , HistoryMedia * media , bool newMsg ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
bool newBlock = isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
to = back ( ) ;
}
2015-03-19 12:18:19 +03:00
return doAddToBack ( to , newBlock , regItem ( new HistoryServiceMsg ( this , to , msgId , date , text , flags , media ) ) , newMsg ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
HistoryItem * History : : addToBack ( const MTPmessage & msg , bool newMsg ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
bool newBlock = isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
to = back ( ) ;
}
2014-07-04 15:12:54 +04:00
return doAddToBack ( to , newBlock , createItem ( to , msg , newMsg ) , newMsg ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
HistoryItem * History : : addToHistory ( const MTPmessage & msg ) {
return createItem ( 0 , msg , false , true ) ;
}
HistoryItem * History : : addToBackForwarded ( MsgId id , HistoryMessage * item ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
bool newBlock = isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
to = back ( ) ;
}
2014-07-04 15:12:54 +04:00
return doAddToBack ( to , newBlock , createItemForwarded ( to , id , item ) , true ) ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
HistoryItem * History : : addToBackDocument ( MsgId id , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc ) {
2014-05-30 12:53:19 +04:00
HistoryBlock * to = 0 ;
bool newBlock = isEmpty ( ) ;
if ( newBlock ) {
to = new HistoryBlock ( this ) ;
} else {
to = back ( ) ;
}
2015-03-19 12:18:19 +03:00
return doAddToBack ( to , newBlock , createItemDocument ( to , id , flags , replyTo , date , from , doc ) , true ) ;
2014-05-30 12:53:19 +04:00
}
void History : : createInitialDateBlock ( const QDateTime & date ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ; // date block
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , date ) ;
dateBlock - > push_back ( dayItem ) ;
if ( width ) {
int32 dh = dayItem - > resize ( width ) ;
dateBlock - > height = dh ;
height + = dh ;
for ( int32 i = 0 , l = size ( ) ; i < l ; + + i ) {
( * this ) [ i ] - > y + = dh ;
}
}
push_front ( dateBlock ) ; // date block
}
2014-07-04 15:12:54 +04:00
HistoryItem * History : : doAddToBack ( HistoryBlock * to , bool newBlock , HistoryItem * adding , bool newMsg ) {
2014-05-30 12:53:19 +04:00
if ( ! adding ) {
if ( newBlock ) delete to ;
2014-07-04 15:12:54 +04:00
return adding ;
2014-05-30 12:53:19 +04:00
}
if ( newBlock ) {
createInitialDateBlock ( adding - > date ) ;
to - > y = height ;
push_back ( to ) ;
} else if ( to - > back ( ) - > date . date ( ) ! = adding - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , to , adding - > date ) ;
to - > push_back ( dayItem ) ;
dayItem - > y = to - > height ;
if ( width ) {
int32 dh = dayItem - > resize ( width ) ;
to - > height + = dh ;
height + = dh ;
}
}
to - > push_back ( adding ) ;
2015-06-15 20:19:24 +03:00
lastMsg = adding ;
2014-05-30 12:53:19 +04:00
adding - > y = to - > height ;
if ( width ) {
int32 dh = adding - > resize ( width ) ;
to - > height + = dh ;
height + = dh ;
}
setMsgCount ( msgCount + 1 ) ;
if ( newMsg ) {
2014-07-04 15:12:54 +04:00
newItemAdded ( adding ) ;
}
2014-08-11 13:03:45 +04:00
HistoryMedia * media = adding - > getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
if ( media ) {
2015-07-03 11:47:16 +03:00
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
2014-08-15 15:19:32 +04:00
if ( t ! = OverviewCount ) {
if ( _overviewIds [ t ] . constFind ( adding - > id ) = = _overviewIds [ t ] . cend ( ) ) {
_overview [ t ] . push_back ( adding - > id ) ;
_overviewIds [ t ] . insert ( adding - > id , NullType ( ) ) ;
if ( _overviewCount [ t ] > 0 ) + + _overviewCount [ t ] ;
2015-07-03 11:47:16 +03:00
if ( App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , t ) ;
}
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > document ( ) - > song ( ) ) {
t = OverviewAudioDocuments ;
if ( _overviewIds [ t ] . constFind ( adding - > id ) = = _overviewIds [ t ] . cend ( ) ) {
_overview [ t ] . push_back ( adding - > id ) ;
_overviewIds [ t ] . insert ( adding - > id , NullType ( ) ) ;
if ( _overviewCount [ t ] > 0 ) + + _overviewCount [ t ] ;
if ( App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , t ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
}
2015-06-15 20:19:24 +03:00
if ( adding - > from ( ) - > id ) {
if ( peer - > chat ) {
QList < UserData * > * lastAuthors = & ( peer - > asChat ( ) - > lastAuthors ) ;
int prev = lastAuthors - > indexOf ( adding - > from ( ) ) ;
if ( prev > 0 ) {
lastAuthors - > removeAt ( prev ) ;
}
if ( prev ) {
lastAuthors - > push_front ( adding - > from ( ) ) ;
}
}
if ( adding - > hasReplyMarkup ( ) ) {
2015-06-22 11:51:39 +03:00
int32 markupFlags = App : : replyMarkup ( adding - > id ) . flags ;
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_flag_personal ) | | adding - > notifyByFrom ( ) ) {
if ( peer - > chat ) {
peer - > asChat ( ) - > markupSenders . insert ( adding - > from ( ) , true ) ;
}
if ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) { // zero markup means replyKeyboardHide
if ( lastKeyboardFrom = = adding - > from ( ) - > id | | ( ! lastKeyboardInited & & ! peer - > chat & & ! adding - > out ( ) ) ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
}
} else if ( peer - > chat & & ( peer - > asChat ( ) - > count < 1 | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & ! peer - > asChat ( ) - > participants . contains ( adding - > from ( ) ) ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
} else {
lastKeyboardInited = true ;
lastKeyboardId = adding - > id ;
lastKeyboardFrom = adding - > from ( ) - > id ;
lastKeyboardUsed = false ;
2015-06-17 22:43:03 +03:00
}
}
2015-03-19 12:18:19 +03:00
}
}
2014-07-04 15:12:54 +04:00
return adding ;
}
2014-10-22 22:39:03 +04:00
void History : : unregTyping ( UserData * from ) {
TypingUsers : : iterator i = typing . find ( from ) ;
if ( i ! = typing . end ( ) ) {
2014-11-12 23:30:26 +03:00
uint64 ms = getms ( true ) ;
2014-10-22 22:39:03 +04:00
i . value ( ) = ms ;
updateTyping ( ms , 0 , true ) ;
App : : main ( ) - > topBar ( ) - > update ( ) ;
}
}
2014-07-04 15:12:54 +04:00
void History : : newItemAdded ( HistoryItem * item ) {
App : : checkImageCacheSize ( ) ;
if ( item - > from ( ) ) {
2014-10-22 22:39:03 +04:00
unregTyping ( item - > from ( ) ) ;
2015-06-10 15:48:26 +03:00
item - > from ( ) - > madeAction ( ) ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
if ( item - > out ( ) ) {
if ( unreadBar ) unreadBar - > destroy ( ) ;
} else if ( item - > unread ( ) ) {
notifies . push_back ( item ) ;
2015-03-19 12:18:19 +03:00
App : : main ( ) - > newUnreadMsg ( this , item ) ;
2014-07-04 15:12:54 +04:00
}
if ( dialogs . isEmpty ( ) ) {
App : : main ( ) - > createDialogAtTop ( this , unreadCount ) ;
} else {
emit App : : main ( ) - > dialogToTop ( dialogs ) ;
}
2014-05-30 12:53:19 +04:00
}
void History : : addToFront ( const QVector < MTPMessage > & slice ) {
2014-07-04 15:12:54 +04:00
if ( slice . isEmpty ( ) ) {
oldLoaded = true ;
return ;
}
2014-05-30 12:53:19 +04:00
int32 addToH = 0 , skip = 0 ;
if ( ! isEmpty ( ) ) {
addToH = - front ( ) - > height ;
pop_front ( ) ; // remove date block
}
HistoryItem * till = isEmpty ( ) ? 0 : front ( ) - > front ( ) , * prev = 0 ;
HistoryBlock * block = new HistoryBlock ( this ) ;
block - > reserve ( slice . size ( ) ) ;
int32 wasMsgCount = msgCount ;
for ( QVector < MTPmessage > : : const_iterator i = slice . cend ( ) - 1 , e = slice . cbegin ( ) ; ; - - i ) {
HistoryItem * adding = createItem ( block , * i , false ) ;
if ( adding ) {
if ( prev & & prev - > date . date ( ) ! = adding - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , block , adding - > date ) ;
block - > push_back ( dayItem ) ;
dayItem - > y = block - > height ;
block - > height + = dayItem - > resize ( width ) ;
}
block - > push_back ( adding ) ;
adding - > y = block - > height ;
block - > height + = adding - > resize ( width ) ;
setMsgCount ( msgCount + 1 ) ;
prev = adding ;
}
if ( i = = e ) break ;
}
if ( till & & prev & & prev - > date . date ( ) ! = till - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , block , till - > date ) ;
block - > push_back ( dayItem ) ;
dayItem - > y = block - > height ;
block - > height + = dayItem - > resize ( width ) ;
}
if ( block - > size ( ) ) {
2015-07-17 22:17:37 +03:00
if ( loadedAtBottom ( ) & & wasMsgCount < unreadCount & & msgCount > = unreadCount ) {
2014-05-30 12:53:19 +04:00
for ( int32 i = block - > size ( ) ; i > 0 ; - - i ) {
if ( ( * block ) [ i - 1 ] - > itemType ( ) = = HistoryItem : : MsgType ) {
+ + wasMsgCount ;
if ( wasMsgCount = = unreadCount ) {
showFrom = ( * block ) [ i - 1 ] ;
break ;
}
}
}
}
push_front ( block ) ;
addToH + = block - > height ;
+ + skip ;
2014-08-11 13:03:45 +04:00
2015-03-19 12:18:19 +03:00
if ( loadedAtBottom ( ) ) { // add photos to overview and authors to lastAuthors
2015-07-03 11:47:16 +03:00
int32 mask = 0 ;
2015-03-19 12:18:19 +03:00
QList < UserData * > * lastAuthors = peer - > chat ? & ( peer - > asChat ( ) - > lastAuthors ) : 0 ;
2014-08-11 13:03:45 +04:00
for ( int32 i = block - > size ( ) ; i > 0 ; - - i ) {
HistoryItem * item = ( * block ) [ i - 1 ] ;
HistoryMedia * media = item - > getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
if ( media ) {
2015-07-03 11:47:16 +03:00
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
2014-08-15 15:19:32 +04:00
if ( t ! = OverviewCount ) {
if ( _overviewIds [ t ] . constFind ( item - > id ) = = _overviewIds [ t ] . cend ( ) ) {
_overview [ t ] . push_front ( item - > id ) ;
_overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
2015-07-03 11:47:16 +03:00
mask | = ( 1 < < t ) ;
}
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > document ( ) - > song ( ) ) {
t = OverviewAudioDocuments ;
if ( _overviewIds [ t ] . constFind ( item - > id ) = = _overviewIds [ t ] . cend ( ) ) {
_overview [ t ] . push_front ( item - > id ) ;
_overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
mask | = ( 1 < < t ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
}
2015-06-15 20:19:24 +03:00
if ( item - > from ( ) - > id ) {
2015-06-17 22:43:03 +03:00
if ( lastAuthors ) { // chats
if ( ! lastAuthors - > contains ( item - > from ( ) ) ) {
lastAuthors - > push_back ( item - > from ( ) ) ;
}
if ( ! lastKeyboardInited & & item - > hasReplyMarkup ( ) & & ! item - > out ( ) ) { // chats with bots
2015-06-22 11:51:39 +03:00
int32 markupFlags = App : : replyMarkup ( item - > id ) . flags ;
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_flag_personal ) | | item - > notifyByFrom ( ) ) {
bool wasKeyboardHide = peer - > asChat ( ) - > markupSenders . contains ( item - > from ( ) ) ;
if ( ! wasKeyboardHide ) {
peer - > asChat ( ) - > markupSenders . insert ( item - > from ( ) , true ) ;
}
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) ) {
if ( ! lastKeyboardInited ) {
if ( wasKeyboardHide | | ( ( peer - > asChat ( ) - > count < 1 | | ! peer - > asChat ( ) - > participants . isEmpty ( ) ) & & ! peer - > asChat ( ) - > participants . contains ( item - > from ( ) ) ) ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
} else {
2015-06-24 20:24:48 +03:00
lastKeyboardInited = true ;
2015-06-22 11:51:39 +03:00
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-17 22:43:03 +03:00
}
}
}
}
} else if ( ! lastKeyboardInited & & item - > hasReplyMarkup ( ) & & ! item - > out ( ) ) { // conversations with bots
2015-06-22 11:51:39 +03:00
int32 markupFlags = App : : replyMarkup ( item - > id ) . flags ;
if ( ! ( markupFlags & MTPDreplyKeyboardMarkup_flag_personal ) | | item - > notifyByFrom ( ) ) {
if ( markupFlags & MTPDreplyKeyboardMarkup_flag_ZERO ) {
2015-06-24 20:24:48 +03:00
clearLastKeyboard ( ) ;
2015-06-22 11:51:39 +03:00
} else {
lastKeyboardInited = true ;
lastKeyboardId = item - > id ;
lastKeyboardFrom = item - > from ( ) - > id ;
lastKeyboardUsed = false ;
}
2015-06-15 20:19:24 +03:00
}
}
}
2014-08-11 13:03:45 +04:00
}
2015-07-03 11:47:16 +03:00
for ( int32 t = 0 ; t < OverviewCount ; + + t ) {
if ( ( mask & ( 1 < < t ) ) & & App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( t ) ) ;
}
2014-08-11 13:03:45 +04:00
}
2014-05-30 12:53:19 +04:00
} else {
delete block ;
}
if ( ! isEmpty ( ) ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ;
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , front ( ) - > front ( ) - > date ) ;
dateBlock - > push_back ( dayItem ) ;
int32 dh = dayItem - > resize ( width ) ;
dateBlock - > height = dh ;
if ( skip ) {
front ( ) - > y + = dh ;
}
push_front ( dateBlock ) ; // date block
addToH + = dh ;
+ + skip ;
}
if ( addToH ) {
for ( iterator i = begin ( ) , e = end ( ) ; i ! = e ; + + i ) {
if ( skip ) {
- - skip ;
} else {
( * i ) - > y + = addToH ;
}
}
height + = addToH ;
}
}
2014-07-04 15:12:54 +04:00
void History : : addToBack ( const QVector < MTPMessage > & slice ) {
if ( slice . isEmpty ( ) ) {
newLoaded = true ;
return ;
}
bool wasEmpty = isEmpty ( ) ;
HistoryItem * prev = isEmpty ( ) ? 0 : back ( ) - > back ( ) ;
HistoryBlock * block = new HistoryBlock ( this ) ;
block - > reserve ( slice . size ( ) ) ;
int32 wasMsgCount = msgCount ;
for ( QVector < MTPmessage > : : const_iterator i = slice . cend ( ) , e = slice . cbegin ( ) ; i ! = e ; ) {
- - i ;
HistoryItem * adding = createItem ( block , * i , false ) ;
if ( adding ) {
if ( prev & & prev - > date . date ( ) ! = adding - > date . date ( ) ) {
HistoryItem * dayItem = createDayServiceMsg ( this , block , adding - > date ) ;
prev - > block ( ) - > push_back ( dayItem ) ;
dayItem - > y = prev - > block ( ) - > height ;
prev - > block ( ) - > height + = dayItem - > resize ( width ) ;
if ( prev - > block ( ) ! = block ) {
height + = dayItem - > height ( ) ;
}
}
block - > push_back ( adding ) ;
adding - > y = block - > height ;
block - > height + = adding - > resize ( width ) ;
setMsgCount ( msgCount + 1 ) ;
prev = adding ;
}
if ( i = = e ) break ;
}
2014-08-11 13:03:45 +04:00
bool wasLoadedAtBottom = loadedAtBottom ( ) ;
2014-07-04 15:12:54 +04:00
if ( block - > size ( ) ) {
block - > y = height ;
push_back ( block ) ;
height + = block - > height ;
} else {
newLoaded = true ;
fixLastMessage ( true ) ;
delete block ;
}
2014-08-11 13:03:45 +04:00
if ( ! wasLoadedAtBottom & & loadedAtBottom ( ) ) { // add all loaded photos to overview
2015-07-03 11:47:16 +03:00
int32 mask = 0 ;
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
if ( _overviewCount [ i ] = = 0 ) continue ; // all loaded
2015-07-03 11:47:16 +03:00
if ( ! _overview [ i ] . isEmpty ( ) | | ! _overviewIds [ i ] . isEmpty ( ) ) {
_overview [ i ] . clear ( ) ;
_overviewIds [ i ] . clear ( ) ;
mask | = ( 1 < < i ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
for ( int32 i = 0 ; i < size ( ) ; + + i ) {
HistoryBlock * b = ( * this ) [ i ] ;
for ( int32 j = 0 ; j < b - > size ( ) ; + + j ) {
HistoryItem * item = ( * b ) [ j ] ;
HistoryMedia * media = item - > getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
if ( media ) {
2015-07-03 11:47:16 +03:00
HistoryMediaType mt = media - > type ( ) ;
MediaOverviewType t = mediaToOverviewType ( mt ) ;
if ( t ! = OverviewCount ) {
if ( _overviewCount [ t ] ! = 0 ) {
_overview [ t ] . push_back ( item - > id ) ;
_overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
mask | = ( 1 < < t ) ;
}
if ( mt = = MediaTypeDocument & & static_cast < HistoryDocument * > ( media ) - > document ( ) - > song ( ) ) {
t = OverviewAudioDocuments ;
if ( _overviewCount [ t ] ! = 0 ) {
_overview [ t ] . push_back ( item - > id ) ;
_overviewIds [ t ] . insert ( item - > id , NullType ( ) ) ;
mask | = ( 1 < < t ) ;
}
}
2014-08-15 15:19:32 +04:00
}
2014-08-11 13:03:45 +04:00
}
}
}
2015-07-03 11:47:16 +03:00
for ( int32 t = 0 ; t < OverviewCount ; + + t ) {
if ( ( mask & ( 1 < < t ) ) & & App : : wnd ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( t ) ) ;
}
2014-08-11 13:03:45 +04:00
}
2014-07-04 15:12:54 +04:00
if ( wasEmpty & & ! isEmpty ( ) ) {
HistoryBlock * dateBlock = new HistoryBlock ( this ) ;
HistoryItem * dayItem = createDayServiceMsg ( this , dateBlock , front ( ) - > front ( ) - > date ) ;
dateBlock - > push_back ( dayItem ) ;
int32 dh = dayItem - > resize ( width ) ;
dateBlock - > height = dh ;
for ( iterator i = begin ( ) , e = end ( ) ; i ! = e ; + + i ) {
( * i ) - > y + = dh ;
}
push_front ( dateBlock ) ; // date block
height + = dh ;
}
}
2015-03-13 16:01:25 +03:00
void History : : inboxRead ( int32 upTo ) {
2014-05-30 12:53:19 +04:00
if ( unreadCount ) {
2015-03-13 16:01:25 +03:00
if ( upTo & & loadedAtBottom ( ) ) App : : main ( ) - > historyToDown ( this ) ;
2014-05-30 12:53:19 +04:00
setUnreadCount ( 0 ) ;
}
if ( ! isEmpty ( ) ) {
2015-03-13 16:01:25 +03:00
int32 till = upTo ? upTo : back ( ) - > back ( ) - > id ;
2014-05-30 12:53:19 +04:00
if ( inboxReadTill < till ) inboxReadTill = till ;
}
if ( ! dialogs . isEmpty ( ) ) {
if ( App : : main ( ) ) App : : main ( ) - > dlgUpdated ( dialogs [ 0 ] ) ;
}
2015-07-17 22:17:37 +03:00
showFrom = 0 ;
2014-07-06 07:32:21 +04:00
App : : wnd ( ) - > notifyClear ( this ) ;
2014-07-04 15:12:54 +04:00
clearNotifications ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-03-13 16:01:25 +03:00
void History : : inboxRead ( HistoryItem * wasRead ) {
return inboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
void History : : outboxRead ( int32 upTo ) {
2014-05-30 12:53:19 +04:00
if ( ! isEmpty ( ) ) {
2015-03-13 16:01:25 +03:00
int32 till = upTo ? upTo : back ( ) - > back ( ) - > id ;
2014-05-30 12:53:19 +04:00
if ( outboxReadTill < till ) outboxReadTill = till ;
}
}
2015-03-13 16:01:25 +03:00
void History : : outboxRead ( HistoryItem * wasRead ) {
return outboxRead ( wasRead ? wasRead - > id : 0 ) ;
}
2014-05-30 12:53:19 +04:00
void History : : setUnreadCount ( int32 newUnreadCount , bool psUpdate ) {
if ( unreadCount ! = newUnreadCount ) {
2015-07-17 22:17:37 +03:00
if ( newUnreadCount = = 1 & & loadedAtBottom ( ) ) {
2014-05-30 12:53:19 +04:00
showFrom = isEmpty ( ) ? 0 : back ( ) - > back ( ) ;
} else if ( ! newUnreadCount ) {
showFrom = 0 ;
}
App : : histories ( ) . unreadFull + = newUnreadCount - unreadCount ;
if ( mute ) App : : histories ( ) . unreadMuted + = newUnreadCount - unreadCount ;
unreadCount = newUnreadCount ;
2014-12-15 18:55:45 +03:00
if ( psUpdate ) App : : wnd ( ) - > updateCounter ( ) ;
2014-05-30 12:53:19 +04:00
if ( unreadBar ) unreadBar - > setCount ( unreadCount ) ;
}
}
void History : : setMsgCount ( int32 newMsgCount ) {
if ( msgCount ! = newMsgCount ) {
msgCount = newMsgCount ;
}
}
void History : : setMute ( bool newMute ) {
if ( mute ! = newMute ) {
App : : histories ( ) . unreadMuted + = newMute ? unreadCount : ( - unreadCount ) ;
mute = newMute ;
2015-04-30 16:53:36 +03:00
if ( App : : wnd ( ) ) App : : wnd ( ) - > updateCounter ( ) ;
if ( App : : main ( ) ) App : : main ( ) - > dlgUpdated ( this ) ;
2014-05-30 12:53:19 +04:00
}
}
void History : : getNextShowFrom ( HistoryBlock * block , int32 i ) {
if ( i > = 0 ) {
int32 l = block - > size ( ) ;
for ( + + i ; i < l ; + + i ) {
if ( ( * block ) [ i ] - > itemType ( ) = = HistoryItem : : MsgType ) {
showFrom = ( * block ) [ i ] ;
return ;
}
}
}
int32 j = indexOf ( block ) , s = size ( ) ;
if ( j > = 0 ) {
for ( + + j ; j < s ; + + j ) {
block = ( * this ) [ j ] ;
for ( int32 i = 0 , l = block - > size ( ) ; i < l ; + + i ) {
if ( ( * block ) [ i ] - > itemType ( ) = = HistoryItem : : MsgType ) {
showFrom = ( * block ) [ i ] ;
return ;
}
}
}
}
showFrom = 0 ;
}
void History : : addUnreadBar ( ) {
2015-07-17 22:17:37 +03:00
if ( unreadBar | | ! showFrom | | showFrom - > detached ( ) | | ! unreadCount ) return ;
2014-05-30 12:53:19 +04:00
HistoryBlock * block = showFrom - > block ( ) ;
int32 i = block - > indexOf ( showFrom ) ;
int32 j = indexOf ( block ) ;
if ( i < 0 | | j < 0 ) return ;
HistoryUnreadBar * bar = new HistoryUnreadBar ( this , block , unreadCount , showFrom - > date ) ;
block - > insert ( i , bar ) ;
unreadBar = bar ;
unreadBar - > y = showFrom - > y ;
int32 dh = unreadBar - > resize ( width ) , l = block - > size ( ) ;
for ( + + i ; i < l ; + + i ) {
( * block ) [ i ] - > y + = dh ;
}
block - > height + = dh ;
for ( + + j , l = size ( ) ; j < l ; + + j ) {
( * this ) [ j ] - > y + = dh ;
}
height + = dh ;
}
2014-07-04 15:12:54 +04:00
void History : : clearNotifications ( ) {
notifies . clear ( ) ;
}
bool History : : loadedAtBottom ( ) const {
return newLoaded ;
}
bool History : : loadedAtTop ( ) const {
return oldLoaded ;
}
2015-07-17 22:17:37 +03:00
bool History : : isReadyFor ( MsgId msgId , bool check ) const {
if ( msgId = = ShowAtTheEndMsgId ) {
return loadedAtBottom ( ) ;
} else if ( msgId = = ShowAtUnreadMsgId ) {
return check ? ( loadedAtBottom ( ) & & ( msgCount > = unreadCount ) ) : ! isEmpty ( ) ;
} else if ( check ) {
HistoryItem * item = App : : histItemById ( msgId ) ;
return item & & item - > history ( ) = = this & & ! item - > detached ( ) ;
}
return ! isEmpty ( ) ;
}
void History : : getReadyFor ( MsgId msgId ) {
if ( ! isReadyFor ( msgId , true ) ) {
clear ( true ) ;
newLoaded = ( msgId = = ShowAtTheEndMsgId ) | | ( lastMsg & & ! lastMsg - > detached ( ) ) ;
oldLoaded = false ;
lastWidth = 0 ;
lastShowAtMsgId = msgId ;
}
}
2014-07-04 15:12:54 +04:00
void History : : fixLastMessage ( bool wasAtBottom ) {
if ( wasAtBottom & & isEmpty ( ) ) {
wasAtBottom = false ;
}
if ( wasAtBottom ) {
2015-06-15 20:19:24 +03:00
lastMsg = back ( ) - > back ( ) ;
2014-07-04 15:12:54 +04:00
} else {
2015-06-15 20:19:24 +03:00
lastMsg = 0 ;
2014-07-04 15:12:54 +04:00
if ( App : : main ( ) ) {
App : : main ( ) - > checkPeerHistory ( peer ) ;
2014-05-30 12:53:19 +04:00
}
}
2014-07-04 15:12:54 +04:00
}
MsgId History : : minMsgId ( ) const {
for ( const_iterator i = cbegin ( ) , e = cend ( ) ; i ! = e ; + + i ) {
for ( HistoryBlock : : const_iterator j = ( * i ) - > cbegin ( ) , en = ( * i ) - > cend ( ) ; j ! = en ; + + j ) {
if ( ( * j ) - > id > 0 ) {
return ( * j ) - > id ;
2014-05-30 12:53:19 +04:00
}
}
}
2014-07-04 15:12:54 +04:00
return 0 ;
2014-05-30 12:53:19 +04:00
}
2014-07-04 15:12:54 +04:00
MsgId History : : maxMsgId ( ) const {
for ( const_iterator i = cend ( ) , e = cbegin ( ) ; i ! = e ; ) {
- - i ;
for ( HistoryBlock : : const_iterator j = ( * i ) - > cend ( ) , en = ( * i ) - > cbegin ( ) ; j ! = en ; ) {
- - j ;
if ( ( * j ) - > id > 0 ) {
return ( * j ) - > id ;
}
}
}
return 0 ;
2014-05-30 12:53:19 +04:00
}
2014-10-10 16:46:20 +04:00
int32 History : : geomResize ( int32 newWidth , int32 * ytransform , bool dontRecountText ) {
if ( width ! = newWidth | | dontRecountText ) {
2014-05-30 12:53:19 +04:00
int32 y = 0 ;
for ( iterator i = begin ( ) , e = end ( ) ; i ! = e ; + + i ) {
HistoryBlock * block = * i ;
bool updTransform = ytransform & & ( * ytransform > = block - > y ) & & ( * ytransform < block - > y + block - > height ) ;
if ( updTransform ) * ytransform - = block - > y ;
if ( block - > y ! = y ) {
block - > y = y ;
}
2014-10-10 16:46:20 +04:00
y + = block - > geomResize ( newWidth , ytransform , dontRecountText ) ;
2014-05-30 12:53:19 +04:00
if ( updTransform ) {
* ytransform + = block - > y ;
ytransform = 0 ;
}
}
width = newWidth ;
height = y ;
}
return height ;
}
2014-07-04 15:12:54 +04:00
void History : : clear ( bool leaveItems ) {
if ( unreadBar ) {
unreadBar - > destroy ( ) ;
}
if ( showFrom ) {
showFrom = 0 ;
}
2014-08-15 15:19:32 +04:00
for ( int32 i = 0 ; i < OverviewCount ; + + i ) {
2015-07-03 11:47:16 +03:00
if ( ! _overview [ i ] . isEmpty ( ) | | ! _overviewIds [ i ] . isEmpty ( ) ) {
if ( _overviewCount [ i ] = = 0 ) _overviewCount [ i ] = _overview [ i ] . size ( ) ;
_overview [ i ] . clear ( ) ;
_overviewIds [ i ] . clear ( ) ;
if ( App : : wnd ( ) & & ! App : : quiting ( ) ) App : : wnd ( ) - > mediaOverviewUpdated ( peer , MediaOverviewType ( i ) ) ;
}
2014-08-15 15:19:32 +04:00
}
2014-05-30 12:53:19 +04:00
for ( Parent : : const_iterator i = cbegin ( ) , e = cend ( ) ; i ! = e ; + + i ) {
2014-07-04 15:12:54 +04:00
if ( leaveItems ) {
( * i ) - > clear ( true ) ;
}
2014-05-30 12:53:19 +04:00
delete * i ;
}
Parent : : clear ( ) ;
setMsgCount ( 0 ) ;
2015-06-17 22:43:03 +03:00
if ( leaveItems ) {
lastKeyboardInited = false ;
} else {
2014-07-04 15:12:54 +04:00
setUnreadCount ( 0 ) ;
2015-06-15 20:19:24 +03:00
lastMsg = 0 ;
2014-07-04 15:12:54 +04:00
}
height = 0 ;
oldLoaded = false ;
2015-06-17 22:43:03 +03:00
if ( peer - > chat ) {
peer - > asChat ( ) - > lastAuthors . clear ( ) ;
peer - > asChat ( ) - > markupSenders . clear ( ) ;
}
if ( leaveItems & & App : : main ( ) ) App : : main ( ) - > historyCleared ( this ) ;
2014-05-30 12:53:19 +04:00
}
History : : Parent : : iterator History : : erase ( History : : Parent : : iterator i ) {
delete * i ;
return Parent : : erase ( i ) ;
}
void History : : blockResized ( HistoryBlock * block , int32 dh ) {
int32 i = indexOf ( block ) , l = size ( ) ;
if ( i > = 0 ) {
for ( + + i ; i < l ; + + i ) {
( * this ) [ i ] - > y - = dh ;
}
height - = dh ;
}
}
void History : : removeBlock ( HistoryBlock * block ) {
int32 i = indexOf ( block ) , h = block - > height ;
if ( i > = 0 ) {
removeAt ( i ) ;
int32 l = size ( ) ;
if ( i > 0 & & l = = 1 ) { // only fake block with date left
removeBlock ( ( * this ) [ 0 ] ) ;
height = 0 ;
} else if ( h ) {
for ( ; i < l ; + + i ) {
( * this ) [ i ] - > y - = h ;
}
height - = h ;
}
}
delete block ;
}
2014-10-10 16:46:20 +04:00
int32 HistoryBlock : : geomResize ( int32 newWidth , int32 * ytransform , bool dontRecountText ) {
2014-05-30 12:53:19 +04:00
int32 y = 0 ;
for ( iterator i = begin ( ) , e = end ( ) ; i ! = e ; + + i ) {
HistoryItem * item = * i ;
bool updTransform = ytransform & & ( * ytransform > = item - > y ) & & ( * ytransform < item - > y + item - > height ( ) ) ;
if ( updTransform ) * ytransform - = item - > y ;
item - > y = y ;
2014-10-10 16:46:20 +04:00
y + = item - > resize ( newWidth , dontRecountText ) ;
2014-05-30 12:53:19 +04:00
if ( updTransform ) {
* ytransform + = item - > y ;
ytransform = 0 ;
}
}
height = y ;
return height ;
}
2014-07-04 15:12:54 +04:00
void HistoryBlock : : clear ( bool leaveItems ) {
if ( leaveItems ) {
for ( Parent : : const_iterator i = cbegin ( ) , e = cend ( ) ; i ! = e ; + + i ) {
( * i ) - > detachFast ( ) ;
}
} else {
for ( Parent : : const_iterator i = cbegin ( ) , e = cend ( ) ; i ! = e ; + + i ) {
delete * i ;
}
2014-05-30 12:53:19 +04:00
}
Parent : : clear ( ) ;
}
2014-07-04 15:12:54 +04:00
2014-05-30 12:53:19 +04:00
HistoryBlock : : Parent : : iterator HistoryBlock : : erase ( HistoryBlock : : Parent : : iterator i ) {
delete * i ;
return Parent : : erase ( i ) ;
}
void HistoryBlock : : removeItem ( HistoryItem * item ) {
int32 i = indexOf ( item ) , dh = 0 ;
if ( history - > showFrom = = item ) {
history - > getNextShowFrom ( this , i ) ;
}
if ( i < 0 ) {
return ;
}
bool createInitialDate = false ;
QDateTime initialDateTime ;
int32 myIndex = history - > indexOf ( this ) ;
if ( myIndex > = 0 & & item - > itemType ( ) ! = HistoryItem : : DateType ) { // fix date items
HistoryItem * nextItem = ( i < size ( ) - 1 ) ? ( * this ) [ i + 1 ] : ( ( myIndex < history - > size ( ) - 1 ) ? ( * ( * history ) [ myIndex + 1 ] ) [ 0 ] : 0 ) ;
if ( nextItem & & nextItem = = history - > unreadBar ) { // skip unread bar
if ( i < size ( ) - 2 ) {
nextItem = ( * this ) [ i + 2 ] ;
} else if ( i < size ( ) - 1 ) {
nextItem = ( ( myIndex < history - > size ( ) - 1 ) ? ( * ( * history ) [ myIndex + 1 ] ) [ 0 ] : 0 ) ;
} else if ( myIndex < history - > size ( ) - 1 ) {
if ( 0 < ( * history ) [ myIndex + 1 ] - > size ( ) - 1 ) {
nextItem = ( * ( * history ) [ myIndex + 1 ] ) [ 1 ] ;
} else if ( myIndex < history - > size ( ) - 2 ) {
nextItem = ( * ( * history ) [ myIndex + 2 ] ) [ 0 ] ;
} else {
nextItem = 0 ;
}
} else {
nextItem = 0 ;
}
}
if ( ! nextItem | | nextItem - > itemType ( ) = = HistoryItem : : DateType ) { // only if there is no next item or it is a date item
HistoryItem * prevItem = ( i > 0 ) ? ( * this ) [ i - 1 ] : 0 ;
if ( prevItem & & prevItem = = history - > unreadBar ) { // skip unread bar
prevItem = ( i > 1 ) ? ( * this ) [ i - 2 ] : 0 ;
}
if ( prevItem ) {
if ( prevItem - > itemType ( ) = = HistoryItem : : DateType ) {
prevItem - > destroy ( ) ;
- - i ;
}
} else if ( myIndex > 0 ) {
HistoryBlock * prevBlock = ( * history ) [ myIndex - 1 ] ;
2014-06-16 13:31:10 +04:00
if ( prevBlock - > isEmpty ( ) | | ( ( myIndex = = 1 ) & & ( prevBlock - > size ( ) ! = 1 | | ( * prevBlock - > cbegin ( ) ) - > itemType ( ) ! = HistoryItem : : DateType ) ) ) {
2014-05-30 12:53:19 +04:00
LOG ( ( " App Error: Found bad history, with no first date block: %1 " ) . arg ( ( * history ) [ 0 ] - > size ( ) ) ) ;
} else if ( ( * prevBlock ) [ prevBlock - > size ( ) - 1 ] - > itemType ( ) = = HistoryItem : : DateType ) {
( * prevBlock ) [ prevBlock - > size ( ) - 1 ] - > destroy ( ) ;
if ( nextItem & & myIndex = = 1 ) { // destroy next date (for creating initial then)
initialDateTime = nextItem - > date ;
createInitialDate = true ;
nextItem - > destroy ( ) ;
}
}
}
}
}
// myIndex can be invalid now, because of destroying previous blocks
dh = item - > height ( ) ;
remove ( i ) ;
int32 l = size ( ) ;
if ( ! item - > out ( ) & & item - > unread ( ) & & history - > unreadCount ) {
history - > setUnreadCount ( history - > unreadCount - 1 ) ;
}
int32 itemType = item - > itemType ( ) ;
if ( itemType = = HistoryItem : : MsgType ) {
history - > setMsgCount ( history - > msgCount - 1 ) ;
} else if ( itemType = = HistoryItem : : UnreadBarType ) {
if ( history - > unreadBar = = item ) {
history - > unreadBar = 0 ;
}
}
if ( createInitialDate ) {
history - > createInitialDateBlock ( initialDateTime ) ;
}
History * h = history ;
if ( l ) {
for ( ; i < l ; + + i ) {
( * this ) [ i ] - > y - = dh ;
}
height - = dh ;
history - > blockResized ( this , dh ) ;
} else {
history - > removeBlock ( this ) ;
}
}
2014-09-30 07:11:09 -07:00
bool ItemAnimations : : animStep ( float64 ms ) {
for ( Animations : : iterator i = _animations . begin ( ) ; i ! = _animations . end ( ) ; ) {
const HistoryItem * item = i . key ( ) ;
if ( item - > animating ( ) ) {
App : : main ( ) - > msgUpdated ( item - > history ( ) - > peer - > id , item ) ;
+ + i ;
} else {
i = _animations . erase ( i ) ;
}
}
return ! _animations . isEmpty ( ) ;
}
uint64 ItemAnimations : : animate ( const HistoryItem * item , uint64 ms ) {
if ( _animations . isEmpty ( ) ) {
_animations . insert ( item , ms ) ;
anim : : start ( this ) ;
return 0 ;
}
Animations : : const_iterator i = _animations . constFind ( item ) ;
if ( i = = _animations . cend ( ) ) i = _animations . insert ( item , ms ) ;
return ms - i . value ( ) ;
}
void ItemAnimations : : remove ( const HistoryItem * item ) {
_animations . remove ( item ) ;
}
namespace {
ItemAnimations _itemAnimations ;
}
ItemAnimations & itemAnimations ( ) {
return _itemAnimations ;
}
2015-03-19 12:18:19 +03:00
HistoryItem : : HistoryItem ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime msgDate , int32 from ) : y ( 0 )
2014-06-16 13:31:10 +04:00
, id ( msgId )
, date ( msgDate )
, _from ( App : : user ( from ) )
, _fromVersion ( _from - > nameVersion )
, _history ( history )
, _block ( block )
2015-03-19 12:18:19 +03:00
, _flags ( flags )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
}
void HistoryItem : : markRead ( ) {
2015-03-19 12:18:19 +03:00
if ( _flags & MTPDmessage_flag_unread ) {
if ( out ( ) ) {
2014-11-05 20:43:32 +03:00
_history - > outboxRead ( this ) ;
2014-05-30 12:53:19 +04:00
} else {
2014-11-05 20:43:32 +03:00
_history - > inboxRead ( this ) ;
2014-05-30 12:53:19 +04:00
}
App : : main ( ) - > msgUpdated ( _history - > peer - > id , this ) ;
2015-03-19 12:18:19 +03:00
_flags & = ~ int32 ( MTPDmessage_flag_unread ) ;
2014-05-30 12:53:19 +04:00
}
}
2014-08-11 13:03:45 +04:00
void HistoryItem : : destroy ( ) {
if ( ! out ( ) ) markRead ( ) ;
bool wasAtBottom = history ( ) - > loadedAtBottom ( ) ;
_history - > removeNotification ( this ) ;
detach ( ) ;
2015-06-15 20:19:24 +03:00
if ( history ( ) - > lastMsg = = this ) {
2014-08-11 13:03:45 +04:00
history ( ) - > fixLastMessage ( wasAtBottom ) ;
}
HistoryMedia * m = getMedia ( true ) ;
2014-08-15 15:19:32 +04:00
MediaOverviewType t = m ? mediaToOverviewType ( m - > type ( ) ) : OverviewCount ;
2015-07-03 11:47:16 +03:00
if ( t ! = OverviewCount ) {
history ( ) - > eraseFromOverview ( t , id ) ;
if ( m - > type ( ) = = MediaTypeDocument & & static_cast < HistoryDocument * > ( m ) - > document ( ) - > song ( ) ) {
history ( ) - > eraseFromOverview ( OverviewAudioDocuments , id ) ;
2014-08-11 13:03:45 +04:00
}
}
delete this ;
}
2014-07-04 15:12:54 +04:00
void HistoryItem : : detach ( ) {
if ( _history & & _history - > unreadBar = = this ) {
_history - > unreadBar = 0 ;
}
if ( _block ) {
_block - > removeItem ( this ) ;
detachFast ( ) ;
App : : historyItemDetached ( this ) ;
} else {
if ( _history - > showFrom = = this ) {
_history - > showFrom = 0 ;
}
}
if ( _history & & _history - > unreadBar & & _history - > back ( ) - > back ( ) = = _history - > unreadBar ) {
_history - > unreadBar - > destroy ( ) ;
}
}
void HistoryItem : : detachFast ( ) {
_block = 0 ;
}
2014-05-30 12:53:19 +04:00
HistoryItem : : ~ HistoryItem ( ) {
2014-09-30 07:11:09 -07:00
itemAnimations ( ) . remove ( this ) ;
2014-05-30 12:53:19 +04:00
App : : historyUnregItem ( this ) ;
if ( id < 0 ) {
App : : app ( ) - > uploader ( ) - > cancel ( id ) ;
}
}
2014-07-04 15:12:54 +04:00
HistoryItem * regItem ( HistoryItem * item , bool returnExisting ) {
if ( ! item ) return 0 ;
2015-03-19 12:18:19 +03:00
2014-07-04 15:12:54 +04:00
HistoryItem * existing = App : : historyRegItem ( item ) ;
if ( existing ) {
delete item ;
return returnExisting ? existing : 0 ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
item - > initDimensions ( ) ;
2014-07-04 15:12:54 +04:00
return item ;
2014-05-30 12:53:19 +04:00
}
2015-04-30 16:53:36 +03:00
HistoryPhoto : : HistoryPhoto ( const MTPDphoto & photo , const QString & caption , HistoryItem * parent ) : HistoryMedia ( )
2015-01-05 23:17:33 +03:00
, pixw ( 1 ) , pixh ( 1 )
2014-11-18 15:41:33 +03:00
, data ( App : : feedPhoto ( photo ) )
2015-04-30 16:53:36 +03:00
, _caption ( st : : minPhotoSize )
2014-11-18 15:41:33 +03:00
, openl ( new PhotoLink ( data ) ) {
2015-04-30 16:53:36 +03:00
if ( ! caption . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_caption . setText ( st : : msgFont , caption + textcmdSkipBlock ( parent - > timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) , itemTextParseOptions ( parent ) ) ;
2015-04-30 16:53:36 +03:00
}
2014-08-11 13:03:45 +04:00
init ( ) ;
}
2014-11-18 15:41:33 +03:00
HistoryPhoto : : HistoryPhoto ( PeerData * chat , const MTPDphoto & photo , int32 width ) : HistoryMedia ( width )
2015-01-05 23:17:33 +03:00
, pixw ( 1 ) , pixh ( 1 )
2014-11-18 15:41:33 +03:00
, data ( App : : feedPhoto ( photo ) )
, openl ( new PhotoLink ( data , chat ) ) {
2014-08-11 13:03:45 +04:00
init ( ) ;
}
void HistoryPhoto : : init ( ) {
2014-10-10 16:46:20 +04:00
data - > thumb - > load ( ) ;
}
void HistoryPhoto : : initDimensions ( const HistoryItem * parent ) {
2014-11-12 23:18:00 +03:00
int32 tw = convertScale ( data - > full - > width ( ) ) , th = convertScale ( data - > full - > height ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
2014-11-18 15:41:33 +03:00
int32 thumbw = tw ;
int32 thumbh = th ;
2014-11-12 23:18:00 +03:00
if ( ! w ) {
w = thumbw ;
2014-11-18 15:41:33 +03:00
} else {
thumbh = w ; // square chat photo updates
2014-11-12 23:18:00 +03:00
}
2015-01-05 23:17:33 +03:00
_maxw = qMax ( w , int32 ( st : : minPhotoSize ) ) ;
_minh = qMax ( thumbh , int32 ( st : : minPhotoSize ) ) ;
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ;
if ( reply | | ! _caption . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
if ( reply ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat | | ! fwd ) {
_minh + = st : : msgPadding . top ( ) ;
}
if ( fwd ) {
_minh + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
}
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
2015-05-20 22:28:24 +03:00
_minh + = st : : webPagePhotoSkip + _caption . minHeight ( ) ;
2015-04-30 16:53:36 +03:00
}
_minh + = st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
}
2014-11-12 23:18:00 +03:00
int32 HistoryPhoto : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-30 16:53:36 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
2015-03-19 12:18:19 +03:00
2015-01-05 23:17:33 +03:00
pixw = qMin ( width , _maxw ) ;
2015-04-30 16:53:36 +03:00
if ( reply | | ! _caption . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
pixw - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
2014-11-12 23:18:00 +03:00
int32 tw = convertScale ( data - > full - > width ( ) ) , th = convertScale ( data - > full - > height ( ) ) ;
2014-11-18 15:41:33 +03:00
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
2014-11-18 15:59:16 +03:00
if ( th > st : : maxMediaSize ) {
tw = ( st : : maxMediaSize * tw ) / th ;
th = st : : maxMediaSize ;
}
2015-01-05 23:17:33 +03:00
pixh = th ;
if ( tw > pixw ) {
pixh = ( pixw * pixh / tw ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-01-05 23:17:33 +03:00
pixw = tw ;
2014-11-12 23:18:00 +03:00
}
2015-01-05 23:17:33 +03:00
if ( pixh > width ) {
pixw = ( pixw * width ) / pixh ;
pixh = width ;
2014-11-12 23:18:00 +03:00
}
2015-01-05 23:17:33 +03:00
if ( pixw < 1 ) pixw = 1 ;
if ( pixh < 1 ) pixh = 1 ;
w = qMax ( pixw , int16 ( st : : minPhotoSize ) ) ;
_height = qMax ( pixh , int16 ( st : : minPhotoSize ) ) ;
2015-04-30 16:53:36 +03:00
if ( reply | | ! _caption . isEmpty ( ) ) {
if ( reply ) {
_height + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat | | ! fwd ) {
_height + = st : : msgPadding . top ( ) ;
}
if ( fwd ) {
_height + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
}
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_height + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
_height + = st : : webPagePhotoSkip + _caption . countHeight ( w ) ;
}
_height + = st : : mediaPadding . bottom ( ) ;
w + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
return _height ;
}
const QString HistoryPhoto : : inDialogsText ( ) const {
return lang ( lng_in_dlg_photo ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryPhoto : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_photo ) + qsl ( " ] " ) ;
}
2015-05-20 22:28:24 +03:00
const Text & HistoryPhoto : : captionForClone ( ) const {
return _caption ;
}
2014-10-10 16:46:20 +04:00
bool HistoryPhoto : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-11-12 23:18:00 +03:00
if ( width < 0 ) width = w ;
2014-08-15 15:19:32 +04:00
return ( x > = 0 & & y > = 0 & & x < width & & y < _height ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
void HistoryPhoto : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-11-12 23:18:00 +03:00
if ( width < 0 ) width = w ;
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2015-03-19 12:18:19 +03:00
int skipx = 0 , skipy = 0 , height = _height ;
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int replyFrom = 0 , fwdFrom = 0 ;
if ( reply | | ! _caption . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-04-30 16:53:36 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-04-30 16:53:36 +03:00
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-03-19 12:18:19 +03:00
skipy + = replyFrom ;
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
2015-04-08 02:03:32 +03:00
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-30 16:53:36 +03:00
if ( ! reply & & ! fwd ) skipy + = st : : msgPadding . top ( ) ;
} else if ( ! reply ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
}
if ( reply ) {
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
lnk = reply - > replyToLink ( ) ;
return ;
}
} else if ( fwd ) {
if ( y > = fwdFrom & & y < fwdFrom + st : : msgServiceNameFont - > height ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-30 16:53:36 +03:00
}
2015-03-19 12:18:19 +03:00
}
2015-04-30 16:53:36 +03:00
height - = st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
height - = _caption . countHeight ( width ) + st : : webPagePhotoSkip ;
if ( x > = skipx & & y > = height + st : : webPagePhotoSkip & & x < skipx + width & & y < _height ) {
2015-06-27 16:02:00 +03:00
bool inText = false ;
_caption . getState ( lnk , inText , x - skipx , y - height - st : : webPagePhotoSkip , width ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
2015-04-30 16:53:36 +03:00
}
}
2015-03-19 12:18:19 +03:00
}
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < height ) {
2015-04-08 02:03:32 +03:00
lnk = openl ;
return ;
2014-05-30 12:53:19 +04:00
}
}
HistoryMedia * HistoryPhoto : : clone ( ) const {
return new HistoryPhoto ( * this ) ;
}
2014-11-22 12:45:04 +03:00
void HistoryPhoto : : updateFrom ( const MTPMessageMedia & media ) {
if ( media . type ( ) = = mtpc_messageMediaPhoto ) {
const MTPPhoto & photo ( media . c_messageMediaPhoto ( ) . vphoto ) ;
if ( photo . type ( ) = = mtpc_photo ) {
const QVector < MTPPhotoSize > & sizes ( photo . c_photo ( ) . vsizes . c_vector ( ) . v ) ;
for ( QVector < MTPPhotoSize > : : const_iterator i = sizes . cbegin ( ) , e = sizes . cend ( ) ; i ! = e ; + + i ) {
char size = 0 ;
const MTPFileLocation * loc = 0 ;
switch ( i - > type ( ) ) {
case mtpc_photoSize : {
const string & s ( i - > c_photoSize ( ) . vtype . c_string ( ) . v ) ;
loc = & i - > c_photoSize ( ) . vlocation ;
if ( s . size ( ) ) size = s [ 0 ] ;
} break ;
case mtpc_photoCachedSize : {
const string & s ( i - > c_photoCachedSize ( ) . vtype . c_string ( ) . v ) ;
2015-04-15 09:23:39 +02:00
loc = & i - > c_photoCachedSize ( ) . vlocation ;
2014-11-22 12:45:04 +03:00
if ( s . size ( ) ) size = s [ 0 ] ;
} break ;
}
if ( ! loc | | loc - > type ( ) ! = mtpc_fileLocation ) continue ;
if ( size = = ' s ' ) {
Local : : writeImage ( storageKey ( loc - > c_fileLocation ( ) ) , data - > thumb ) ;
} else if ( size = = ' m ' ) {
Local : : writeImage ( storageKey ( loc - > c_fileLocation ( ) ) , data - > medium ) ;
} else if ( size = = ' x ' ) {
Local : : writeImage ( storageKey ( loc - > c_fileLocation ( ) ) , data - > full ) ;
}
}
}
}
}
2014-08-15 15:19:32 +04:00
void HistoryPhoto : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
2015-05-20 22:28:24 +03:00
bool out = parent - > out ( ) ;
2014-11-12 23:18:00 +03:00
if ( width < 0 ) width = w ;
2015-03-19 12:18:19 +03:00
int skipx = 0 , skipy = 0 , height = _height ;
2015-04-30 16:53:36 +03:00
if ( reply | | ! _caption . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , 0 , 0 , width , _height , bg , cors , & sh ) ;
2015-04-30 16:53:36 +03:00
int replyFrom = 0 , fwdFrom = 0 ;
2015-05-20 22:28:24 +03:00
if ( ! out & & parent - > history ( ) - > peer - > chat ) {
2015-03-19 12:18:19 +03:00
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-04-30 16:53:36 +03:00
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-03-19 12:18:19 +03:00
skipy + = replyFrom ;
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( ! fwd & & ! reply ) skipy + = st : : msgPadding . top ( ) ;
} else if ( ! reply ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
}
if ( reply ) {
skipy + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
} else if ( fwd ) {
skipy + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _caption . isEmpty ( ) ) {
height - = st : : webPagePhotoSkip + _caption . countHeight ( width ) ;
}
2015-05-20 22:28:24 +03:00
} else {
2015-05-22 14:14:52 +03:00
App : : roundShadow ( p , 0 , 0 , width , _height , selected ? st : : msgInSelectShadow : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
data - > full - > load ( false , false ) ;
2014-11-12 23:18:00 +03:00
bool full = data - > full - > loaded ( ) ;
QPixmap pix ;
if ( full ) {
2015-05-20 22:28:24 +03:00
pix = data - > full - > pixSingle ( pixw , pixh , width , height ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-05-20 22:28:24 +03:00
pix = data - > thumb - > pixBlurredSingle ( pixw , pixh , width , height ) ;
2014-11-12 23:18:00 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( skipx , skipy , pix ) ;
2014-11-12 23:18:00 +03:00
if ( ! full ) {
uint64 dt = itemAnimations ( ) . animate ( parent , getms ( ) ) ;
int32 cnt = int32 ( st : : photoLoaderCnt ) , period = int32 ( st : : photoLoaderPeriod ) , t = dt % period , delta = int32 ( st : : photoLoaderDelta ) ;
2015-03-19 12:18:19 +03:00
int32 x = ( width - st : : photoLoader . width ( ) ) / 2 , y = ( height - st : : photoLoader . height ( ) ) / 2 ;
p . fillRect ( skipx + x , skipy + y , st : : photoLoader . width ( ) , st : : photoLoader . height ( ) , st : : photoLoaderBg - > b ) ;
2014-11-12 23:18:00 +03:00
x + = ( st : : photoLoader . width ( ) - cnt * st : : photoLoaderPoint . width ( ) - ( cnt - 1 ) * st : : photoLoaderSkip ) / 2 ;
y + = ( st : : photoLoader . height ( ) - st : : photoLoaderPoint . height ( ) ) / 2 ;
QColor c ( st : : white - > c ) ;
QBrush b ( c ) ;
for ( int32 i = 0 ; i < cnt ; + + i ) {
t - = delta ;
while ( t < 0 ) t + = period ;
2014-09-30 07:11:09 -07:00
2014-11-12 23:18:00 +03:00
float64 alpha = ( t > = st : : photoLoaderDuration1 + st : : photoLoaderDuration2 ) ? 0 : ( ( t > st : : photoLoaderDuration1 ? ( ( st : : photoLoaderDuration1 + st : : photoLoaderDuration2 - t ) / st : : photoLoaderDuration2 ) : ( t / st : : photoLoaderDuration1 ) ) ) ;
c . setAlphaF ( st : : photoLoaderAlphaMin + alpha * ( 1 - st : : photoLoaderAlphaMin ) ) ;
b . setColor ( c ) ;
2015-03-19 12:18:19 +03:00
p . fillRect ( skipx + x + i * ( st : : photoLoaderPoint . width ( ) + st : : photoLoaderSkip ) , skipy + y , st : : photoLoaderPoint . width ( ) , st : : photoLoaderPoint . height ( ) , b ) ;
2014-05-30 12:53:19 +04:00
}
2014-11-12 23:18:00 +03:00
}
2014-05-30 12:53:19 +04:00
2014-11-12 23:18:00 +03:00
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , skipx , skipy , width , height , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-05-30 12:53:19 +04:00
}
// date
2014-08-15 15:19:32 +04:00
QString time ( parent - > time ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( _caption . isEmpty ( ) ) {
if ( time . isEmpty ( ) ) return ;
int32 dateX = skipx + width - parent - > timeWidth ( false ) - st : : msgDateImgDelta - 2 * st : : msgDateImgPadding . x ( ) ;
int32 dateY = skipy + height - st : : msgDateFont - > height - 2 * st : : msgDateImgPadding . y ( ) - st : : msgDateImgDelta ;
if ( parent - > out ( ) ) {
dateX - = st : : msgCheckRect . pxWidth ( ) + st : : msgDateImgCheckSpace ;
}
int32 dateW = skipx + width - dateX - st : : msgDateImgDelta ;
int32 dateH = skipy + height - dateY - st : : msgDateImgDelta ;
2014-05-30 12:53:19 +04:00
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , dateX , dateY , dateW , dateH , selected ? st : : msgDateImgSelectBg : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-04-30 16:53:36 +03:00
p . setFont ( st : : msgDateFont - > f ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
p . drawText ( dateX + st : : msgDateImgPadding . x ( ) , dateY + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , time ) ;
if ( out ) {
QPoint iconPos ( dateX - 2 + dateW - st : : msgDateImgCheckSpace - st : : msgCheckRect . pxWidth ( ) , dateY + ( dateH - st : : msgCheckRect . pxHeight ( ) ) / 2 ) ;
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & st : : msgImgCheckRect ;
} else {
iconRect = & st : : msgImgDblCheckRect ;
}
2014-05-30 12:53:19 +04:00
} else {
2015-04-30 16:53:36 +03:00
iconRect = & st : : msgImgSendingRect ;
2014-05-30 12:53:19 +04:00
}
2015-04-30 16:53:36 +03:00
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
} else {
p . setPen ( st : : black - > p ) ;
_caption . draw ( p , skipx , skipy + height + st : : webPagePhotoSkip , width ) ;
style : : color date ( selected ? ( out ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
p . drawText ( w - st : : msgPadding . right ( ) + st : : msgDateDelta . x ( ) - parent - > timeWidth ( true ) + st : : msgDateSpace , _height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , time ) ;
if ( out ) {
QPoint iconPos ( w + st : : msgCheckPos . x ( ) - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , _height + st : : msgCheckPos . y ( ) - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
2014-05-30 12:53:19 +04:00
}
}
}
2015-03-19 12:18:19 +03:00
ImagePtr HistoryPhoto : : replyPreview ( ) {
2015-04-07 01:15:29 +03:00
return data - > makeReplyPreview ( ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
QString formatSizeText ( qint64 size ) {
if ( size > = 1024 * 1024 ) { // more than 1 mb
qint64 sizeTenthMb = ( size * 10 / ( 1024 * 1024 ) ) ;
2015-06-29 15:25:28 +03:00
return QString : : number ( sizeTenthMb / 10 ) + ' . ' + QString : : number ( sizeTenthMb % 10 ) + qsl ( " MB " ) ;
2014-05-30 12:53:19 +04:00
}
qint64 sizeTenthKb = ( size * 10 / 1024 ) ;
2015-06-29 15:25:28 +03:00
return QString : : number ( sizeTenthKb / 10 ) + ' . ' + QString : : number ( sizeTenthKb % 10 ) + qsl ( " KB " ) ;
2014-05-30 12:53:19 +04:00
}
QString formatDownloadText ( qint64 ready , qint64 total ) {
QString readyStr , totalStr , mb ;
if ( total > = 1024 * 1024 ) { // more than 1 mb
qint64 readyTenthMb = ( ready * 10 / ( 1024 * 1024 ) ) , totalTenthMb = ( total * 10 / ( 1024 * 1024 ) ) ;
readyStr = QString : : number ( readyTenthMb / 10 ) + ' . ' + QString : : number ( readyTenthMb % 10 ) ;
totalStr = QString : : number ( totalTenthMb / 10 ) + ' . ' + QString : : number ( totalTenthMb % 10 ) ;
2015-01-26 16:04:41 +03:00
mb = qsl ( " MB " ) ;
2014-05-30 12:53:19 +04:00
} else {
qint64 readyKb = ( ready / 1024 ) , totalKb = ( total / 1024 ) ;
readyStr = QString : : number ( readyKb ) ;
totalStr = QString : : number ( totalKb ) ;
2015-01-26 16:04:41 +03:00
mb = qsl ( " KB " ) ;
2014-05-30 12:53:19 +04:00
}
2014-12-18 21:40:49 +03:00
return lng_save_downloaded ( lt_ready , readyStr , lt_total , totalStr , lt_mb , mb ) ;
2014-05-30 12:53:19 +04:00
}
QString formatDurationText ( qint64 duration ) {
qint64 hours = ( duration / 3600 ) , minutes = ( duration % 3600 ) / 60 , seconds = duration % 60 ;
return ( hours ? QString : : number ( hours ) + ' : ' : QString ( ) ) + ( minutes > = 10 ? QString ( ) : QString ( ' 0 ' ) ) + QString : : number ( minutes ) + ' : ' + ( seconds > = 10 ? QString ( ) : QString ( ' 0 ' ) ) + QString : : number ( seconds ) ;
}
QString formatDurationAndSizeText ( qint64 duration , qint64 size ) {
2014-12-18 21:40:49 +03:00
return lng_duration_and_size ( lt_duration , formatDurationText ( duration ) , lt_size , formatSizeText ( size ) ) ;
2014-05-30 12:53:19 +04:00
}
int32 _downloadWidth = 0 , _openWithWidth = 0 , _cancelWidth = 0 , _buttonWidth = 0 ;
2015-04-30 16:53:36 +03:00
HistoryVideo : : HistoryVideo ( const MTPDvideo & video , const QString & caption , HistoryItem * parent ) : HistoryMedia ( )
2014-11-18 15:41:33 +03:00
, data ( App : : feedVideo ( video ) )
2014-06-16 13:31:10 +04:00
, _openl ( new VideoOpenLink ( data ) )
, _savel ( new VideoSaveLink ( data ) )
, _cancell ( new VideoCancelLink ( data ) )
2015-04-30 16:53:36 +03:00
, _caption ( st : : minPhotoSize )
2014-06-16 13:31:10 +04:00
, _dldDone ( 0 )
, _uplDone ( 0 )
{
2015-05-20 22:28:24 +03:00
if ( ! caption . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_caption . setText ( st : : msgFont , caption + textcmdSkipBlock ( parent - > timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) , itemTextParseOptions ( parent ) ) ;
2015-05-20 22:28:24 +03:00
}
2014-05-30 12:53:19 +04:00
_size = formatDurationAndSizeText ( data - > duration , data - > size ) ;
if ( ! _openWithWidth ) {
_downloadWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_download ) ) ;
_openWithWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_open_with ) ) ;
_cancelWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_cancel ) ) ;
_buttonWidth = ( st : : mediaSaveButton . width > 0 ) ? st : : mediaSaveButton . width : ( ( _downloadWidth > _openWithWidth ? ( _downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth ) : _openWithWidth ) - st : : mediaSaveButton . width ) ;
}
data - > thumb - > load ( ) ;
int32 tw = data - > thumb - > width ( ) , th = data - > thumb - > height ( ) ;
if ( data - > thumb - > isNull ( ) | | ! tw | | ! th ) {
_thumbw = _thumbx = _thumby = 0 ;
} else if ( tw > th ) {
_thumbw = ( tw * st : : mediaThumbSize ) / th ;
_thumbx = ( _thumbw - st : : mediaThumbSize ) / 2 ;
_thumby = 0 ;
} else {
_thumbw = st : : mediaThumbSize ;
_thumbx = 0 ;
_thumby = ( ( th * _thumbw ) / tw - st : : mediaThumbSize ) / 2 ;
}
}
2014-08-15 15:19:32 +04:00
void HistoryVideo : : initDimensions ( const HistoryItem * parent ) {
2014-10-10 16:46:20 +04:00
_maxw = st : : mediaMaxWidth ;
2014-05-30 12:53:19 +04:00
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
if ( ! parent - > out ( ) ) { // add Download / Save As button
_maxw + = st : : mediaSaveDelta + _buttonWidth ;
}
2015-03-19 12:18:19 +03:00
_minh = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
_minh + = st : : msgServiceNameFont - > height ;
2015-03-19 12:18:19 +03:00
}
2015-05-20 22:28:24 +03:00
if ( _caption . isEmpty ( ) ) {
_height = _minh ;
} else {
_minh + = st : : webPagePhotoSkip + _caption . minHeight ( ) ;
}
2014-05-30 12:53:19 +04:00
}
void HistoryVideo : : regItem ( HistoryItem * item ) {
App : : regVideoItem ( data , item ) ;
}
void HistoryVideo : : unregItem ( HistoryItem * item ) {
App : : unregVideoItem ( data , item ) ;
}
const QString HistoryVideo : : inDialogsText ( ) const {
return lang ( lng_in_dlg_video ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryVideo : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_video ) + qsl ( " ] " ) ;
}
2014-10-10 16:46:20 +04:00
bool HistoryVideo : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2015-06-28 15:37:10 +03:00
int32 height = _height ;
if ( width < 0 ) {
width = w ;
} else if ( ! _caption . isEmpty ( ) ) {
height = countHeight ( parent , width ) ;
}
if ( width > = _maxw ) {
width = _maxw ;
}
return ( x > = 0 & & y > = 0 & & x < width & & y < height ) ;
}
int32 HistoryVideo : : countHeight ( const HistoryItem * parent , int32 width ) const {
if ( _caption . isEmpty ( ) ) return _height ;
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
2015-06-28 15:37:10 +03:00
int32 h = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
h + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
h + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
h + = st : : msgPadding . top ( ) ;
}
h + = st : : msgServiceNameFont - > height ;
}
if ( ! _caption . isEmpty ( ) ) {
int32 textw = width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ;
if ( ! parent - > out ( ) ) { // substract Download / Save As button
textw - = st : : mediaSaveDelta + _buttonWidth ;
}
h + = st : : webPagePhotoSkip + _caption . countHeight ( textw ) ;
}
return h ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
void HistoryVideo : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2015-06-28 15:37:10 +03:00
int32 height = _height ;
if ( width < 0 ) {
width = w ;
} else if ( ! _caption . isEmpty ( ) ) {
height = countHeight ( parent , width ) ;
}
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
bool out = parent - > out ( ) , hovered , pressed ;
if ( width > = _maxw ) {
width = _maxw ;
}
if ( ! out ) { // draw Download / Save As button
2015-06-28 15:37:10 +03:00
int32 h = height ;
2015-05-20 22:28:24 +03:00
if ( ! _caption . isEmpty ( ) ) {
h - = st : : webPagePhotoSkip + _caption . countHeight ( width - _buttonWidth - st : : mediaSaveDelta - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( h - skipy - btnh ) / 2 ;
2014-05-30 12:53:19 +04:00
if ( x > = btnx & & y > = btny & & x < btnx + btnw & & y < btny + btnh ) {
2015-04-08 02:03:32 +03:00
lnk = data - > loader ? _cancell : _savel ;
return ;
2014-05-30 12:53:19 +04:00
}
width - = btnw + st : : mediaSaveDelta ;
}
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
}
if ( reply ) {
2015-03-19 12:18:19 +03:00
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
2015-04-08 02:03:32 +03:00
lnk = reply - > replyToLink ( ) ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
if ( y > = fwdFrom & & y < skipy ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-23 18:50:11 +03:00
}
2015-03-19 12:18:19 +03:00
}
2015-05-20 22:28:24 +03:00
int32 tw = width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ;
if ( x > = st : : mediaPadding . left ( ) & & y > = skipy + st : : mediaPadding . top ( ) & & x < st : : mediaPadding . left ( ) + tw & & y < skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize & & ! data - > loader & & data - > access ) {
2015-04-08 02:03:32 +03:00
lnk = _openl ;
return ;
2014-05-30 12:53:19 +04:00
}
2015-05-20 22:28:24 +03:00
if ( ! _caption . isEmpty ( ) & & x > = st : : mediaPadding . left ( ) & & x < st : : mediaPadding . left ( ) + tw & & y > = skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : webPagePhotoSkip ) {
2015-06-27 16:02:00 +03:00
bool inText = false ;
_caption . getState ( lnk , inText , x - st : : mediaPadding . left ( ) , y - skipy - st : : mediaPadding . top ( ) - st : : mediaThumbSize - st : : webPagePhotoSkip , tw ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
2015-05-20 22:28:24 +03:00
}
2014-05-30 12:53:19 +04:00
}
HistoryMedia * HistoryVideo : : clone ( ) const {
2014-10-10 16:46:20 +04:00
return new HistoryVideo ( * this ) ;
2014-05-30 12:53:19 +04:00
}
2014-08-15 15:19:32 +04:00
void HistoryVideo : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
2015-06-28 15:37:10 +03:00
int32 height = _height ;
if ( width < 0 ) {
width = w ;
} else if ( ! _caption . isEmpty ( ) ) {
height = countHeight ( parent , width ) ;
}
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return ;
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
data - > thumb - > checkload ( ) ;
bool out = parent - > out ( ) , hovered , pressed ;
if ( width > = _maxw ) {
width = _maxw ;
}
if ( ! out ) { // draw Download / Save As button
hovered = ( ( data - > loader ? _cancell : _savel ) = = textlnkOver ( ) ) ;
pressed = hovered & & ( ( data - > loader ? _cancell : _savel ) = = textlnkDown ( ) ) ;
if ( hovered & & ! pressed & & textlnkDown ( ) ) hovered = false ;
2015-06-28 15:37:10 +03:00
int32 h = height ;
2015-05-20 22:28:24 +03:00
if ( ! _caption . isEmpty ( ) ) {
h - = st : : webPagePhotoSkip + _caption . countHeight ( width - _buttonWidth - st : : mediaSaveDelta - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2014-05-30 12:53:19 +04:00
2015-05-20 22:28:24 +03:00
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( h - skipy - btnh ) / 2 ;
style : : color bg ( selected ? st : : msgInSelectBg : ( hovered ? st : : mediaSaveButton . overBgColor : st : : mediaSaveButton . bgColor ) ) ;
style : : color sh ( selected ? st : : msgInSelectShadow : st : : msgInShadow ) ;
RoundCorners cors ( selected ? MessageInSelectedCorners : ( hovered ? ButtonHoverCorners : MessageInCorners ) ) ;
App : : roundRect ( p , btnx , btny , btnw , btnh , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( ( hovered ? st : : mediaSaveButton . overColor : st : : mediaSaveButton . color ) - > p ) ;
p . setFont ( st : : mediaSaveButton . font - > f ) ;
QString btnText ( lang ( data - > loader ? lng_media_cancel : ( data - > already ( ) . isEmpty ( ) ? lng_media_download : lng_media_open_with ) ) ) ;
int32 btnTextWidth = data - > loader ? _cancelWidth : ( data - > already ( ) . isEmpty ( ) ? _downloadWidth : _openWithWidth ) ;
p . drawText ( btnx + ( btnw - btnTextWidth ) / 2 , btny + ( pressed ? st : : mediaSaveButton . downTextTop : st : : mediaSaveButton . textTop ) + st : : mediaSaveButton . font - > ascent , btnText ) ;
width - = btnw + st : : mediaSaveDelta ;
}
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
2015-06-28 15:37:10 +03:00
App : : roundRect ( p , 0 , 0 , width , height , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2015-03-19 12:18:19 +03:00
if ( reply ) {
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
if ( _thumbw ) {
2015-05-20 22:28:24 +03:00
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , data - > thumb - > pixSingle ( _thumbw , 0 , st : : mediaThumbSize , st : : mediaThumbSize ) ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-03-19 12:18:19 +03:00
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , App : : sprite ( ) , ( out ? st : : mediaDocOutImg : st : : mediaDocInImg ) ) ;
2014-05-30 12:53:19 +04:00
}
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) , st : : mediaThumbSize , st : : mediaThumbSize , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-05-30 12:53:19 +04:00
}
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
int32 twidth = width - tleft - st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
int32 secondwidth = width - tleft - fullTimeWidth ;
p . setFont ( st : : mediaFont - > f ) ;
p . setPen ( st : : black - > c ) ;
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , lang ( lng_media_video ) ) ;
2014-05-30 12:53:19 +04:00
QString statusText ;
style : : color status ( selected ? ( out ? st : : mediaOutSelectColor : st : : mediaInSelectColor ) : ( out ? st : : mediaOutColor : st : : mediaInColor ) ) ;
p . setPen ( status - > p ) ;
if ( data - > loader ) {
2015-07-03 11:47:16 +03:00
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
2014-05-30 12:53:19 +04:00
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
} else {
statusText = _size ;
}
}
2015-04-30 16:53:36 +03:00
int32 texty = skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize - st : : mediaDetailsShift - st : : mediaFont - > height ;
p . drawText ( tleft , texty + st : : mediaFont - > ascent , statusText ) ;
if ( parent - > isMediaUnread ( ) ) {
int32 w = st : : mediaFont - > m . width ( statusText ) ;
if ( w + st : : mediaUnreadSkip + st : : mediaUnreadSize < = twidth ) {
p . setRenderHint ( QPainter : : HighQualityAntialiasing , true ) ;
p . setPen ( Qt : : NoPen ) ;
p . setBrush ( ( out ? ( selected ? st : : mediaOutUnreadSelectColor : st : : mediaOutUnreadColor ) : ( selected ? st : : mediaInUnreadSelectColor : st : : mediaInUnreadColor ) ) - > b ) ;
p . drawEllipse ( QRect ( tleft + w + st : : mediaUnreadSkip , texty + ( ( st : : mediaFont - > height - st : : mediaUnreadSize ) / 2 ) , st : : mediaUnreadSize , st : : mediaUnreadSize ) ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
}
}
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgDateFont - > f ) ;
2015-05-20 22:28:24 +03:00
if ( ! _caption . isEmpty ( ) ) {
p . setPen ( st : : black - > p ) ;
_caption . draw ( p , st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : webPagePhotoSkip , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2014-05-30 12:53:19 +04:00
style : : color date ( selected ? ( out ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
2015-06-28 15:37:10 +03:00
p . drawText ( width + st : : msgDateDelta . x ( ) - fullTimeWidth + st : : msgDateSpace , height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , parent - > time ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( out ) {
2015-06-28 15:37:10 +03:00
QPoint iconPos ( width + 5 - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , height + 1 - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
2014-05-30 12:53:19 +04:00
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
2015-05-20 22:28:24 +03:00
int32 HistoryVideo : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
w = qMin ( width , _maxw ) ;
if ( _caption . isEmpty ( ) ) return _height ;
_height = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_height + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
_height + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
_height + = st : : msgPadding . top ( ) ;
}
_height + = st : : msgServiceNameFont - > height ;
}
if ( ! _caption . isEmpty ( ) ) {
int32 textw = w - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ;
if ( ! parent - > out ( ) ) { // substract Download / Save As button
textw - = st : : mediaSaveDelta + _buttonWidth ;
}
_height + = st : : webPagePhotoSkip + _caption . countHeight ( textw ) ;
}
return _height ;
}
2015-03-19 12:18:19 +03:00
ImagePtr HistoryVideo : : replyPreview ( ) {
if ( data - > replyPreview - > isNull ( ) & & ! data - > thumb - > isNull ( ) ) {
if ( data - > thumb - > loaded ( ) ) {
int w = data - > thumb - > width ( ) , h = data - > thumb - > height ( ) ;
if ( w < = 0 ) w = 1 ;
if ( h < = 0 ) h = 1 ;
data - > replyPreview = ImagePtr ( w > h ? data - > thumb - > pix ( w * st : : msgReplyBarSize . height ( ) / h , st : : msgReplyBarSize . height ( ) ) : data - > thumb - > pix ( st : : msgReplyBarSize . height ( ) ) , " PNG " ) ;
} else {
data - > thumb - > load ( ) ;
}
}
return data - > replyPreview ;
}
2015-04-04 23:01:34 +03:00
HistoryAudio : : HistoryAudio ( const MTPDaudio & audio ) : HistoryMedia ( )
2014-11-18 15:41:33 +03:00
, data ( App : : feedAudio ( audio ) )
2014-06-16 13:31:10 +04:00
, _openl ( new AudioOpenLink ( data ) )
, _savel ( new AudioSaveLink ( data ) )
, _cancell ( new AudioCancelLink ( data ) )
, _dldDone ( 0 )
, _uplDone ( 0 )
{
2014-05-30 12:53:19 +04:00
_size = formatDurationAndSizeText ( data - > duration , data - > size ) ;
if ( ! _openWithWidth ) {
_downloadWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_download ) ) ;
_openWithWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_open_with ) ) ;
_cancelWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_cancel ) ) ;
_buttonWidth = ( st : : mediaSaveButton . width > 0 ) ? st : : mediaSaveButton . width : ( ( _downloadWidth > _openWithWidth ? ( _downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth ) : _openWithWidth ) - st : : mediaSaveButton . width ) ;
}
}
2014-08-15 15:19:32 +04:00
void HistoryAudio : : initDimensions ( const HistoryItem * parent ) {
2014-10-10 16:46:20 +04:00
_maxw = st : : mediaMaxWidth ;
2014-05-30 12:53:19 +04:00
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
if ( ! parent - > out ( ) ) { // add Download / Save As button
_maxw + = st : : mediaSaveDelta + _buttonWidth ;
}
2014-10-10 16:46:20 +04:00
2015-03-19 12:18:19 +03:00
_minh = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
_minh + = st : : msgServiceNameFont - > height ;
2015-03-19 12:18:19 +03:00
}
_height = _minh ;
2014-05-30 12:53:19 +04:00
}
2014-08-15 15:19:32 +04:00
void HistoryAudio : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return ;
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-09-04 11:33:44 +04:00
bool out = parent - > out ( ) , hovered , pressed , already = ! data - > already ( ) . isEmpty ( ) , hasdata = ! data - > data . isEmpty ( ) ;
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
2015-05-24 20:58:39 +03:00
if ( ! data - > loader & & data - > status ! = FileFailed & & ! already & & ! hasdata & & data - > size < AudioVoiceMsgInMemory ) {
2014-09-04 11:33:44 +04:00
data - > save ( QString ( ) ) ;
}
2014-05-30 12:53:19 +04:00
if ( ! out ) { // draw Download / Save As button
hovered = ( ( data - > loader ? _cancell : _savel ) = = textlnkOver ( ) ) ;
pressed = hovered & & ( ( data - > loader ? _cancell : _savel ) = = textlnkDown ( ) ) ;
if ( hovered & & ! pressed & & textlnkDown ( ) ) hovered = false ;
2015-03-19 12:18:19 +03:00
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( _height - skipy - btnh ) / 2 ;
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? st : : msgInSelectBg : ( hovered ? st : : mediaSaveButton . overBgColor : st : : mediaSaveButton . bgColor ) ) ;
style : : color sh ( selected ? st : : msgInSelectShadow : st : : msgInShadow ) ;
RoundCorners cors ( selected ? MessageInSelectedCorners : ( hovered ? ButtonHoverCorners : MessageInCorners ) ) ;
App : : roundRect ( p , btnx , btny , btnw , btnh , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( ( hovered ? st : : mediaSaveButton . overColor : st : : mediaSaveButton . color ) - > p ) ;
p . setFont ( st : : mediaSaveButton . font - > f ) ;
2014-09-04 11:33:44 +04:00
QString btnText ( lang ( data - > loader ? lng_media_cancel : ( already ? lng_media_open_with : lng_media_download ) ) ) ;
int32 btnTextWidth = data - > loader ? _cancelWidth : ( already ? _openWithWidth : _downloadWidth ) ;
2014-05-30 12:53:19 +04:00
p . drawText ( btnx + ( btnw - btnTextWidth ) / 2 , btny + ( pressed ? st : : mediaSaveButton . downTextTop : st : : mediaSaveButton . textTop ) + st : : mediaSaveButton . font - > ascent , btnText ) ;
width - = btnw + st : : mediaSaveDelta ;
}
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , 0 , 0 , width , _height , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2015-03-19 12:18:19 +03:00
if ( reply ) {
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
2015-07-01 00:07:05 +03:00
AudioMsgId playing ;
2015-05-29 21:52:43 +03:00
AudioPlayerState playingState = AudioPlayerStopped ;
2014-09-04 11:33:44 +04:00
int64 playingPosition = 0 , playingDuration = 0 ;
2015-05-24 20:58:39 +03:00
int32 playingFrequency = 0 ;
2015-05-29 21:52:43 +03:00
if ( audioPlayer ( ) ) {
audioPlayer ( ) - > currentState ( & playing , & playingState , & playingPosition , & playingDuration , & playingFrequency ) ;
2014-09-04 11:33:44 +04:00
}
2015-05-24 20:58:39 +03:00
2014-09-04 11:33:44 +04:00
QRect img ;
2015-06-02 14:22:00 +03:00
QString statusText ;
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
img = out ? st : : mediaAudioOutImg : st : : mediaAudioInImg ;
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
img = out ? st : : mediaAudioOutImg : st : : mediaAudioInImg ;
} else if ( already | | hasdata ) {
bool showPause = false ;
2015-07-03 11:47:16 +03:00
if ( playing . msgId = = parent - > id & & ! ( playingState & AudioPlayerStoppedMask ) & & playingState ! = AudioPlayerFinishing ) {
2015-06-02 14:22:00 +03:00
statusText = formatDurationText ( playingPosition / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) + qsl ( " / " ) + formatDurationText ( playingDuration / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) ;
showPause = ( playingState = = AudioPlayerPlaying | | playingState = = AudioPlayerResuming | | playingState = = AudioPlayerStarting ) ;
} else {
statusText = formatDurationText ( data - > duration ) ;
}
2014-09-04 11:33:44 +04:00
img = out ? ( showPause ? st : : mediaPauseOutImg : st : : mediaPlayOutImg ) : ( showPause ? st : : mediaPauseInImg : st : : mediaPlayInImg ) ;
} else {
2015-06-02 14:22:00 +03:00
if ( data - > loader ) {
2015-07-03 11:47:16 +03:00
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
2015-06-02 14:22:00 +03:00
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
statusText = _size ;
}
2014-09-04 11:33:44 +04:00
img = out ? st : : mediaAudioOutImg : st : : mediaAudioInImg ;
}
2015-06-02 14:22:00 +03:00
2015-03-19 12:18:19 +03:00
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , App : : sprite ( ) , img ) ;
2014-05-30 12:53:19 +04:00
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) , st : : mediaThumbSize , st : : mediaThumbSize , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-05-30 12:53:19 +04:00
}
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
int32 twidth = width - tleft - st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
int32 secondwidth = width - tleft - fullTimeWidth ;
p . setFont ( st : : mediaFont - > f ) ;
p . setPen ( st : : black - > c ) ;
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , lang ( lng_media_audio ) ) ;
2014-05-30 12:53:19 +04:00
style : : color status ( selected ? ( out ? st : : mediaOutSelectColor : st : : mediaInSelectColor ) : ( out ? st : : mediaOutColor : st : : mediaInColor ) ) ;
p . setPen ( status - > p ) ;
2015-04-30 16:53:36 +03:00
int32 texty = skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize - st : : mediaDetailsShift - st : : mediaFont - > height ;
p . drawText ( tleft , texty + st : : mediaFont - > ascent , statusText ) ;
if ( parent - > isMediaUnread ( ) ) {
int32 w = st : : mediaFont - > m . width ( statusText ) ;
if ( w + st : : mediaUnreadSkip + st : : mediaUnreadSize < = twidth ) {
p . setRenderHint ( QPainter : : HighQualityAntialiasing , true ) ;
p . setPen ( Qt : : NoPen ) ;
p . setBrush ( ( out ? ( selected ? st : : mediaOutUnreadSelectColor : st : : mediaOutUnreadColor ) : ( selected ? st : : mediaInUnreadSelectColor : st : : mediaInUnreadColor ) ) - > b ) ;
p . drawEllipse ( QRect ( tleft + w + st : : mediaUnreadSkip , texty + ( ( st : : mediaFont - > height - st : : mediaUnreadSize ) / 2 ) , st : : mediaUnreadSize , st : : mediaUnreadSize ) ) ;
p . setRenderHint ( QPainter : : HighQualityAntialiasing , false ) ;
}
}
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgDateFont - > f ) ;
style : : color date ( selected ? ( out ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
2014-08-15 15:19:32 +04:00
p . drawText ( width + st : : msgDateDelta . x ( ) - fullTimeWidth + st : : msgDateSpace , _height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , parent - > time ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( out ) {
2014-06-15 16:31:03 +04:00
QPoint iconPos ( width + 5 - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , _height + 1 - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
2014-05-30 12:53:19 +04:00
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
void HistoryAudio : : regItem ( HistoryItem * item ) {
App : : regAudioItem ( data , item ) ;
}
void HistoryAudio : : unregItem ( HistoryItem * item ) {
App : : unregAudioItem ( data , item ) ;
}
2015-05-29 21:52:43 +03:00
void HistoryAudio : : updateFrom ( const MTPMessageMedia & media ) {
if ( media . type ( ) = = mtpc_messageMediaAudio ) {
App : : feedAudio ( media . c_messageMediaAudio ( ) . vaudio , data ) ;
if ( ! data - > data . isEmpty ( ) ) {
Local : : writeAudio ( mediaKey ( mtpToLocationType ( mtpc_inputAudioFileLocation ) , data - > dc , data - > id ) , data - > data ) ;
}
}
}
2014-05-30 12:53:19 +04:00
const QString HistoryAudio : : inDialogsText ( ) const {
return lang ( lng_in_dlg_audio ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryAudio : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_audio ) + qsl ( " ] " ) ;
}
2014-10-10 16:46:20 +04:00
bool HistoryAudio : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
return ( x > = 0 & & y > = 0 & & x < width & & y < _height ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryAudio : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
bool out = parent - > out ( ) , hovered , pressed ;
if ( width > = _maxw ) {
width = _maxw ;
}
if ( ! out ) { // draw Download / Save As button
2015-03-19 12:18:19 +03:00
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( _height - skipy - btnh ) / 2 ;
2014-05-30 12:53:19 +04:00
if ( x > = btnx & & y > = btny & & x < btnx + btnw & & y < btny + btnh ) {
2015-04-08 02:03:32 +03:00
lnk = data - > loader ? _cancell : _savel ;
return ;
2014-05-30 12:53:19 +04:00
}
width - = btnw + st : : mediaSaveDelta ;
}
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
}
if ( reply ) {
2015-03-19 12:18:19 +03:00
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
2015-04-08 02:03:32 +03:00
lnk = reply - > replyToLink ( ) ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
if ( y > = fwdFrom & & y < skipy ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-23 18:50:11 +03:00
}
2015-03-19 12:18:19 +03:00
}
if ( x > = 0 & & y > = skipy & & x < width & & y < _height & & ! data - > loader & & data - > access ) {
2015-04-08 02:03:32 +03:00
lnk = _openl ;
return ;
2014-05-30 12:53:19 +04:00
}
}
HistoryMedia * HistoryAudio : : clone ( ) const {
2014-10-10 16:46:20 +04:00
return new HistoryAudio ( * this ) ;
2014-05-30 12:53:19 +04:00
}
2015-07-01 00:07:05 +03:00
namespace {
QString documentName ( DocumentData * document ) {
SongData * song = document - > song ( ) ;
if ( ! song | | ( song - > title . isEmpty ( ) & & song - > performer . isEmpty ( ) ) ) return document - > name ;
if ( song - > performer . isEmpty ( ) ) return song - > title ;
2015-07-03 11:47:16 +03:00
return song - > performer + QString : : fromUtf8 ( " \xe2 \x80 \x93 " ) + ( song - > title . isEmpty ( ) ? qsl ( " Unknown Track " ) : song - > title ) ;
2015-07-01 00:07:05 +03:00
}
}
2015-04-04 23:01:34 +03:00
HistoryDocument : : HistoryDocument ( DocumentData * document ) : HistoryMedia ( )
2014-12-23 02:11:37 +03:00
, data ( document )
2014-06-16 13:31:10 +04:00
, _openl ( new DocumentOpenLink ( data ) )
, _savel ( new DocumentSaveLink ( data ) )
, _cancell ( new DocumentCancelLink ( data ) )
2015-07-01 00:07:05 +03:00
, _name ( documentName ( data ) )
2014-06-16 13:31:10 +04:00
, _dldDone ( 0 )
, _uplDone ( 0 )
{
2014-05-30 12:53:19 +04:00
_namew = st : : mediaFont - > m . width ( _name . isEmpty ( ) ? qsl ( " Document " ) : _name ) ;
2015-07-01 00:07:05 +03:00
_size = document - > song ( ) ? formatDurationAndSizeText ( document - > song ( ) - > duration , data - > size ) : formatSizeText ( data - > size ) ;
2014-05-30 12:53:19 +04:00
2014-10-10 16:46:20 +04:00
_height = _minh = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
2014-05-30 12:53:19 +04:00
if ( ! _openWithWidth ) {
_downloadWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_download ) ) ;
_openWithWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_open_with ) ) ;
_cancelWidth = st : : mediaSaveButton . font - > m . width ( lang ( lng_media_cancel ) ) ;
_buttonWidth = ( st : : mediaSaveButton . width > 0 ) ? st : : mediaSaveButton . width : ( ( _downloadWidth > _openWithWidth ? ( _downloadWidth > _cancelWidth ? _downloadWidth : _cancelWidth ) : _openWithWidth ) - st : : mediaSaveButton . width ) ;
}
data - > thumb - > load ( ) ;
int32 tw = data - > thumb - > width ( ) , th = data - > thumb - > height ( ) ;
if ( data - > thumb - > isNull ( ) | | ! tw | | ! th ) {
_thumbw = _thumbx = _thumby = 0 ;
} else if ( tw > th ) {
_thumbw = ( tw * st : : mediaThumbSize ) / th ;
_thumbx = ( _thumbw - st : : mediaThumbSize ) / 2 ;
_thumby = 0 ;
} else {
_thumbw = st : : mediaThumbSize ;
_thumbx = 0 ;
_thumby = ( ( th * _thumbw ) / tw - st : : mediaThumbSize ) / 2 ;
}
}
2014-08-15 15:19:32 +04:00
void HistoryDocument : : initDimensions ( const HistoryItem * parent ) {
2014-10-10 16:46:20 +04:00
if ( parent = = animated . msg ) {
2015-06-02 17:00:30 +03:00
_maxw = animated . w / cIntRetinaFactor ( ) ;
_minh = animated . h / cIntRetinaFactor ( ) ;
2014-10-10 16:46:20 +04:00
} else {
_maxw = st : : mediaMaxWidth ;
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
if ( _namew + tleft + st : : mediaPadding . right ( ) > _maxw ) {
_maxw = _namew + tleft + st : : mediaPadding . right ( ) ;
}
if ( ! parent - > out ( ) ) { // add Download / Save As button
_maxw + = st : : mediaSaveDelta + _buttonWidth ;
}
2015-03-19 12:18:19 +03:00
_minh = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
2015-07-03 21:03:47 +03:00
if ( ! data - > song ( ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) ;
}
_minh + = st : : msgServiceNameFont - > height ;
2015-03-19 12:18:19 +03:00
}
}
2014-05-30 12:53:19 +04:00
}
2015-04-19 13:29:19 +03:00
_height = _minh ;
2014-05-30 12:53:19 +04:00
}
2014-08-15 15:19:32 +04:00
void HistoryDocument : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return ;
2015-07-01 00:07:05 +03:00
bool out = parent - > out ( ) , hovered , pressed , already = ! data - > already ( ) . isEmpty ( ) , hasdata = ! data - > data . isEmpty ( ) ;
2014-10-10 16:46:20 +04:00
if ( parent = = animated . msg ) {
2015-06-02 17:00:30 +03:00
int32 pw = animated . w / cIntRetinaFactor ( ) , ph = animated . h / cIntRetinaFactor ( ) ;
2015-05-21 15:08:05 +03:00
if ( width < pw ) {
pw = width ;
ph = ( pw = = w ) ? _height : ( pw * animated . h / animated . w ) ;
if ( ph < 1 ) ph = 1 ;
}
2015-05-22 14:14:52 +03:00
App : : roundShadow ( p , 0 , 0 , pw , ph , selected ? st : : msgInSelectShadow : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
2015-05-21 15:08:05 +03:00
2015-06-02 17:00:30 +03:00
p . drawPixmap ( 0 , 0 , animated . current ( pw * cIntRetinaFactor ( ) , ph * cIntRetinaFactor ( ) , true ) ) ;
2015-05-21 15:08:05 +03:00
if ( selected ) {
App : : roundRect ( p , 0 , 0 , pw , ph , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-10-10 16:46:20 +04:00
}
return ;
}
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-07-03 21:03:47 +03:00
const HistoryForwarded * fwd = ( reply | | data - > song ( ) ) ? 0 : toHistoryForwarded ( parent ) ;
2015-04-23 18:50:11 +03:00
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
if ( ! out ) { // draw Download / Save As button
hovered = ( ( data - > loader ? _cancell : _savel ) = = textlnkOver ( ) ) ;
pressed = hovered & & ( ( data - > loader ? _cancell : _savel ) = = textlnkDown ( ) ) ;
if ( hovered & & ! pressed & & textlnkDown ( ) ) hovered = false ;
2015-03-19 12:18:19 +03:00
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( _height - skipy - btnh ) / 2 ;
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? st : : msgInSelectBg : ( hovered ? st : : mediaSaveButton . overBgColor : st : : mediaSaveButton . bgColor ) ) ;
style : : color sh ( selected ? st : : msgInSelectShadow : st : : msgInShadow ) ;
RoundCorners cors ( selected ? MessageInSelectedCorners : ( hovered ? ButtonHoverCorners : MessageInCorners ) ) ;
App : : roundRect ( p , btnx , btny , btnw , btnh , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( ( hovered ? st : : mediaSaveButton . overColor : st : : mediaSaveButton . color ) - > p ) ;
p . setFont ( st : : mediaSaveButton . font - > f ) ;
2015-07-01 00:07:05 +03:00
QString btnText ( lang ( data - > loader ? lng_media_cancel : ( already ? lng_media_open_with : lng_media_download ) ) ) ;
int32 btnTextWidth = data - > loader ? _cancelWidth : ( already ? _openWithWidth : _downloadWidth ) ;
2014-05-30 12:53:19 +04:00
p . drawText ( btnx + ( btnw - btnTextWidth ) / 2 , btny + ( pressed ? st : : mediaSaveButton . downTextTop : st : : mediaSaveButton . textTop ) + st : : mediaSaveButton . font - > ascent , btnText ) ;
width - = btnw + st : : mediaSaveDelta ;
}
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , 0 , 0 , width , _height , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2015-03-19 12:18:19 +03:00
if ( reply ) {
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
2015-07-01 00:07:05 +03:00
QString statusText ;
if ( data - > song ( ) ) {
SongMsgId playing ;
AudioPlayerState playingState = AudioPlayerStopped ;
int64 playingPosition = 0 , playingDuration = 0 ;
int32 playingFrequency = 0 ;
if ( audioPlayer ( ) ) {
audioPlayer ( ) - > currentState ( & playing , & playingState , & playingPosition , & playingDuration , & playingFrequency ) ;
}
QRect img ;
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
2015-07-03 21:03:47 +03:00
img = out ? st : : mediaMusicOutImg : st : : mediaMusicInImg ;
2015-07-01 00:07:05 +03:00
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
2015-07-03 21:03:47 +03:00
img = out ? st : : mediaMusicOutImg : st : : mediaMusicInImg ;
2015-07-01 00:07:05 +03:00
} else if ( already | | hasdata ) {
bool showPause = false ;
2015-07-03 11:47:16 +03:00
if ( playing . msgId = = parent - > id & & ! ( playingState & AudioPlayerStoppedMask ) & & playingState ! = AudioPlayerFinishing ) {
2015-07-01 00:07:05 +03:00
statusText = formatDurationText ( playingPosition / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) + qsl ( " / " ) + formatDurationText ( playingDuration / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) ;
showPause = ( playingState = = AudioPlayerPlaying | | playingState = = AudioPlayerResuming | | playingState = = AudioPlayerStarting ) ;
} else {
statusText = formatDurationText ( data - > song ( ) - > duration ) ;
}
2015-07-03 11:47:16 +03:00
if ( ! showPause & & playing . msgId = = parent - > id & & App : : main ( ) & & App : : main ( ) - > player ( ) - > seekingSong ( playing ) ) showPause = true ;
2015-07-01 00:07:05 +03:00
img = out ? ( showPause ? st : : mediaPauseOutImg : st : : mediaPlayOutImg ) : ( showPause ? st : : mediaPauseInImg : st : : mediaPlayInImg ) ;
} else {
if ( data - > loader ) {
2015-07-03 11:47:16 +03:00
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
2015-07-01 00:07:05 +03:00
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
statusText = _size ;
}
2015-07-03 21:03:47 +03:00
img = out ? st : : mediaMusicOutImg : st : : mediaMusicInImg ;
2015-07-01 00:07:05 +03:00
}
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , App : : sprite ( ) , img ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-07-01 00:07:05 +03:00
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
} else if ( data - > loader ) {
2015-07-03 11:47:16 +03:00
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
2015-07-01 00:07:05 +03:00
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
statusText = _size ;
}
if ( _thumbw ) {
data - > thumb - > checkload ( ) ;
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , data - > thumb - > pixSingle ( _thumbw , 0 , st : : mediaThumbSize , st : : mediaThumbSize ) ) ;
} else {
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) ) , App : : sprite ( ) , ( out ? st : : mediaDocOutImg : st : : mediaDocInImg ) ) ;
}
2014-05-30 12:53:19 +04:00
}
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) , st : : mediaThumbSize , st : : mediaThumbSize , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-05-30 12:53:19 +04:00
}
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
int32 twidth = width - tleft - st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
int32 secondwidth = width - tleft - fullTimeWidth ;
p . setFont ( st : : mediaFont - > f ) ;
p . setPen ( st : : black - > c ) ;
if ( twidth < _namew ) {
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , st : : mediaFont - > m . elidedText ( _name , Qt : : ElideRight , twidth ) ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , _name ) ;
2014-05-30 12:53:19 +04:00
}
style : : color status ( selected ? ( out ? st : : mediaOutSelectColor : st : : mediaInSelectColor ) : ( out ? st : : mediaOutColor : st : : mediaInColor ) ) ;
p . setPen ( status - > p ) ;
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize - st : : mediaDetailsShift - st : : mediaFont - > descent , statusText ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgDateFont - > f ) ;
style : : color date ( selected ? ( out ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
2014-08-15 15:19:32 +04:00
p . drawText ( width + st : : msgDateDelta . x ( ) - fullTimeWidth + st : : msgDateSpace , _height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , parent - > time ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( out ) {
2014-06-15 16:31:03 +04:00
QPoint iconPos ( width + 5 - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , _height + 1 - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
2014-05-30 12:53:19 +04:00
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
2015-07-03 13:48:28 +03:00
void HistoryDocument : : drawInPlaylist ( QPainter & p , const HistoryItem * parent , bool selected , bool over , int32 width ) const {
bool out = parent - > out ( ) , already = ! data - > already ( ) . isEmpty ( ) , hasdata = ! data - > data . isEmpty ( ) ;
int32 height = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
style : : color bg ( selected ? st : : msgInSelectBg : ( over ? st : : playlistHoverBg : st : : msgInBg ) ) ;
p . fillRect ( 0 , 0 , width , height , bg - > b ) ;
QString statusText ;
if ( data - > song ( ) ) {
SongMsgId playing ;
AudioPlayerState playingState = AudioPlayerStopped ;
int64 playingPosition = 0 , playingDuration = 0 ;
int32 playingFrequency = 0 ;
if ( audioPlayer ( ) ) {
audioPlayer ( ) - > currentState ( & playing , & playingState , & playingPosition , & playingDuration , & playingFrequency ) ;
}
QRect img ;
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
2015-07-03 21:03:47 +03:00
img = st : : mediaMusicInImg ;
2015-07-03 13:48:28 +03:00
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
2015-07-03 21:03:47 +03:00
img = st : : mediaMusicInImg ;
2015-07-03 13:48:28 +03:00
} else if ( already | | hasdata ) {
bool isPlaying = ( playing . msgId = = parent - > id ) ;
bool showPause = false ;
if ( playing . msgId = = parent - > id & & ! ( playingState & AudioPlayerStoppedMask ) & & playingState ! = AudioPlayerFinishing ) {
statusText = formatDurationText ( playingPosition / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) + qsl ( " / " ) + formatDurationText ( playingDuration / ( playingFrequency ? playingFrequency : AudioVoiceMsgFrequency ) ) ;
showPause = ( playingState = = AudioPlayerPlaying | | playingState = = AudioPlayerResuming | | playingState = = AudioPlayerStarting ) ;
} else {
statusText = formatDurationText ( data - > song ( ) - > duration ) ;
}
if ( ! showPause & & playing . msgId = = parent - > id & & App : : main ( ) & & App : : main ( ) - > player ( ) - > seekingSong ( playing ) ) showPause = true ;
img = isPlaying ? ( showPause ? st : : mediaPauseOutImg : st : : mediaPlayOutImg ) : ( showPause ? st : : mediaPauseInImg : st : : mediaPlayInImg ) ;
} else {
if ( data - > loader ) {
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
statusText = _size ;
}
2015-07-03 21:03:47 +03:00
img = st : : mediaMusicInImg ;
2015-07-03 13:48:28 +03:00
}
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , st : : mediaPadding . top ( ) ) , App : : sprite ( ) , img ) ;
} else {
if ( data - > status = = FileFailed ) {
statusText = lang ( lng_attach_failed ) ;
} else if ( data - > status = = FileUploading ) {
if ( _uplTextCache . isEmpty ( ) | | _uplDone ! = data - > uploadOffset ) {
_uplDone = data - > uploadOffset ;
_uplTextCache = formatDownloadText ( _uplDone , data - > size ) ;
}
statusText = _uplTextCache ;
} else if ( data - > loader ) {
int32 offset = data - > loader - > currentOffset ( ) ;
if ( _dldTextCache . isEmpty ( ) | | _dldDone ! = offset ) {
_dldDone = offset ;
_dldTextCache = formatDownloadText ( _dldDone , data - > size ) ;
}
statusText = _dldTextCache ;
} else {
statusText = _size ;
}
if ( _thumbw ) {
data - > thumb - > checkload ( ) ;
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , st : : mediaPadding . top ( ) ) , data - > thumb - > pixSingle ( _thumbw , 0 , st : : mediaThumbSize , st : : mediaThumbSize ) ) ;
} else {
p . drawPixmap ( QPoint ( st : : mediaPadding . left ( ) , st : : mediaPadding . top ( ) ) , App : : sprite ( ) , st : : mediaDocInImg ) ;
}
}
if ( selected ) {
App : : roundRect ( p , st : : mediaPadding . left ( ) , st : : mediaPadding . top ( ) , st : : mediaThumbSize , st : : mediaThumbSize , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
int32 twidth = width - tleft - st : : mediaPadding . right ( ) ;
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
int32 secondwidth = width - tleft - fullTimeWidth ;
p . setFont ( st : : mediaFont - > f ) ;
p . setPen ( st : : black - > c ) ;
if ( twidth < _namew ) {
p . drawText ( tleft , st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , st : : mediaFont - > m . elidedText ( _name , Qt : : ElideRight , twidth ) ) ;
} else {
p . drawText ( tleft , st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , _name ) ;
}
style : : color status ( selected ? st : : mediaInSelectColor : st : : mediaInColor ) ;
p . setPen ( status - > p ) ;
p . drawText ( tleft , st : : mediaPadding . top ( ) + st : : mediaThumbSize - st : : mediaDetailsShift - st : : mediaFont - > descent , statusText ) ;
}
TextLinkPtr HistoryDocument : : linkInPlaylist ( ) {
if ( ! data - > loader & & data - > access ) {
return _openl ;
}
return TextLinkPtr ( ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryDocument : : regItem ( HistoryItem * item ) {
App : : regDocumentItem ( data , item ) ;
}
void HistoryDocument : : unregItem ( HistoryItem * item ) {
App : : unregDocumentItem ( data , item ) ;
}
void HistoryDocument : : updateFrom ( const MTPMessageMedia & media ) {
if ( media . type ( ) = = mtpc_messageMediaDocument ) {
2015-01-02 17:55:24 +03:00
App : : feedDocument ( media . c_messageMediaDocument ( ) . vdocument , data ) ;
2014-05-30 12:53:19 +04:00
}
}
2014-10-10 16:46:20 +04:00
int32 HistoryDocument : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
2014-11-18 15:41:33 +03:00
w = qMin ( width , _maxw ) ;
2014-10-10 16:46:20 +04:00
if ( parent = = animated . msg ) {
2014-11-18 15:41:33 +03:00
if ( w > st : : maxMediaSize ) {
w = st : : maxMediaSize ;
}
2015-06-02 17:00:30 +03:00
_height = animated . h / cIntRetinaFactor ( ) ;
if ( animated . w / cIntRetinaFactor ( ) > w ) {
_height = ( w * _height / ( animated . w / cIntRetinaFactor ( ) ) ) ;
2014-10-10 16:46:20 +04:00
if ( _height < = 0 ) _height = 1 ;
}
2015-03-19 12:18:19 +03:00
} else {
_height = _minh ;
2014-10-10 16:46:20 +04:00
}
2014-05-30 12:53:19 +04:00
return _height ;
}
const QString HistoryDocument : : inDialogsText ( ) const {
2015-07-01 00:07:05 +03:00
return _name . isEmpty ( ) ? lang ( lng_in_dlg_file ) : _name ;
2014-05-30 12:53:19 +04:00
}
2014-11-22 12:45:04 +03:00
const QString HistoryDocument : : inHistoryText ( ) const {
2015-07-01 00:07:05 +03:00
return qsl ( " [ " ) + lang ( lng_in_dlg_file ) + ( _name . isEmpty ( ) ? QString ( ) : ( qsl ( " : " ) + _name ) ) + qsl ( " ] " ) ;
2014-11-22 12:45:04 +03:00
}
2014-10-10 16:46:20 +04:00
bool HistoryDocument : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width > = _maxw ) {
width = _maxw ;
}
2014-10-10 16:46:20 +04:00
if ( parent = = animated . msg ) {
int32 h = ( width = = w ) ? _height : ( width * animated . h / animated . w ) ;
if ( h < 1 ) h = 1 ;
return ( x > = 0 & & y > = 0 & & x < width & & y < h ) ;
}
2014-05-30 12:53:19 +04:00
return ( x > = 0 & & y > = 0 & & x < width & & y < _height ) ;
}
2014-10-10 16:46:20 +04:00
int32 HistoryDocument : : countHeight ( const HistoryItem * parent , int32 width ) const {
if ( width < 0 ) width = w ;
if ( width > = _maxw ) {
width = _maxw ;
}
if ( parent = = animated . msg ) {
int32 h = ( width = = w ) ? _height : ( width * animated . h / animated . w ) ;
if ( h < 1 ) h = 1 ;
return h ;
}
return _height ;
}
2015-06-27 16:02:00 +03:00
void HistoryDocument : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2014-05-30 12:53:19 +04:00
bool out = parent - > out ( ) , hovered , pressed ;
if ( width > = _maxw ) {
width = _maxw ;
}
2014-10-10 16:46:20 +04:00
if ( parent = = animated . msg ) {
int32 h = ( width = = w ) ? _height : ( width * animated . h / animated . w ) ;
if ( h < 1 ) h = 1 ;
2015-04-08 02:03:32 +03:00
lnk = ( x > = 0 & & y > = 0 & & x < width & & y < h ) ? _openl : TextLinkPtr ( ) ;
return ;
2014-10-10 16:46:20 +04:00
}
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-07-03 21:03:47 +03:00
const HistoryForwarded * fwd = ( reply | | data - > song ( ) ) ? 0 : toHistoryForwarded ( parent ) ;
2015-04-23 18:50:11 +03:00
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
if ( ! out ) { // draw Download / Save As button
2015-03-19 12:18:19 +03:00
int32 btnw = _buttonWidth , btnh = st : : mediaSaveButton . height , btnx = width - _buttonWidth , btny = skipy + ( _height - skipy - btnh ) / 2 ;
2014-05-30 12:53:19 +04:00
if ( x > = btnx & & y > = btny & & x < btnx + btnw & & y < btny + btnh ) {
2015-04-08 02:03:32 +03:00
lnk = data - > loader ? _cancell : _savel ;
return ;
2014-05-30 12:53:19 +04:00
}
width - = btnw + st : : mediaSaveDelta ;
}
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
}
if ( reply ) {
2015-03-19 12:18:19 +03:00
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
2015-04-08 02:03:32 +03:00
lnk = reply - > replyToLink ( ) ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
if ( y > = fwdFrom & & y < skipy ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-23 18:50:11 +03:00
}
2015-03-19 12:18:19 +03:00
}
if ( x > = 0 & & y > = skipy & & x < width & & y < _height & & ! data - > loader & & data - > access ) {
2015-04-08 02:03:32 +03:00
lnk = _openl ;
return ;
2014-05-30 12:53:19 +04:00
}
}
HistoryMedia * HistoryDocument : : clone ( ) const {
2014-10-10 16:46:20 +04:00
return new HistoryDocument ( * this ) ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
ImagePtr HistoryDocument : : replyPreview ( ) {
if ( data - > replyPreview - > isNull ( ) & & ! data - > thumb - > isNull ( ) ) {
if ( data - > thumb - > loaded ( ) ) {
int w = data - > thumb - > width ( ) , h = data - > thumb - > height ( ) ;
if ( w < = 0 ) w = 1 ;
if ( h < = 0 ) h = 1 ;
data - > replyPreview = ImagePtr ( w > h ? data - > thumb - > pix ( w * st : : msgReplyBarSize . height ( ) / h , st : : msgReplyBarSize . height ( ) ) : data - > thumb - > pix ( st : : msgReplyBarSize . height ( ) ) , " PNG " ) ;
} else {
data - > thumb - > load ( ) ;
}
}
return data - > replyPreview ;
}
2015-04-04 23:01:34 +03:00
HistorySticker : : HistorySticker ( DocumentData * document ) : HistoryMedia ( )
, pixw ( 1 ) , pixh ( 1 ) , data ( document ) , lastw ( 0 )
2014-12-23 02:11:37 +03:00
{
data - > thumb - > load ( ) ;
2015-07-03 11:47:16 +03:00
if ( ! data - > sticker ( ) - > alt . isEmpty ( ) ) {
_emoji = data - > sticker ( ) - > alt ;
2015-07-01 00:27:56 +03:00
}
2015-01-05 23:17:33 +03:00
}
void HistorySticker : : initDimensions ( const HistoryItem * parent ) {
pixw = data - > dimensions . width ( ) ;
pixh = data - > dimensions . height ( ) ;
if ( pixw > st : : maxStickerSize ) {
pixh = ( st : : maxStickerSize * pixh ) / pixw ;
pixw = st : : maxStickerSize ;
}
if ( pixh > st : : maxStickerSize ) {
pixw = ( st : : maxStickerSize * pixw ) / pixh ;
pixh = st : : maxStickerSize ;
}
if ( pixw < 1 ) pixw = 1 ;
if ( pixh < 1 ) pixh = 1 ;
_maxw = qMax ( pixw , int16 ( st : : minPhotoSize ) ) ;
_minh = qMax ( pixh , int16 ( st : : minPhotoSize ) ) ;
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
2015-06-02 14:22:00 +03:00
_maxw + = st : : msgReplyPadding . left ( ) + reply - > replyToWidth ( ) ;
2015-03-19 12:18:19 +03:00
}
_height = _minh ;
w = qMin ( lastw , _maxw ) ;
2014-12-23 02:11:37 +03:00
}
void HistorySticker : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
if ( width < 1 ) return ;
2015-01-02 17:55:24 +03:00
if ( width > _maxw ) width = _maxw ;
2014-12-23 02:11:37 +03:00
2015-03-19 12:18:19 +03:00
int32 usew = _maxw , usex = 0 ;
const HistoryReply * reply = toHistoryReply ( parent ) ;
if ( reply ) {
2015-06-02 14:22:00 +03:00
usew - = st : : msgReplyPadding . left ( ) + reply - > replyToWidth ( ) ;
2015-03-19 12:18:19 +03:00
if ( parent - > out ( ) ) {
usex = width - usew ;
}
}
2014-12-23 02:11:37 +03:00
bool out = parent - > out ( ) , hovered , pressed , already = ! data - > already ( ) . isEmpty ( ) , hasdata = ! data - > data . isEmpty ( ) ;
if ( ! data - > loader & & data - > status ! = FileFailed & & ! already & & ! hasdata ) {
data - > save ( QString ( ) ) ;
}
2015-07-01 00:07:05 +03:00
if ( data - > sticker ( ) - > img - > isNull ( ) & & ( already | | hasdata ) ) {
2014-12-23 02:11:37 +03:00
if ( already ) {
2015-07-01 00:07:05 +03:00
data - > sticker ( ) - > img = ImagePtr ( data - > already ( ) ) ;
2014-12-23 02:11:37 +03:00
} else {
2015-07-01 00:07:05 +03:00
data - > sticker ( ) - > img = ImagePtr ( data - > data ) ;
2014-12-23 02:11:37 +03:00
}
}
if ( selected ) {
2015-07-01 00:07:05 +03:00
if ( data - > sticker ( ) - > img - > isNull ( ) ) {
2015-03-19 12:18:19 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - pixw ) / 2 , ( _minh - pixh ) / 2 ) , data - > thumb - > pixBlurredColored ( st : : msgStickerOverlay , pixw , pixh ) ) ;
2015-01-05 23:17:33 +03:00
} else {
2015-07-01 00:07:05 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - pixw ) / 2 , ( _minh - pixh ) / 2 ) , data - > sticker ( ) - > img - > pixColored ( st : : msgStickerOverlay , pixw , pixh ) ) ;
2015-01-05 23:17:33 +03:00
}
} else {
2015-07-01 00:07:05 +03:00
if ( data - > sticker ( ) - > img - > isNull ( ) ) {
2015-03-19 12:18:19 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - pixw ) / 2 , ( _minh - pixh ) / 2 ) , data - > thumb - > pixBlurred ( pixw , pixh ) ) ;
2015-01-05 23:17:33 +03:00
} else {
2015-07-01 00:07:05 +03:00
p . drawPixmap ( QPoint ( usex + ( usew - pixw ) / 2 , ( _minh - pixh ) / 2 ) , data - > sticker ( ) - > img - > pix ( pixw , pixh ) ) ;
2015-01-05 23:17:33 +03:00
}
2014-12-23 02:11:37 +03:00
}
// date
QString time ( parent - > time ( ) ) ;
if ( time . isEmpty ( ) ) return ;
2015-04-30 16:53:36 +03:00
int32 dateX = usex + usew - parent - > timeWidth ( false ) - st : : msgDateImgDelta - 2 * st : : msgDateImgPadding . x ( ) ;
2014-12-23 02:11:37 +03:00
int32 dateY = _height - st : : msgDateFont - > height - 2 * st : : msgDateImgPadding . y ( ) - st : : msgDateImgDelta ;
if ( parent - > out ( ) ) {
dateX - = st : : msgCheckRect . pxWidth ( ) + st : : msgDateImgCheckSpace ;
}
2015-03-19 12:18:19 +03:00
int32 dateW = usex + usew - dateX - st : : msgDateImgDelta ;
2014-12-23 02:11:37 +03:00
int32 dateH = _height - dateY - st : : msgDateImgDelta ;
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , dateX , dateY , dateW , dateH , selected ? st : : msgDateImgSelectBg : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2014-12-23 02:11:37 +03:00
p . setFont ( st : : msgDateFont - > f ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
p . drawText ( dateX + st : : msgDateImgPadding . x ( ) , dateY + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , time ) ;
if ( out ) {
QPoint iconPos ( dateX - 2 + dateW - st : : msgDateImgCheckSpace - st : : msgCheckRect . pxWidth ( ) , dateY + ( dateH - st : : msgCheckRect . pxHeight ( ) ) / 2 ) ;
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & st : : msgImgCheckRect ;
} else {
iconRect = & st : : msgImgDblCheckRect ;
}
} else {
iconRect = & st : : msgImgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
2015-03-19 12:18:19 +03:00
if ( reply ) {
2015-06-02 14:22:00 +03:00
int32 rw = width - usew - st : : msgReplyPadding . left ( ) , rh = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
int32 rx = parent - > out ( ) ? 0 : ( usew + st : : msgReplyPadding . left ( ) ) , ry = _height - rh ;
2015-03-19 12:18:19 +03:00
2015-05-21 00:33:39 +03:00
App : : roundRect ( p , rx , ry , rw , rh , selected ? App : : msgServiceSelectBg ( ) : App : : msgServiceBg ( ) , selected ? ServiceSelectedCorners : ServiceCorners ) ;
2015-03-19 12:18:19 +03:00
reply - > drawReplyTo ( p , rx + st : : msgReplyPadding . left ( ) , ry , rw - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected , true ) ;
}
}
int32 HistorySticker : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
w = qMin ( width , _maxw ) ;
lastw = width ;
return _height ;
2014-12-23 02:11:37 +03:00
}
void HistorySticker : : regItem ( HistoryItem * item ) {
App : : regDocumentItem ( data , item ) ;
}
void HistorySticker : : unregItem ( HistoryItem * item ) {
App : : unregDocumentItem ( data , item ) ;
}
void HistorySticker : : updateFrom ( const MTPMessageMedia & media ) {
if ( media . type ( ) = = mtpc_messageMediaDocument ) {
2015-01-02 17:55:24 +03:00
App : : feedDocument ( media . c_messageMediaDocument ( ) . vdocument , data ) ;
2015-05-29 21:52:43 +03:00
if ( ! data - > data . isEmpty ( ) ) {
Local : : writeStickerImage ( mediaKey ( mtpToLocationType ( mtpc_inputDocumentFileLocation ) , data - > dc , data - > id ) , data - > data ) ;
}
2014-12-23 02:11:37 +03:00
}
}
const QString HistorySticker : : inDialogsText ( ) const {
2015-01-05 23:17:33 +03:00
return _emoji . isEmpty ( ) ? lang ( lng_in_dlg_sticker ) : lng_in_dlg_sticker_emoji ( lt_emoji , _emoji ) ;
2014-12-23 02:11:37 +03:00
}
const QString HistorySticker : : inHistoryText ( ) const {
2015-01-05 23:17:33 +03:00
return qsl ( " [ " ) + inDialogsText ( ) + qsl ( " ] " ) ;
2014-12-23 02:11:37 +03:00
}
bool HistorySticker : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
return ( x > = 0 & & y > = 0 & & x < _maxw & & y < _minh ) ;
}
int32 HistorySticker : : countHeight ( const HistoryItem * parent , int32 width ) const {
return _minh ;
}
2015-06-27 16:02:00 +03:00
void HistorySticker : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2015-03-19 12:18:19 +03:00
if ( width < 0 ) width = w ;
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2015-03-19 12:18:19 +03:00
if ( width > _maxw ) width = _maxw ;
int32 usew = _maxw , usex = 0 ;
const HistoryReply * reply = toHistoryReply ( parent ) ;
if ( reply ) {
usew - = reply - > replyToWidth ( ) ;
int32 rw = width - usew , rh = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
int32 rx = parent - > out ( ) ? 0 : usew , ry = _height - rh ;
if ( x > = rx & & y > = ry & & x < rx + rw & & y < ry + rh ) {
2015-04-08 02:03:32 +03:00
lnk = reply - > replyToLink ( ) ;
return ;
2015-03-19 12:18:19 +03:00
}
}
2014-12-23 02:11:37 +03:00
}
HistoryMedia * HistorySticker : : clone ( ) const {
return new HistorySticker ( * this ) ;
}
2014-11-18 15:41:33 +03:00
HistoryContact : : HistoryContact ( int32 userId , const QString & first , const QString & last , const QString & phone ) : HistoryMedia ( 0 )
, userId ( userId )
2014-06-16 13:31:10 +04:00
, phone ( App : : formatPhone ( phone ) )
, contact ( App : : userLoaded ( userId ) )
{
2014-05-30 12:53:19 +04:00
_maxw = st : : mediaMaxWidth ;
name . setText ( st : : mediaFont , ( first + ' ' + last ) . trimmed ( ) , _textNameOptions ) ;
phonew = st : : mediaFont - > m . width ( phone ) ;
if ( contact ) {
if ( contact - > phone . isEmpty ( ) ) {
contact - > setPhone ( phone ) ;
}
if ( contact - > contact < 0 ) {
contact - > contact = 0 ;
}
contact - > photo - > load ( ) ;
}
}
2014-08-15 15:19:32 +04:00
void HistoryContact : : initDimensions ( const HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( name . maxWidth ( ) + tleft + fullTimeWidth > _maxw ) {
_maxw = name . maxWidth ( ) + tleft + fullTimeWidth ;
}
if ( phonew + tleft + st : : mediaPadding . right ( ) > _maxw ) {
_maxw = phonew + tleft + st : : mediaPadding . right ( ) ;
}
2015-03-19 12:18:19 +03:00
_minh = st : : mediaPadding . top ( ) + st : : mediaThumbSize + st : : mediaPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-03-19 12:18:19 +03:00
if ( const HistoryReply * reply = toHistoryReply ( parent ) ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ) {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
_minh + = st : : msgServiceNameFont - > height ;
2015-03-19 12:18:19 +03:00
}
_height = _minh ;
2014-05-30 12:53:19 +04:00
}
const QString HistoryContact : : inDialogsText ( ) const {
return lang ( lng_in_dlg_contact ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryContact : : inHistoryText ( ) const {
return qsl ( " [ " ) + lang ( lng_in_dlg_contact ) + qsl ( " : " ) + name . original ( 0 , 0xFFFF , false ) + qsl ( " , " ) + phone + qsl ( " ] " ) ;
}
2014-10-10 16:46:20 +04:00
bool HistoryContact : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
return ( x > = 0 & & y < = 0 & & x < w & & y < _height ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
void HistoryContact : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-08-15 15:19:32 +04:00
if ( width < 0 ) width = w ;
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
}
if ( reply ) {
2015-03-19 12:18:19 +03:00
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
2015-04-08 02:03:32 +03:00
lnk = reply - > replyToLink ( ) ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
if ( y > = fwdFrom & & y < skipy ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-23 18:50:11 +03:00
}
2015-03-19 12:18:19 +03:00
}
if ( x > = 0 & & y > = skipy & & x < w & & y < _height & & contact ) {
2015-04-08 02:03:32 +03:00
lnk = contact - > lnk ;
return ;
2014-05-30 12:53:19 +04:00
}
}
HistoryMedia * HistoryContact : : clone ( ) const {
QStringList names = name . original ( 0 , 0xFFFF , false ) . split ( QChar ( ' ' ) , QString : : SkipEmptyParts ) ;
if ( names . isEmpty ( ) ) {
names . push_back ( QString ( ) ) ;
}
QString fname = names . front ( ) ;
names . pop_front ( ) ;
HistoryContact * result = new HistoryContact ( userId , fname , names . join ( QChar ( ' ' ) ) , phone ) ;
return result ;
}
2014-08-15 15:19:32 +04:00
void HistoryContact : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
2014-05-30 12:53:19 +04:00
if ( width < 1 ) return ;
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-23 18:50:11 +03:00
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int skipy = 0 , replyFrom = 0 , fwdFrom = 0 ;
2015-03-19 12:18:19 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
skipy = st : : msgServiceNameFont - > height ;
}
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
skipy + = replyFrom ;
} else if ( fwd ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
2015-03-19 12:18:19 +03:00
}
2014-05-30 12:53:19 +04:00
bool out = parent - > out ( ) ;
if ( width > = _maxw ) {
width = _maxw ;
}
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , 0 , 0 , width , _height , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-04-23 18:50:11 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
}
2015-03-19 12:18:19 +03:00
if ( reply ) {
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
2015-04-23 18:50:11 +03:00
} else if ( fwd ) {
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) , ( contact ? contact - > photo : userDefPhoto ( 1 ) ) - > pixRounded ( st : : mediaThumbSize ) ) ;
if ( selected ) {
App : : roundRect ( p , st : : mediaPadding . left ( ) , skipy + st : : mediaPadding . top ( ) , st : : mediaThumbSize , st : : mediaThumbSize , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
}
2014-05-30 12:53:19 +04:00
int32 tleft = st : : mediaPadding . left ( ) + st : : mediaThumbSize + st : : mediaPadding . right ( ) ;
int32 twidth = width - tleft - st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
int32 fullTimeWidth = parent - > timeWidth ( true ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
int32 secondwidth = width - tleft - fullTimeWidth ;
p . setFont ( st : : mediaFont - > f ) ;
p . setPen ( st : : black - > c ) ;
if ( twidth < phonew ) {
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , st : : mediaFont - > m . elidedText ( phone , Qt : : ElideRight , twidth ) ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-03-19 12:18:19 +03:00
p . drawText ( tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaNameTop + st : : mediaFont - > ascent , phone ) ;
2014-05-30 12:53:19 +04:00
}
style : : color status ( selected ? ( out ? st : : mediaOutSelectColor : st : : mediaInSelectColor ) : ( out ? st : : mediaOutColor : st : : mediaInColor ) ) ;
p . setPen ( status - > p ) ;
2015-03-19 12:18:19 +03:00
name . drawElided ( p , tleft , skipy + st : : mediaPadding . top ( ) + st : : mediaThumbSize - st : : mediaDetailsShift - st : : mediaFont - > height , secondwidth ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgDateFont - > f ) ;
style : : color date ( selected ? ( out ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
2014-08-15 15:19:32 +04:00
p . drawText ( width + st : : msgDateDelta . x ( ) - fullTimeWidth + st : : msgDateSpace , _height - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , parent - > time ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( out ) {
2014-06-15 16:31:03 +04:00
QPoint iconPos ( width + 5 - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , _height + 1 - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
2014-05-30 12:53:19 +04:00
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
2014-08-22 18:55:23 +04:00
void HistoryContact : : updateFrom ( const MTPMessageMedia & media ) {
if ( media . type ( ) = = mtpc_messageMediaContact ) {
userId = media . c_messageMediaContact ( ) . vuser_id . v ;
contact = App : : userLoaded ( userId ) ;
if ( contact ) {
if ( contact - > phone . isEmpty ( ) ) {
contact - > setPhone ( phone ) ;
}
if ( contact - > contact < 0 ) {
contact - > contact = 0 ;
}
contact - > photo - > load ( ) ;
}
}
}
2015-04-04 23:01:34 +03:00
HistoryWebPage : : HistoryWebPage ( WebPageData * data ) : HistoryMedia ( )
, data ( data )
, _openl ( data - > url . isEmpty ( ) ? 0 : new TextLink ( data - > url ) )
2015-04-07 01:15:29 +03:00
, _photol ( ( data - > photo & & data - > type ! = WebPageVideo ) ? new PhotoLink ( data - > photo ) : 0 )
2015-04-04 23:01:34 +03:00
, _asArticle ( false )
, _title ( st : : msgMinWidth - st : : webPageLeft )
, _description ( st : : msgMinWidth - st : : webPageLeft )
, _siteNameWidth ( 0 )
, _durationWidth ( 0 )
, _pixw ( 0 ) , _pixh ( 0 )
{
}
void HistoryWebPage : : initDimensions ( const HistoryItem * parent ) {
if ( data - > pendingTill ) {
2015-05-20 22:28:24 +03:00
_maxw = _minh = _height = 0 ;
//_maxw = st::webPageLeft + st::linkFont->m.width(lang((data->pendingTill < 0) ? lng_attach_failed : lng_profile_loading));
//_minh = st::replyHeight;
//_height = _minh;
2015-04-04 23:01:34 +03:00
return ;
}
if ( ! _openl & & ! data - > url . isEmpty ( ) ) _openl = TextLinkPtr ( new TextLink ( data - > url ) ) ;
2015-04-07 01:15:29 +03:00
if ( ! _photol & & data - > photo & & data - > type ! = WebPageVideo ) _photol = TextLinkPtr ( new PhotoLink ( data - > photo ) ) ;
2015-04-04 23:01:34 +03:00
if ( data - > photo & & data - > type ! = WebPagePhoto & & data - > type ! = WebPageVideo ) {
if ( data - > type = = WebPageProfile ) {
_asArticle = true ;
2015-06-27 16:02:00 +03:00
} else if ( data - > siteName = = qstr ( " Twitter " ) | | data - > siteName = = qstr ( " Facebook " ) ) {
2015-04-04 23:01:34 +03:00
_asArticle = false ;
} else {
_asArticle = true ;
}
} else {
_asArticle = false ;
}
if ( _asArticle ) {
w = st : : webPagePhotoSize ;
_maxw = st : : webPageLeft + st : : webPagePhotoSize ;
_minh = st : : webPagePhotoSize ;
_minh + = st : : webPagePhotoSkip + ( st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
} else if ( data - > photo ) {
int32 tw = convertScale ( data - > photo - > full - > width ( ) ) , th = convertScale ( data - > photo - > full - > height ( ) ) ;
if ( ! tw | | ! th ) {
tw = th = 1 ;
}
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
if ( th > st : : maxMediaSize ) {
tw = ( st : : maxMediaSize * tw ) / th ;
th = st : : maxMediaSize ;
}
int32 thumbw = tw ;
int32 thumbh = th ;
w = thumbw ;
2015-05-01 02:05:19 +03:00
_maxw = st : : webPageLeft + qMax ( thumbh , qMax ( w , int32 ( st : : minPhotoSize ) ) ) + parent - > timeWidth ( true ) ;
2015-04-04 23:01:34 +03:00
_minh = qMax ( thumbh , int32 ( st : : minPhotoSize ) ) ;
_minh + = st : : webPagePhotoSkip ;
} else {
_maxw = st : : webPageLeft ;
_minh = 0 ;
}
if ( ! data - > siteName . isEmpty ( ) ) {
_siteNameWidth = st : : webPageTitleFont - > m . width ( data - > siteName ) ;
if ( _asArticle ) {
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _siteNameWidth + st : : webPagePhotoDelta + st : : webPagePhotoSize ) ) ;
} else {
2015-04-30 16:53:36 +03:00
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _siteNameWidth + parent - > timeWidth ( true ) ) ) ;
2015-04-04 23:01:34 +03:00
_minh + = st : : webPageTitleFont - > height ;
}
}
QString title ( data - > title . isEmpty ( ) ? data - > author : data - > title ) ;
if ( ! title . isEmpty ( ) ) {
2015-06-10 15:48:26 +03:00
title = textClean ( title ) ;
if ( ! _asArticle & & ! data - > photo & & data - > description . isEmpty ( ) ) title + = textcmdSkipBlock ( parent - > timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
_title . setText ( st : : webPageTitleFont , title , _webpageTitleOptions ) ;
2015-04-04 23:01:34 +03:00
if ( _asArticle ) {
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _title . maxWidth ( ) + st : : webPagePhotoDelta + st : : webPagePhotoSize ) ) ;
} else {
2015-06-10 15:48:26 +03:00
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _title . maxWidth ( ) ) ) ;
2015-04-08 02:03:32 +03:00
_minh + = qMin ( _title . minHeight ( ) , 2 * st : : webPageTitleFont - > height ) ;
2015-04-04 23:01:34 +03:00
}
}
2015-04-07 01:15:29 +03:00
if ( ! data - > description . isEmpty ( ) ) {
2015-04-11 11:04:10 +01:00
QString text = textClean ( data - > description ) ;
2015-04-30 16:53:36 +03:00
if ( ! _asArticle & & ! data - > photo ) text + = textcmdSkipBlock ( parent - > timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
2015-04-11 11:04:10 +01:00
const TextParseOptions * opts = & _webpageDescriptionOptions ;
2015-06-27 16:02:00 +03:00
if ( data - > siteName = = qstr ( " Twitter " ) ) {
2015-04-11 11:04:10 +01:00
opts = & _twitterDescriptionOptions ;
2015-06-27 16:02:00 +03:00
} else if ( data - > siteName = = qstr ( " Instagram " ) ) {
2015-04-11 11:04:10 +01:00
opts = & _instagramDescriptionOptions ;
2015-04-08 02:03:32 +03:00
}
2015-04-11 11:04:10 +01:00
_description . setText ( st : : webPageDescriptionFont , text , * opts ) ;
2015-04-04 23:01:34 +03:00
if ( _asArticle ) {
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _description . maxWidth ( ) + st : : webPagePhotoDelta + st : : webPagePhotoSize ) ) ;
} else {
2015-04-11 11:04:10 +01:00
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _description . maxWidth ( ) ) ) ;
2015-04-08 02:03:32 +03:00
_minh + = qMin ( _description . minHeight ( ) , 3 * st : : webPageTitleFont - > height ) ;
2015-04-04 23:01:34 +03:00
}
}
if ( ! _asArticle & & data - > photo & & ( _siteNameWidth | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) ) {
_minh + = st : : webPagePhotoSkip ;
}
if ( data - > type = = WebPageVideo & & data - > duration ) {
_duration = formatDurationText ( data - > duration ) ;
_durationWidth = st : : msgDateFont - > m . width ( _duration ) ;
}
2015-04-19 13:29:19 +03:00
_height = _minh ;
2015-04-04 23:01:34 +03:00
}
void HistoryWebPage : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
2015-05-20 22:28:24 +03:00
if ( width < 1 | | data - > pendingTill ) return ;
2015-04-04 23:01:34 +03:00
int32 bottomSkip = 0 ;
2015-05-20 22:28:24 +03:00
//if (!data->pendingTill) {
2015-04-04 23:01:34 +03:00
if ( data - > photo ) {
bottomSkip + = st : : webPagePhotoSkip ;
2015-04-30 16:53:36 +03:00
if ( _asArticle | | ( st : : webPageLeft + qMax ( _pixw , int16 ( st : : minPhotoSize ) ) + parent - > timeWidth ( true ) > width ) ) {
2015-04-04 23:01:34 +03:00
bottomSkip + = ( st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
}
}
2015-05-20 22:28:24 +03:00
//}
2015-04-04 23:01:34 +03:00
style : : color bar = ( selected ? ( parent - > out ( ) ? st : : msgOutReplyBarSelColor : st : : msgInReplyBarSelColor ) : ( parent - > out ( ) ? st : : msgOutReplyBarColor : st : : msgInReplyBarColor ) ) ;
style : : color semibold = ( selected ? ( parent - > out ( ) ? st : : msgOutServiceSelColor : st : : msgInServiceSelColor ) : ( parent - > out ( ) ? st : : msgOutServiceColor : st : : msgInServiceColor ) ) ;
style : : color regular = ( selected ? ( parent - > out ( ) ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( parent - > out ( ) ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . fillRect ( 0 , 0 , st : : webPageBar , _height - bottomSkip , bar - > b ) ;
2015-05-20 22:28:24 +03:00
//if (data->pendingTill) {
// p.setFont(st::linkFont->f);
// p.setPen(regular->p);
// p.drawText(st::webPageLeft, (_minh - st::linkFont->height) / 2 + st::linkFont->ascent, lang(data->pendingTill < 0 ? lng_attach_failed : lng_profile_loading));
// return;
//}
2015-04-04 23:01:34 +03:00
p . save ( ) ;
p . translate ( st : : webPageLeft , 0 ) ;
width - = st : : webPageLeft ;
if ( _asArticle ) {
int32 pixwidth = st : : webPagePhotoSize , pixheight = st : : webPagePhotoSize ;
data - > photo - > medium - > load ( false , false ) ;
bool out = parent - > out ( ) ;
bool full = data - > photo - > medium - > loaded ( ) ;
QPixmap pix ;
if ( full ) {
2015-05-20 22:28:24 +03:00
pix = data - > photo - > medium - > pixSingle ( _pixw , _pixh , pixwidth , pixheight ) ;
2015-04-04 23:01:34 +03:00
} else {
2015-05-20 22:28:24 +03:00
pix = data - > photo - > thumb - > pixBlurredSingle ( _pixw , _pixh , pixwidth , pixheight ) ;
2015-04-04 23:01:34 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( width - pixwidth , 0 , pix ) ;
if ( selected ) {
App : : roundRect ( p , width - pixwidth , 0 , pixwidth , pixheight , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2015-04-04 23:01:34 +03:00
}
}
int32 articleLines = 5 ;
if ( _siteNameWidth ) {
int32 availw = width ;
if ( _asArticle ) {
availw - = st : : webPagePhotoSize + st : : webPagePhotoDelta ;
} else if ( _title . isEmpty ( ) & & _description . isEmpty ( ) & & ! data - > photo ) {
2015-04-30 16:53:36 +03:00
availw - = parent - > timeWidth ( true ) ;
2015-04-04 23:01:34 +03:00
}
p . setFont ( st : : webPageTitleFont - > f ) ;
p . setPen ( semibold - > p ) ;
p . drawText ( 0 , st : : webPageTitleFont - > ascent , ( availw > = _siteNameWidth ) ? data - > siteName : st : : webPageTitleFont - > m . elidedText ( data - > siteName , Qt : : ElideRight , availw ) ) ;
p . translate ( 0 , st : : webPageTitleFont - > height ) ;
- - articleLines ;
}
if ( ! _title . isEmpty ( ) ) {
p . setPen ( st : : black - > p ) ;
int32 availw = width , endskip = 0 ;
if ( _asArticle ) {
availw - = st : : webPagePhotoSize + st : : webPagePhotoDelta ;
} else if ( _description . isEmpty ( ) & & ! data - > photo ) {
2015-04-30 16:53:36 +03:00
endskip = parent - > timeWidth ( true ) ;
2015-04-04 23:01:34 +03:00
}
_title . drawElided ( p , 0 , 0 , availw , 2 , style : : al_left , 0 , - 1 , endskip ) ;
int32 h = _title . countHeight ( availw ) ;
if ( h > st : : webPageTitleFont - > height ) {
articleLines - = 2 ;
p . translate ( 0 , st : : webPageTitleFont - > height * 2 ) ;
} else {
- - articleLines ;
p . translate ( 0 , h ) ;
}
}
if ( ! _description . isEmpty ( ) ) {
p . setPen ( st : : black - > p ) ;
int32 availw = width , endskip = 0 ;
if ( _asArticle ) {
availw - = st : : webPagePhotoSize + st : : webPagePhotoDelta ;
if ( articleLines > 3 ) articleLines = 3 ;
2015-04-30 16:53:36 +03:00
} else {
if ( ! data - > photo ) endskip = parent - > timeWidth ( true ) ;
2015-04-04 23:01:34 +03:00
articleLines = 3 ;
}
_description . drawElided ( p , 0 , 0 , availw , articleLines , style : : al_left , 0 , - 1 , endskip ) ;
p . translate ( 0 , qMin ( _description . countHeight ( availw ) , st : : webPageDescriptionFont - > height * articleLines ) ) ;
}
if ( ! _asArticle & & data - > photo ) {
if ( _siteNameWidth | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
p . translate ( 0 , st : : webPagePhotoSkip ) ;
}
int32 pixwidth = qMax ( _pixw , int16 ( st : : minPhotoSize ) ) , pixheight = qMax ( _pixh , int16 ( st : : minPhotoSize ) ) ;
data - > photo - > full - > load ( false , false ) ;
bool out = parent - > out ( ) ;
bool full = data - > photo - > full - > loaded ( ) ;
QPixmap pix ;
if ( full ) {
2015-05-20 22:28:24 +03:00
pix = data - > photo - > full - > pixSingle ( _pixw , _pixh , pixwidth , pixheight ) ;
2015-04-04 23:01:34 +03:00
} else {
2015-05-20 22:28:24 +03:00
pix = data - > photo - > thumb - > pixBlurredSingle ( _pixw , _pixh , pixwidth , pixheight ) ;
2015-04-04 23:01:34 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( 0 , 0 , pix ) ;
2015-04-04 23:01:34 +03:00
if ( ! full ) {
uint64 dt = itemAnimations ( ) . animate ( parent , getms ( ) ) ;
int32 cnt = int32 ( st : : photoLoaderCnt ) , period = int32 ( st : : photoLoaderPeriod ) , t = dt % period , delta = int32 ( st : : photoLoaderDelta ) ;
int32 x = ( pixwidth - st : : photoLoader . width ( ) ) / 2 , y = ( pixheight - st : : photoLoader . height ( ) ) / 2 ;
p . fillRect ( x , y , st : : photoLoader . width ( ) , st : : photoLoader . height ( ) , st : : photoLoaderBg - > b ) ;
x + = ( st : : photoLoader . width ( ) - cnt * st : : photoLoaderPoint . width ( ) - ( cnt - 1 ) * st : : photoLoaderSkip ) / 2 ;
y + = ( st : : photoLoader . height ( ) - st : : photoLoaderPoint . height ( ) ) / 2 ;
QColor c ( st : : white - > c ) ;
QBrush b ( c ) ;
for ( int32 i = 0 ; i < cnt ; + + i ) {
t - = delta ;
while ( t < 0 ) t + = period ;
float64 alpha = ( t > = st : : photoLoaderDuration1 + st : : photoLoaderDuration2 ) ? 0 : ( ( t > st : : photoLoaderDuration1 ? ( ( st : : photoLoaderDuration1 + st : : photoLoaderDuration2 - t ) / st : : photoLoaderDuration2 ) : ( t / st : : photoLoaderDuration1 ) ) ) ;
c . setAlphaF ( st : : photoLoaderAlphaMin + alpha * ( 1 - st : : photoLoaderAlphaMin ) ) ;
b . setColor ( c ) ;
p . fillRect ( x + i * ( st : : photoLoaderPoint . width ( ) + st : : photoLoaderSkip ) , y , st : : photoLoaderPoint . width ( ) , st : : photoLoaderPoint . height ( ) , b ) ;
}
}
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , 0 , 0 , pixwidth , pixheight , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2015-04-04 23:01:34 +03:00
}
if ( data - > type = = WebPageVideo ) {
2015-06-27 16:02:00 +03:00
if ( data - > siteName = = qstr ( " YouTube " ) ) {
2015-04-04 23:01:34 +03:00
p . drawPixmap ( QPoint ( ( pixwidth - st : : youtubeIcon . pxWidth ( ) ) / 2 , ( pixheight - st : : youtubeIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : youtubeIcon ) ;
} else {
p . drawPixmap ( QPoint ( ( pixwidth - st : : videoIcon . pxWidth ( ) ) / 2 , ( pixheight - st : : videoIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : videoIcon ) ;
}
if ( _durationWidth ) {
int32 dateX = pixwidth - _durationWidth - st : : msgDateImgDelta - 2 * st : : msgDateImgPadding . x ( ) ;
int32 dateY = pixheight - st : : msgDateFont - > height - 2 * st : : msgDateImgPadding . y ( ) - st : : msgDateImgDelta ;
int32 dateW = pixwidth - dateX - st : : msgDateImgDelta ;
int32 dateH = pixheight - dateY - st : : msgDateImgDelta ;
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , dateX , dateY , dateW , dateH , selected ? st : : msgDateImgSelectBg : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2015-04-04 23:01:34 +03:00
p . setFont ( st : : msgDateFont - > f ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
p . drawText ( dateX + st : : msgDateImgPadding . x ( ) , dateY + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , _duration ) ;
}
}
p . translate ( 0 , pixheight ) ;
}
p . restore ( ) ;
}
int32 HistoryWebPage : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
if ( data - > pendingTill ) {
w = width ;
_height = _minh ;
return _height ;
}
w = width ;
width - = st : : webPageLeft ;
if ( _asArticle ) {
int32 tw = convertScale ( data - > photo - > medium - > width ( ) ) , th = convertScale ( data - > photo - > medium - > height ( ) ) ;
if ( tw > st : : webPagePhotoSize ) {
if ( th > tw ) {
th = th * st : : webPagePhotoSize / tw ;
tw = st : : webPagePhotoSize ;
} else if ( th > st : : webPagePhotoSize ) {
tw = tw * st : : webPagePhotoSize / th ;
th = st : : webPagePhotoSize ;
}
}
_pixw = tw ;
_pixh = th ;
if ( _pixw < 1 ) _pixw = 1 ;
if ( _pixh < 1 ) _pixh = 1 ;
_height = st : : webPagePhotoSize ;
_height + = st : : webPagePhotoSkip + ( st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
} else if ( data - > photo ) {
_pixw = qMin ( width , int32 ( _maxw - st : : webPageLeft ) ) ;
int32 tw = convertScale ( data - > photo - > full - > width ( ) ) , th = convertScale ( data - > photo - > full - > height ( ) ) ;
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
if ( th > st : : maxMediaSize ) {
tw = ( st : : maxMediaSize * tw ) / th ;
th = st : : maxMediaSize ;
}
_pixh = th ;
if ( tw > _pixw ) {
_pixh = ( _pixw * _pixh / tw ) ;
} else {
_pixw = tw ;
}
if ( _pixh > width ) {
_pixw = ( _pixw * width ) / _pixh ;
_pixh = width ;
}
if ( _pixw < 1 ) _pixw = 1 ;
if ( _pixh < 1 ) _pixh = 1 ;
_height = qMax ( _pixh , int16 ( st : : minPhotoSize ) ) ;
_height + = st : : webPagePhotoSkip ;
2015-04-30 16:53:36 +03:00
if ( qMax ( _pixw , int16 ( st : : minPhotoSize ) ) + parent - > timeWidth ( true ) > width ) {
2015-04-04 23:01:34 +03:00
_height + = ( st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) ;
}
} else {
_height = 0 ;
}
if ( ! _asArticle ) {
if ( ! data - > siteName . isEmpty ( ) ) {
_height + = st : : webPageTitleFont - > height ;
}
if ( ! _title . isEmpty ( ) ) {
_height + = qMin ( _title . countHeight ( width ) , st : : webPageTitleFont - > height * 2 ) ;
}
if ( ! _description . isEmpty ( ) ) {
_height + = qMin ( _description . countHeight ( width ) , st : : webPageDescriptionFont - > height * 3 ) ;
}
if ( data - > photo & & ( _siteNameWidth | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) ) {
_height + = st : : webPagePhotoSkip ;
}
}
return _height ;
}
void HistoryWebPage : : regItem ( HistoryItem * item ) {
App : : regWebPageItem ( data , item ) ;
}
void HistoryWebPage : : unregItem ( HistoryItem * item ) {
App : : unregWebPageItem ( data , item ) ;
}
const QString HistoryWebPage : : inDialogsText ( ) const {
return QString ( ) ;
}
const QString HistoryWebPage : : inHistoryText ( ) const {
return QString ( ) ;
}
bool HistoryWebPage : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
if ( width < 0 ) width = w ;
if ( width > = _maxw ) width = _maxw ;
return ( x > = 0 & & y > = 0 & & x < width & & y < _height ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryWebPage : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2015-04-04 23:01:34 +03:00
if ( width < 0 ) width = w ;
2015-04-08 02:03:32 +03:00
if ( width < 1 ) return ;
2015-04-04 23:01:34 +03:00
2015-04-08 02:03:32 +03:00
width - = st : : webPageLeft ;
x - = st : : webPageLeft ;
2015-04-04 23:01:34 +03:00
2015-04-08 02:03:32 +03:00
if ( _asArticle ) {
int32 pixwidth = st : : webPagePhotoSize , pixheight = st : : webPagePhotoSize ;
if ( x > = width - pixwidth & & x < width & & y > = 0 & & y < pixheight ) {
lnk = _openl ;
return ;
2015-04-04 23:01:34 +03:00
}
2015-04-08 02:03:32 +03:00
}
int32 articleLines = 5 ;
if ( _siteNameWidth ) {
y - = st : : webPageTitleFont - > height ;
- - articleLines ;
}
if ( ! _title . isEmpty ( ) ) {
int32 availw = width ;
if ( _asArticle ) {
availw - = st : : webPagePhotoSize + st : : webPagePhotoDelta ;
2015-04-04 23:01:34 +03:00
}
2015-04-08 02:03:32 +03:00
int32 h = _title . countHeight ( availw ) ;
if ( h > st : : webPageTitleFont - > height ) {
articleLines - = 2 ;
y - = st : : webPageTitleFont - > height * 2 ;
} else {
- - articleLines ;
y - = h ;
2015-04-04 23:01:34 +03:00
}
2015-04-08 02:03:32 +03:00
}
if ( ! _description . isEmpty ( ) ) {
int32 availw = width ;
if ( _asArticle ) {
availw - = st : : webPagePhotoSize + st : : webPagePhotoDelta ;
if ( articleLines > 3 ) articleLines = 3 ;
} else if ( ! data - > photo ) {
articleLines = 3 ;
2015-04-04 23:01:34 +03:00
}
2015-06-27 16:02:00 +03:00
int32 desch = qMin ( _description . countHeight ( width ) , st : : webPageDescriptionFont - > height * articleLines ) ;
if ( y > = 0 & & y < desch ) {
bool inText = false ;
2015-04-08 02:03:32 +03:00
_description . getState ( lnk , inText , x , y , availw ) ;
2015-06-27 16:02:00 +03:00
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
2015-04-08 02:03:32 +03:00
return ;
}
2015-06-27 16:02:00 +03:00
y - = desch ;
2015-04-08 02:03:32 +03:00
}
if ( _siteNameWidth | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
y - = st : : webPagePhotoSkip ;
}
if ( ! _asArticle ) {
2015-04-04 23:01:34 +03:00
int32 pixwidth = qMax ( _pixw , int16 ( st : : minPhotoSize ) ) , pixheight = qMax ( _pixh , int16 ( st : : minPhotoSize ) ) ;
if ( x > = 0 & & y > = 0 & & x < pixwidth & & y < pixheight ) {
2015-04-08 02:03:32 +03:00
lnk = _photol ? _photol : _openl ;
return ;
2015-04-04 23:01:34 +03:00
}
}
}
HistoryMedia * HistoryWebPage : : clone ( ) const {
return new HistoryWebPage ( * this ) ;
}
ImagePtr HistoryWebPage : : replyPreview ( ) {
2015-04-07 01:15:29 +03:00
return data - > photo ? data - > photo - > makeReplyPreview ( ) : ImagePtr ( ) ;
2015-04-04 23:01:34 +03:00
}
2014-11-12 23:18:00 +03:00
namespace {
2014-11-23 14:20:40 +03:00
QRegularExpression reYouTube1 ( qsl ( " ^(https?://) ? ( www \ \ . | m \ \ . ) ? youtube \ \ . com / watch \ \ ? ( [ ^ # ] + & ) ? v = ( [ a - z0 - 9 _ - ] + ) ( & [ ^ \ \ s ] * ) ? $ " ), QRegularExpression::CaseInsensitiveOption) ;
2015-02-14 15:41:32 +03:00
QRegularExpression reYouTube2 ( qsl ( " ^(https?://) ? ( www \ \ . ) ? youtu \ \ . be / ( [ a - z0 - 9 _ - ] + ) ( [ / \ \ ? # ] [ ^ \ \ s ] * ) ? $ " ), QRegularExpression::CaseInsensitiveOption) ;
2014-11-23 14:20:40 +03:00
QRegularExpression reInstagram ( qsl ( " ^(https?://) ? ( www \ \ . ) ? instagram \ \ . com / p / ( [ a - z0 - 9 _ - ] + ) ( [ / \ \ ? ] [ ^ \ \ s ] * ) ? $ " ), QRegularExpression::CaseInsensitiveOption) ;
QRegularExpression reVimeo ( qsl ( " ^(https?://) ? ( www \ \ . ) ? vimeo \ \ . com / ( [ 0 - 9 ] + ) ( [ / \ \ ? ] [ ^ \ \ s ] * ) ? $ " ), QRegularExpression::CaseInsensitiveOption) ;
2014-11-12 23:18:00 +03:00
ImageLinkManager manager ;
}
void ImageLinkManager : : init ( ) {
if ( manager ) delete manager ;
manager = new QNetworkAccessManager ( ) ;
App : : setProxySettings ( * manager ) ;
2014-11-13 01:35:00 +03:00
2014-11-12 23:18:00 +03:00
connect ( manager , SIGNAL ( authenticationRequired ( QNetworkReply * , QAuthenticator * ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2014-11-15 02:23:35 +03:00
connect ( manager , SIGNAL ( sslErrors ( QNetworkReply * , const QList < QSslError > & ) ) , this , SLOT ( onFailed ( QNetworkReply * ) ) ) ;
2014-11-12 23:18:00 +03:00
connect ( manager , SIGNAL ( finished ( QNetworkReply * ) ) , this , SLOT ( onFinished ( QNetworkReply * ) ) ) ;
if ( black ) delete black ;
QImage b ( cIntRetinaFactor ( ) , cIntRetinaFactor ( ) , QImage : : Format_ARGB32_Premultiplied ) ;
{
QPainter p ( & b ) ;
p . fillRect ( QRect ( 0 , 0 , cIntRetinaFactor ( ) , cIntRetinaFactor ( ) ) , st : : white - > b ) ;
}
2014-12-23 02:11:37 +03:00
QPixmap p = QPixmap : : fromImage ( b , Qt : : ColorOnly ) ;
2014-11-12 23:18:00 +03:00
p . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
black = new ImagePtr ( p , " PNG " ) ;
}
void ImageLinkManager : : reinit ( ) {
if ( manager ) App : : setProxySettings ( * manager ) ;
}
void ImageLinkManager : : deinit ( ) {
if ( manager ) {
delete manager ;
manager = 0 ;
}
if ( black ) {
delete black ;
black = 0 ;
}
dataLoadings . clear ( ) ;
imageLoadings . clear ( ) ;
}
void initImageLinkManager ( ) {
manager . init ( ) ;
}
void reinitImageLinkManager ( ) {
manager . reinit ( ) ;
}
void deinitImageLinkManager ( ) {
manager . deinit ( ) ;
}
void ImageLinkManager : : getData ( ImageLinkData * data ) {
if ( ! manager ) {
DEBUG_LOG ( ( " App Error: getting image link data without manager init! " ) ) ;
return failed ( data ) ;
}
QString url ;
switch ( data - > type ) {
case YouTubeLink : {
url = qsl ( " https://gdata.youtube.com/feeds/api/videos/ " ) + data - > id . mid ( 8 ) + qsl ( " ?v=2&alt=json " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
dataLoadings [ reply ] = data ;
} break ;
2014-11-23 14:20:40 +03:00
case VimeoLink : {
url = qsl ( " https://vimeo.com/api/v2/video/ " ) + data - > id . mid ( 6 ) + qsl ( " .json " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
dataLoadings [ reply ] = data ;
} break ;
2014-11-12 23:18:00 +03:00
case InstagramLink : {
//url = qsl("https://api.instagram.com/oembed?url=http://instagr.am/p/") + data->id.mid(10) + '/';
url = qsl ( " https://instagram.com/p/ " ) + data - > id . mid ( 10 ) + qsl ( " /media/?size=l " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
imageLoadings [ reply ] = data ;
} break ;
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : {
int32 w = st : : locationSize . width ( ) , h = st : : locationSize . height ( ) ;
int32 zoom = 13 , scale = 1 ;
if ( cScale ( ) = = dbisTwo | | cRetina ( ) ) {
scale = 2 ;
} else {
w = convertScale ( w ) ;
h = convertScale ( h ) ;
}
url = qsl ( " https://maps.googleapis.com/maps/api/staticmap?center= " ) + data - > id . mid ( 9 ) + qsl ( " &zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big| " ) . arg ( zoom ) . arg ( w ) . arg ( h ) . arg ( scale ) + data - > id . mid ( 9 ) + qsl ( " &sensor=false " ) ;
QNetworkReply * reply = manager - > get ( QNetworkRequest ( QUrl ( url ) ) ) ;
imageLoadings [ reply ] = data ;
} break ;
2014-11-12 23:18:00 +03:00
default : {
2014-11-13 01:35:00 +03:00
failed ( data ) ;
2014-11-12 23:18:00 +03:00
} break ;
}
}
void ImageLinkManager : : onFinished ( QNetworkReply * reply ) {
if ( ! manager ) return ;
if ( reply - > error ( ) ! = QNetworkReply : : NoError ) return onFailed ( reply ) ;
QVariant statusCode = reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) ;
if ( statusCode . isValid ( ) ) {
int status = statusCode . toInt ( ) ;
if ( status = = 301 | | status = = 302 ) {
QString loc = reply - > header ( QNetworkRequest : : LocationHeader ) . toString ( ) ;
if ( ! loc . isEmpty ( ) ) {
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
ImageLinkData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
} else if ( + + serverRedirects [ d ] > MaxHttpRedirects ) {
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
dataLoadings . erase ( i ) ;
dataLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
} else if ( ( i = imageLoadings . find ( reply ) ) ! = imageLoadings . cend ( ) ) {
ImageLinkData * d = i . value ( ) ;
if ( serverRedirects . constFind ( d ) = = serverRedirects . cend ( ) ) {
serverRedirects . insert ( d , 1 ) ;
} else if ( + + serverRedirects [ d ] > MaxHttpRedirects ) {
DEBUG_LOG ( ( " Network Error: Too many HTTP redirects in onFinished() for image link: %1 " ) . arg ( loc ) ) ;
return onFailed ( reply ) ;
}
imageLoadings . erase ( i ) ;
imageLoadings . insert ( manager - > get ( QNetworkRequest ( loc ) ) , d ) ;
return ;
}
}
}
if ( status ! = 200 ) {
DEBUG_LOG ( ( " Network Error: Bad HTTP status received in onFinished() for image link: %1 " ) . arg ( status ) ) ;
return onFailed ( reply ) ;
}
}
ImageLinkData * d = 0 ;
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
QJsonParseError e ;
QJsonDocument doc = QJsonDocument : : fromJson ( reply - > readAll ( ) , & e ) ;
if ( e . error ! = QJsonParseError : : NoError ) {
DEBUG_LOG ( ( " JSON Error: Bad json received in onFinished() for image link " ) ) ;
return onFailed ( reply ) ;
}
switch ( d - > type ) {
case YouTubeLink : {
2014-11-23 14:20:40 +03:00
QJsonObject obj = doc . object ( ) ;
2014-11-12 23:18:00 +03:00
QString thumb ;
int32 seconds = 0 ;
QJsonObject : : const_iterator entryIt = obj . constFind ( qsl ( " entry " ) ) ;
if ( entryIt ! = obj . constEnd ( ) & & entryIt . value ( ) . isObject ( ) ) {
QJsonObject entry = entryIt . value ( ) . toObject ( ) ;
QJsonObject : : const_iterator mediaIt = entry . constFind ( qsl ( " media$group " ) ) ;
if ( mediaIt ! = entry . constEnd ( ) & & mediaIt . value ( ) . isObject ( ) ) {
QJsonObject media = mediaIt . value ( ) . toObject ( ) ;
// title from media
QJsonObject : : const_iterator titleIt = media . constFind ( qsl ( " media$title " ) ) ;
if ( titleIt ! = media . constEnd ( ) & & titleIt . value ( ) . isObject ( ) ) {
QJsonObject title = titleIt . value ( ) . toObject ( ) ;
QJsonObject : : const_iterator tIt = title . constFind ( qsl ( " $t " ) ) ;
if ( tIt ! = title . constEnd ( ) & & tIt . value ( ) . isString ( ) ) {
d - > title = tIt . value ( ) . toString ( ) ;
}
}
// thumb
QJsonObject : : const_iterator thumbnailsIt = media . constFind ( qsl ( " media$thumbnail " ) ) ;
int32 bestLevel = 0 ;
if ( thumbnailsIt ! = media . constEnd ( ) & & thumbnailsIt . value ( ) . isArray ( ) ) {
QJsonArray thumbnails = thumbnailsIt . value ( ) . toArray ( ) ;
for ( int32 i = 0 , l = thumbnails . size ( ) ; i < l ; + + i ) {
QJsonValue thumbnailVal = thumbnails . at ( i ) ;
if ( ! thumbnailVal . isObject ( ) ) continue ;
QJsonObject thumbnail = thumbnailVal . toObject ( ) ;
QJsonObject : : const_iterator urlIt = thumbnail . constFind ( qsl ( " url " ) ) ;
if ( urlIt = = thumbnail . constEnd ( ) | | ! urlIt . value ( ) . isString ( ) ) continue ;
int32 level = 0 ;
if ( thumbnail . constFind ( qsl ( " time " ) ) = = thumbnail . constEnd ( ) ) {
level + = 10 ;
}
QJsonObject : : const_iterator wIt = thumbnail . constFind ( qsl ( " width " ) ) ;
if ( wIt ! = thumbnail . constEnd ( ) ) {
int32 w = 0 ;
if ( wIt . value ( ) . isDouble ( ) ) {
w = qMax ( qRound ( wIt . value ( ) . toDouble ( ) ) , 0 ) ;
} else if ( wIt . value ( ) . isString ( ) ) {
w = qMax ( qRound ( wIt . value ( ) . toString ( ) . toDouble ( ) ) , 0 ) ;
}
switch ( w ) {
case 640 : level + = 4 ; break ;
case 480 : level + = 3 ; break ;
case 320 : level + = 2 ; break ;
case 120 : level + = 1 ; break ;
}
}
if ( level > bestLevel ) {
thumb = urlIt . value ( ) . toString ( ) ;
bestLevel = level ;
}
}
}
// duration
QJsonObject : : const_iterator durationIt = media . constFind ( qsl ( " yt$duration " ) ) ;
if ( durationIt ! = media . constEnd ( ) & & durationIt . value ( ) . isObject ( ) ) {
QJsonObject duration = durationIt . value ( ) . toObject ( ) ;
QJsonObject : : const_iterator secondsIt = duration . constFind ( qsl ( " seconds " ) ) ;
if ( secondsIt ! = duration . constEnd ( ) ) {
if ( secondsIt . value ( ) . isDouble ( ) ) {
seconds = qRound ( secondsIt . value ( ) . toDouble ( ) ) ;
} else if ( secondsIt . value ( ) . isString ( ) ) {
seconds = qRound ( secondsIt . value ( ) . toString ( ) . toDouble ( ) ) ;
}
}
}
}
// title field
if ( d - > title . isEmpty ( ) ) {
QJsonObject : : const_iterator titleIt = entry . constFind ( qsl ( " title " ) ) ;
if ( titleIt ! = entry . constEnd ( ) & & titleIt . value ( ) . isObject ( ) ) {
QJsonObject title = titleIt . value ( ) . toObject ( ) ;
QJsonObject : : const_iterator tIt = title . constFind ( qsl ( " $t " ) ) ;
if ( tIt ! = title . constEnd ( ) & & tIt . value ( ) . isString ( ) ) {
d - > title = tIt . value ( ) . toString ( ) ;
}
}
}
}
if ( seconds > 0 ) {
d - > duration = formatDurationText ( seconds ) ;
}
if ( thumb . isEmpty ( ) ) {
2014-11-13 01:35:00 +03:00
failed ( d ) ;
2014-11-12 23:18:00 +03:00
} else {
imageLoadings . insert ( manager - > get ( QNetworkRequest ( thumb ) ) , d ) ;
}
} break ;
2014-11-23 14:20:40 +03:00
case VimeoLink : {
QString thumb ;
int32 seconds = 0 ;
QJsonArray arr = doc . array ( ) ;
if ( ! arr . isEmpty ( ) ) {
QJsonObject obj = arr . at ( 0 ) . toObject ( ) ;
QJsonObject : : const_iterator titleIt = obj . constFind ( qsl ( " title " ) ) ;
if ( titleIt ! = obj . constEnd ( ) & & titleIt . value ( ) . isString ( ) ) {
d - > title = titleIt . value ( ) . toString ( ) ;
}
QJsonObject : : const_iterator thumbnailsIt = obj . constFind ( qsl ( " thumbnail_large " ) ) ;
if ( thumbnailsIt ! = obj . constEnd ( ) & & thumbnailsIt . value ( ) . isString ( ) ) {
thumb = thumbnailsIt . value ( ) . toString ( ) ;
}
QJsonObject : : const_iterator secondsIt = obj . constFind ( qsl ( " duration " ) ) ;
if ( secondsIt ! = obj . constEnd ( ) ) {
if ( secondsIt . value ( ) . isDouble ( ) ) {
seconds = qRound ( secondsIt . value ( ) . toDouble ( ) ) ;
} else if ( secondsIt . value ( ) . isString ( ) ) {
seconds = qRound ( secondsIt . value ( ) . toString ( ) . toDouble ( ) ) ;
}
}
}
if ( seconds > 0 ) {
d - > duration = formatDurationText ( seconds ) ;
}
if ( thumb . isEmpty ( ) ) {
failed ( d ) ;
} else {
imageLoadings . insert ( manager - > get ( QNetworkRequest ( thumb ) ) , d ) ;
}
} break ;
2014-11-12 23:18:00 +03:00
2014-11-13 14:27:10 +03:00
case InstagramLink : failed ( d ) ; break ;
case GoogleMapsLink : failed ( d ) ; break ;
2014-11-12 23:18:00 +03:00
}
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
QPixmap thumb ;
QByteArray format ;
QByteArray data ( reply - > readAll ( ) ) ;
{
QBuffer buffer ( & data ) ;
QImageReader reader ( & buffer ) ;
thumb = QPixmap : : fromImageReader ( & reader , Qt : : ColorOnly ) ;
format = reader . format ( ) ;
2014-11-13 14:27:10 +03:00
thumb . setDevicePixelRatio ( cRetinaFactor ( ) ) ;
2014-11-12 23:18:00 +03:00
if ( format . isEmpty ( ) ) format = QByteArray ( " JPG " ) ;
}
d - > loading = false ;
d - > thumb = thumb . isNull ( ) ? ( * black ) : ImagePtr ( thumb , format ) ;
serverRedirects . remove ( d ) ;
if ( App : : main ( ) ) App : : main ( ) - > update ( ) ;
}
}
}
void ImageLinkManager : : onFailed ( QNetworkReply * reply ) {
if ( ! manager ) return ;
ImageLinkData * d = 0 ;
QMap < QNetworkReply * , ImageLinkData * > : : iterator i = dataLoadings . find ( reply ) ;
if ( i ! = dataLoadings . cend ( ) ) {
d = i . value ( ) ;
dataLoadings . erase ( i ) ;
} else {
i = imageLoadings . find ( reply ) ;
if ( i ! = imageLoadings . cend ( ) ) {
d = i . value ( ) ;
imageLoadings . erase ( i ) ;
}
}
DEBUG_LOG ( ( " Network Error: failed to get data for image link %1, error %2 " ) . arg ( d ? d - > id : 0 ) . arg ( reply - > errorString ( ) ) ) ;
if ( d ) {
2014-11-13 01:35:00 +03:00
failed ( d ) ;
2014-11-12 23:18:00 +03:00
}
}
void ImageLinkManager : : failed ( ImageLinkData * data ) {
2014-11-13 01:35:00 +03:00
data - > loading = false ;
data - > thumb = * black ;
serverRedirects . remove ( data ) ;
2014-11-12 23:18:00 +03:00
}
void ImageLinkData : : load ( ) {
if ( ! thumb - > isNull ( ) ) return thumb - > load ( false , false ) ;
if ( loading ) return ;
loading = true ;
manager . getData ( this ) ;
}
2015-04-30 16:53:36 +03:00
HistoryImageLink : : HistoryImageLink ( const QString & url , const QString & title , const QString & description ) : HistoryMedia ( ) ,
_title ( st : : msgMinWidth ) ,
_description ( st : : msgMinWidth ) {
if ( ! title . isEmpty ( ) ) {
_title . setText ( st : : webPageTitleFont , textClean ( title ) , _webpageTitleOptions ) ;
}
if ( ! description . isEmpty ( ) ) {
_description . setText ( st : : webPageDescriptionFont , textClean ( description ) , _webpageDescriptionOptions ) ;
}
2014-11-13 14:27:10 +03:00
if ( url . startsWith ( qsl ( " location: " ) ) ) {
2014-11-22 12:45:04 +03:00
QString lnk = qsl ( " https://maps.google.com/maps?q= " ) + url . mid ( 9 ) + qsl ( " &ll= " ) + url . mid ( 9 ) + qsl ( " &z=17 " ) ;
link . reset ( new TextLink ( lnk ) ) ;
2014-11-23 14:20:40 +03:00
2014-11-22 12:45:04 +03:00
data = App : : imageLink ( url , GoogleMapsLink , lnk ) ;
2014-11-12 23:18:00 +03:00
} else {
2014-11-23 14:20:40 +03:00
link . reset ( new TextLink ( url ) ) ;
2014-11-22 12:45:04 +03:00
int matchIndex = 4 ;
2014-11-13 14:27:10 +03:00
QRegularExpressionMatch m = reYouTube1 . match ( url ) ;
2014-11-22 12:45:04 +03:00
if ( ! m . hasMatch ( ) ) {
m = reYouTube2 . match ( url ) ;
matchIndex = 3 ;
}
2014-11-12 23:18:00 +03:00
if ( m . hasMatch ( ) ) {
2014-11-22 12:45:04 +03:00
data = App : : imageLink ( qsl ( " youtube: " ) + m . captured ( matchIndex ) , YouTubeLink , url ) ;
2014-11-12 23:18:00 +03:00
} else {
2014-11-23 14:20:40 +03:00
m = reVimeo . match ( url ) ;
2014-11-13 14:27:10 +03:00
if ( m . hasMatch ( ) ) {
2014-11-23 14:20:40 +03:00
data = App : : imageLink ( qsl ( " vimeo: " ) + m . captured ( 3 ) , VimeoLink , url ) ;
2014-11-13 14:27:10 +03:00
} else {
2014-11-23 14:20:40 +03:00
m = reInstagram . match ( url ) ;
if ( m . hasMatch ( ) ) {
data = App : : imageLink ( qsl ( " instagram: " ) + m . captured ( 3 ) , InstagramLink , url ) ;
data - > title = qsl ( " instagram.com/p/ " ) + m . captured ( 3 ) ;
} else {
data = 0 ;
}
2014-11-13 14:27:10 +03:00
}
2014-11-12 23:18:00 +03:00
}
}
}
int32 HistoryImageLink : : fullWidth ( ) const {
if ( data ) {
switch ( data - > type ) {
case YouTubeLink : return 640 ;
2014-11-23 14:20:40 +03:00
case VimeoLink : return 640 ;
2014-11-12 23:18:00 +03:00
case InstagramLink : return 640 ;
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : return st : : locationSize . width ( ) ;
2014-11-12 23:18:00 +03:00
}
}
2015-01-05 23:17:33 +03:00
return st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
int32 HistoryImageLink : : fullHeight ( ) const {
if ( data ) {
switch ( data - > type ) {
case YouTubeLink : return 480 ;
2014-11-23 14:20:40 +03:00
case VimeoLink : return 480 ;
2014-11-12 23:18:00 +03:00
case InstagramLink : return 640 ;
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : return st : : locationSize . height ( ) ;
2014-11-12 23:18:00 +03:00
}
}
2015-01-05 23:17:33 +03:00
return st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
void HistoryImageLink : : initDimensions ( const HistoryItem * parent ) {
int32 tw = convertScale ( fullWidth ( ) ) , th = convertScale ( fullHeight ( ) ) ;
2015-01-05 23:17:33 +03:00
int32 thumbw = qMax ( tw , int32 ( st : : minPhotoSize ) ) , maxthumbh = thumbw ;
2014-11-12 23:18:00 +03:00
int32 thumbh = qRound ( th * float64 ( thumbw ) / tw ) ;
if ( thumbh > maxthumbh ) {
thumbw = qRound ( thumbw * float64 ( maxthumbh ) / thumbh ) ;
thumbh = maxthumbh ;
2015-01-05 23:17:33 +03:00
if ( thumbw < st : : minPhotoSize ) {
thumbw = st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
}
2015-01-05 23:17:33 +03:00
if ( thumbh < st : : minPhotoSize ) {
thumbh = st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
if ( ! w ) {
w = thumbw ;
}
_maxw = w ;
2015-03-19 12:18:19 +03:00
_minh = thumbh ;
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ;
if ( reply | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
_maxw + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
if ( reply ) {
_minh + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat | | ! fwd ) {
_minh + = st : : msgPadding . top ( ) ;
}
if ( fwd ) {
_minh + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
}
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_minh + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-04-30 16:53:36 +03:00
if ( ! _title . isEmpty ( ) ) {
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _title . maxWidth ( ) ) ) ;
_minh + = qMin ( _title . minHeight ( ) , 2 * st : : webPageTitleFont - > height ) ;
}
if ( ! _description . isEmpty ( ) ) {
_maxw = qMax ( _maxw , int32 ( st : : webPageLeft + _description . maxWidth ( ) ) ) ;
_minh + = qMin ( _description . minHeight ( ) , 3 * st : : webPageTitleFont - > height ) ;
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
_minh + = st : : webPagePhotoSkip ;
}
_minh + = st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
}
2015-04-19 13:29:19 +03:00
_height = _minh ;
2014-11-12 23:18:00 +03:00
}
void HistoryImageLink : : draw ( QPainter & p , const HistoryItem * parent , bool selected , int32 width ) const {
if ( width < 0 ) width = w ;
2015-03-19 12:18:19 +03:00
int skipx = 0 , skipy = 0 , height = _height ;
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ;
2015-05-20 22:28:24 +03:00
bool out = parent - > out ( ) ;
2015-04-30 16:53:36 +03:00
if ( reply | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , 0 , 0 , width , _height , bg , cors , & sh ) ;
2015-04-30 16:53:36 +03:00
int replyFrom = 0 , fwdFrom = 0 ;
2015-05-20 22:28:24 +03:00
if ( ! out & & parent - > history ( ) - > peer - > chat ) {
2015-03-19 12:18:19 +03:00
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-04-30 16:53:36 +03:00
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-03-19 12:18:19 +03:00
skipy + = replyFrom ;
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( parent - > from ( ) - > color - > p ) ;
parent - > from ( ) - > nameText . drawElided ( p , st : : mediaPadding . left ( ) , st : : msgPadding . top ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-30 16:53:36 +03:00
if ( ! fwd & & ! reply ) skipy + = st : : msgPadding . top ( ) ;
} else if ( ! reply ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
}
if ( reply ) {
skipy + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
reply - > drawReplyTo ( p , st : : msgReplyPadding . left ( ) , replyFrom , width - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) , selected ) ;
} else if ( fwd ) {
skipy + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
fwd - > drawForwardedFrom ( p , st : : mediaPadding . left ( ) , fwdFrom , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) , selected ) ;
2015-03-19 12:18:19 +03:00
}
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-04-30 16:53:36 +03:00
if ( ! _title . isEmpty ( ) ) {
p . setPen ( st : : black - > p ) ;
_title . drawElided ( p , st : : mediaPadding . left ( ) , skipy , width , 2 ) ;
skipy + = qMin ( _title . countHeight ( width ) , 2 * st : : webPageTitleFont - > height ) ;
}
if ( ! _description . isEmpty ( ) ) {
p . setPen ( st : : black - > p ) ;
_description . drawElided ( p , st : : mediaPadding . left ( ) , skipy , width , 3 ) ;
skipy + = qMin ( _description . countHeight ( width ) , 3 * st : : webPageDescriptionFont - > height ) ;
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
skipy + = st : : webPagePhotoSkip ;
}
2015-03-19 12:18:19 +03:00
height - = skipy + st : : mediaPadding . bottom ( ) ;
2015-05-20 22:28:24 +03:00
} else {
2015-05-22 14:14:52 +03:00
App : : roundShadow ( p , 0 , 0 , width , _height , selected ? st : : msgInSelectShadow : st : : msgInShadow , selected ? InSelectedShadowCorners : InShadowCorners ) ;
2015-03-19 12:18:19 +03:00
}
2014-11-12 23:18:00 +03:00
data - > load ( ) ;
QPixmap toDraw ;
if ( data & & ! data - > thumb - > isNull ( ) ) {
int32 w = data - > thumb - > width ( ) , h = data - > thumb - > height ( ) ;
2015-05-20 22:28:24 +03:00
QPixmap pix ;
2015-03-19 12:18:19 +03:00
if ( width * h = = height * w | | ( w = = convertScale ( fullWidth ( ) ) & & h = = convertScale ( fullHeight ( ) ) ) ) {
2015-05-20 22:28:24 +03:00
pix = data - > thumb - > pixSingle ( width , height , width , height ) ;
2015-05-20 22:50:05 +03:00
} else if ( width * h > height * w ) {
int32 nw = height * w / h ;
pix = data - > thumb - > pixSingle ( nw , height , width , height ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-05-20 22:50:05 +03:00
int32 nh = width * h / w ;
pix = data - > thumb - > pixSingle ( width , nh , width , height ) ;
2014-11-12 23:18:00 +03:00
}
2015-05-20 22:28:24 +03:00
p . drawPixmap ( QPoint ( skipx , skipy ) , pix ) ;
2014-11-12 23:18:00 +03:00
} else {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , skipx , skipy , width , height , st : : black , BlackCorners ) ;
2014-11-12 23:18:00 +03:00
}
if ( data ) {
switch ( data - > type ) {
2015-03-19 12:18:19 +03:00
case YouTubeLink : p . drawPixmap ( QPoint ( skipx + ( width - st : : youtubeIcon . pxWidth ( ) ) / 2 , skipy + ( height - st : : youtubeIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : youtubeIcon ) ; break ;
2015-04-04 23:01:34 +03:00
case VimeoLink : p . drawPixmap ( QPoint ( skipx + ( width - st : : vimeoIcon . pxWidth ( ) ) / 2 , skipy + ( height - st : : vimeoIcon . pxHeight ( ) ) / 2 ) , App : : sprite ( ) , st : : vimeoIcon ) ; break ;
2014-11-12 23:18:00 +03:00
}
if ( ! data - > title . isEmpty ( ) | | ! data - > duration . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
p . fillRect ( skipx , skipy , width , st : : msgDateFont - > height + 2 * st : : msgDateImgPadding . y ( ) , st : : msgDateImgBg - > b ) ;
2014-11-12 23:18:00 +03:00
p . setFont ( st : : msgDateFont - > f ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
int32 titleWidth = width - 2 * st : : msgDateImgPadding . x ( ) ;
if ( ! data - > duration . isEmpty ( ) ) {
int32 durationWidth = st : : msgDateFont - > m . width ( data - > duration ) ;
2015-03-19 12:18:19 +03:00
p . drawText ( skipx + width - st : : msgDateImgPadding . x ( ) - durationWidth , skipy + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , data - > duration ) ;
2014-11-12 23:18:00 +03:00
titleWidth - = durationWidth + st : : msgDateImgPadding . x ( ) ;
}
if ( ! data - > title . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
p . drawText ( skipx + st : : msgDateImgPadding . x ( ) , skipy + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , st : : msgDateFont - > m . elidedText ( data - > title , Qt : : ElideRight , titleWidth ) ) ;
2014-11-12 23:18:00 +03:00
}
}
}
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , skipx , skipy , width , height , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2014-11-12 23:18:00 +03:00
}
// date
QString time ( parent - > time ( ) ) ;
if ( time . isEmpty ( ) ) return ;
2015-04-30 16:53:36 +03:00
int32 dateX = skipx + width - parent - > timeWidth ( false ) - st : : msgDateImgDelta - 2 * st : : msgDateImgPadding . x ( ) ;
2015-03-19 12:18:19 +03:00
int32 dateY = skipy + height - st : : msgDateFont - > height - 2 * st : : msgDateImgPadding . y ( ) - st : : msgDateImgDelta ;
2014-11-12 23:18:00 +03:00
if ( parent - > out ( ) ) {
dateX - = st : : msgCheckRect . pxWidth ( ) + st : : msgDateImgCheckSpace ;
}
2015-03-19 12:18:19 +03:00
int32 dateW = skipx + width - dateX - st : : msgDateImgDelta ;
int32 dateH = skipy + height - dateY - st : : msgDateImgDelta ;
2014-11-12 23:18:00 +03:00
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , dateX , dateY , dateW , dateH , selected ? st : : msgDateImgSelectBg : st : : msgDateImgBg , selected ? DateSelectedCorners : DateCorners ) ;
2014-11-12 23:18:00 +03:00
p . setFont ( st : : msgDateFont - > f ) ;
p . setPen ( st : : msgDateImgColor - > p ) ;
p . drawText ( dateX + st : : msgDateImgPadding . x ( ) , dateY + st : : msgDateImgPadding . y ( ) + st : : msgDateFont - > ascent , time ) ;
if ( out ) {
QPoint iconPos ( dateX - 2 + dateW - st : : msgDateImgCheckSpace - st : : msgCheckRect . pxWidth ( ) , dateY + ( dateH - st : : msgCheckRect . pxHeight ( ) ) / 2 ) ;
const QRect * iconRect ;
if ( parent - > id > 0 ) {
if ( parent - > unread ( ) ) {
iconRect = & st : : msgImgCheckRect ;
} else {
iconRect = & st : : msgImgDblCheckRect ;
}
} else {
iconRect = & st : : msgImgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
int32 HistoryImageLink : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
2015-03-19 12:18:19 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
2015-04-30 16:53:36 +03:00
const HistoryForwarded * fwd = toHistoryForwarded ( parent ) ;
2015-03-19 12:18:19 +03:00
2014-11-18 15:41:33 +03:00
w = qMin ( width , _maxw ) ;
2015-04-30 16:53:36 +03:00
if ( reply | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
w - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
2014-11-12 23:18:00 +03:00
int32 tw = convertScale ( fullWidth ( ) ) , th = convertScale ( fullHeight ( ) ) ;
2014-11-18 15:41:33 +03:00
if ( tw > st : : maxMediaSize ) {
th = ( st : : maxMediaSize * th ) / tw ;
tw = st : : maxMediaSize ;
}
2014-11-12 23:18:00 +03:00
_height = th ;
if ( tw > w ) {
_height = ( w * _height / tw ) ;
} else {
w = tw ;
}
if ( _height > width ) {
w = ( w * width ) / _height ;
_height = width ;
}
2015-01-05 23:17:33 +03:00
if ( w < st : : minPhotoSize ) {
w = st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
2015-01-05 23:17:33 +03:00
if ( _height < st : : minPhotoSize ) {
_height = st : : minPhotoSize ;
2014-11-12 23:18:00 +03:00
}
2015-04-30 16:53:36 +03:00
if ( reply | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
_height + = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
}
2015-04-30 16:53:36 +03:00
if ( reply ) {
_height + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} else {
if ( parent - > out ( ) | | ! parent - > history ( ) - > peer - > chat | | ! fwd ) {
_height + = st : : msgPadding . top ( ) ;
}
if ( fwd ) {
_height + = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
}
if ( ! _title . isEmpty ( ) ) {
_height + = qMin ( _title . countHeight ( w ) , st : : webPageTitleFont - > height * 2 ) ;
}
if ( ! _description . isEmpty ( ) ) {
_height + = qMin ( _description . countHeight ( w ) , st : : webPageDescriptionFont - > height * 3 ) ;
}
if ( ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
_height + = st : : webPagePhotoSkip ;
}
_height + = st : : mediaPadding . bottom ( ) ;
w + = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
2015-03-19 12:18:19 +03:00
}
2014-11-12 23:18:00 +03:00
return _height ;
}
const QString HistoryImageLink : : inDialogsText ( ) const {
if ( data ) {
switch ( data - > type ) {
case YouTubeLink : return qsl ( " YouTube Video " ) ;
2014-11-23 14:20:40 +03:00
case VimeoLink : return qsl ( " Vimeo Video " ) ;
2014-11-12 23:18:00 +03:00
case InstagramLink : return qsl ( " Instagram Link " ) ;
2014-11-13 14:27:10 +03:00
case GoogleMapsLink : return lang ( lng_maps_point ) ;
2014-11-12 23:18:00 +03:00
}
}
return QString ( ) ;
}
2014-11-22 12:45:04 +03:00
const QString HistoryImageLink : : inHistoryText ( ) const {
if ( data ) {
switch ( data - > type ) {
case YouTubeLink : return qsl ( " [ YouTube Video : " ) + link - > text ( ) + qsl ( " ] " ) ;
2014-11-23 14:20:40 +03:00
case VimeoLink : return qsl ( " [ Vimeo Video : " ) + link - > text ( ) + qsl ( " ] " ) ;
2014-11-22 12:45:04 +03:00
case InstagramLink : return qsl ( " [ Instagram Link : " ) + link - > text ( ) + qsl ( " ] " ) ;
case GoogleMapsLink : return qsl ( " [ " ) + lang ( lng_maps_point ) + qsl ( " : " ) + link - > text ( ) + qsl ( " ] " ) ;
}
}
return qsl ( " [ Link : " ) + link - > text ( ) + qsl ( " ] " ) ;
}
2014-11-12 23:18:00 +03:00
bool HistoryImageLink : : hasPoint ( int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
if ( width < 0 ) width = w ;
return ( x > = 0 & & y > = 0 & & x < width & & y < _height ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryImageLink : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent , int32 width ) const {
2014-11-12 23:18:00 +03:00
if ( width < 0 ) width = w ;
2015-03-19 12:18:19 +03:00
int skipx = 0 , skipy = 0 , height = _height ;
2015-04-30 16:53:36 +03:00
const HistoryReply * reply = toHistoryReply ( parent ) ;
const HistoryForwarded * fwd = reply ? 0 : toHistoryForwarded ( parent ) ;
int replyFrom = 0 , fwdFrom = 0 ;
if ( reply | | ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) ) {
2015-03-19 12:18:19 +03:00
skipx = st : : mediaPadding . left ( ) ;
2015-04-30 16:53:36 +03:00
if ( reply ) {
skipy = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
} if ( fwd ) {
skipy = st : : msgServiceNameFont - > height + st : : msgPadding . top ( ) ;
}
2015-03-19 12:18:19 +03:00
if ( ! parent - > out ( ) & & parent - > history ( ) - > peer - > chat ) {
replyFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-04-30 16:53:36 +03:00
fwdFrom = st : : msgPadding . top ( ) + st : : msgNameFont - > height ;
2015-03-19 12:18:19 +03:00
skipy + = replyFrom ;
if ( x > = st : : mediaPadding . left ( ) & & y > = st : : msgPadding . top ( ) & & x < width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) & & x < st : : mediaPadding . left ( ) + parent - > from ( ) - > nameText . maxWidth ( ) & & y < replyFrom ) {
2015-04-08 02:03:32 +03:00
lnk = parent - > from ( ) - > lnk ;
return ;
2015-03-19 12:18:19 +03:00
}
2015-04-30 16:53:36 +03:00
if ( ! fwd & & ! reply ) skipy + = st : : msgPadding . top ( ) ;
} else if ( ! reply ) {
fwdFrom = st : : msgPadding . top ( ) ;
skipy + = fwdFrom ;
}
if ( reply ) {
if ( x > = 0 & & y > = replyFrom + st : : msgReplyPadding . top ( ) & & x < width & & y < skipy - st : : msgReplyPadding . bottom ( ) ) {
lnk = reply - > replyToLink ( ) ;
return ;
}
} else if ( fwd ) {
if ( y > = fwdFrom & & y < fwdFrom + st : : msgServiceNameFont - > height ) {
2015-06-27 16:02:00 +03:00
return fwd - > getForwardedState ( lnk , state , x - st : : mediaPadding . left ( ) , width - st : : mediaPadding . left ( ) - st : : mediaPadding . right ( ) ) ;
2015-04-30 16:53:36 +03:00
}
2015-03-19 12:18:19 +03:00
}
2015-04-30 16:53:36 +03:00
height - = st : : mediaPadding . bottom ( ) ;
2015-03-19 12:18:19 +03:00
width - = st : : mediaPadding . left ( ) + st : : mediaPadding . right ( ) ;
}
if ( x > = skipx & & y > = skipy & & x < skipx + width & & y < height & & data ) {
2015-04-08 02:03:32 +03:00
lnk = link ;
return ;
2014-11-12 23:18:00 +03:00
}
}
HistoryMedia * HistoryImageLink : : clone ( ) const {
return new HistoryImageLink ( * this ) ;
}
2014-05-30 12:53:19 +04:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , const MTPDmessage & msg ) :
2015-03-19 12:18:19 +03:00
HistoryItem ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . vfrom_id . v )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
QString text ( textClean ( qs ( msg . vmessage ) ) ) ;
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2014-05-30 12:53:19 +04:00
initMedia ( msg . vmedia , text ) ;
initDimensions ( text ) ;
}
2015-03-19 12:18:19 +03:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , const QString & msg , const MTPMessageMedia & media ) :
HistoryItem ( history , block , msgId , flags , date , from )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
QString text ( msg ) ;
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2014-05-30 12:53:19 +04:00
initMedia ( media , text ) ;
initDimensions ( text ) ;
}
2015-03-19 12:18:19 +03:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , const QString & msg , HistoryMedia * fromMedia ) :
HistoryItem ( history , block , msgId , flags , date , from )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2014-06-16 13:31:10 +04:00
{
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2014-05-30 12:53:19 +04:00
if ( fromMedia ) {
2014-08-15 15:19:32 +04:00
_media = fromMedia - > clone ( ) ;
_media - > regItem ( this ) ;
2014-05-30 12:53:19 +04:00
}
2015-01-02 17:55:24 +03:00
initDimensions ( msg ) ;
}
2015-03-19 12:18:19 +03:00
HistoryMessage : : HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , DocumentData * doc ) :
HistoryItem ( history , block , msgId , flags , date , from )
2015-01-02 17:55:24 +03:00
, _text ( st : : msgMinWidth )
, _textWidth ( 0 )
, _textHeight ( 0 )
, _media ( 0 )
{
2015-04-30 16:53:36 +03:00
initTime ( ) ;
2015-01-02 17:55:24 +03:00
initMediaFromDocument ( doc ) ;
initDimensions ( QString ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-30 16:53:36 +03:00
void HistoryMessage : : initTime ( ) {
_time = date . toString ( cTimeFormat ( ) ) ;
_timeWidth = st : : msgDateFont - > m . width ( _time ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryMessage : : initMedia ( const MTPMessageMedia & media , QString & currentText ) {
switch ( media . type ( ) ) {
case mtpc_messageMediaContact : {
const MTPDmessageMediaContact & d ( media . c_messageMediaContact ( ) ) ;
2014-08-15 15:19:32 +04:00
_media = new HistoryContact ( d . vuser_id . v , qs ( d . vfirst_name ) , qs ( d . vlast_name ) , qs ( d . vphone_number ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageMediaGeo : {
const MTPGeoPoint & point ( media . c_messageMediaGeo ( ) . vgeo ) ;
if ( point . type ( ) = = mtpc_geoPoint ) {
const MTPDgeoPoint & d ( point . c_geoPoint ( ) ) ;
2014-11-13 14:27:10 +03:00
_media = new HistoryImageLink ( qsl ( " location:%1,%2 " ) . arg ( d . vlat . v ) . arg ( d . vlong . v ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageMediaVenue : {
const MTPDmessageMediaVenue & d ( media . c_messageMediaVenue ( ) ) ;
if ( d . vgeo . type ( ) = = mtpc_geoPoint ) {
const MTPDgeoPoint & g ( d . vgeo . c_geoPoint ( ) ) ;
_media = new HistoryImageLink ( qsl ( " location:%1,%2 " ) . arg ( g . vlat . v ) . arg ( g . vlong . v ) , qs ( d . vtitle ) , qs ( d . vaddress ) ) ;
}
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageMediaPhoto : {
2015-04-30 16:53:36 +03:00
const MTPDmessageMediaPhoto & photo ( media . c_messageMediaPhoto ( ) ) ;
if ( photo . vphoto . type ( ) = = mtpc_photo ) {
_media = new HistoryPhoto ( photo . vphoto . c_photo ( ) , qs ( photo . vcaption ) , this ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaVideo : {
2015-04-30 16:53:36 +03:00
const MTPDmessageMediaVideo & video ( media . c_messageMediaVideo ( ) ) ;
if ( video . vvideo . type ( ) = = mtpc_video ) {
_media = new HistoryVideo ( video . vvideo . c_video ( ) , qs ( video . vcaption ) , this ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaAudio : {
const MTPAudio & audio ( media . c_messageMediaAudio ( ) . vaudio ) ;
if ( audio . type ( ) = = mtpc_audio ) {
2014-08-15 15:19:32 +04:00
_media = new HistoryAudio ( audio . c_audio ( ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageMediaDocument : {
const MTPDocument & document ( media . c_messageMediaDocument ( ) . vdocument ) ;
if ( document . type ( ) = = mtpc_document ) {
2015-01-02 17:55:24 +03:00
DocumentData * doc = App : : feedDocument ( document ) ;
return initMediaFromDocument ( doc ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-04 23:01:34 +03:00
case mtpc_messageMediaWebPage : {
const MTPWebPage & d ( media . c_messageMediaWebPage ( ) . vwebpage ) ;
switch ( d . type ( ) ) {
case mtpc_webPageEmpty : initMediaFromText ( currentText ) ; break ;
case mtpc_webPagePending : {
WebPageData * webPage = App : : feedWebPage ( d . c_webPagePending ( ) ) ;
_media = new HistoryWebPage ( webPage ) ;
} break ;
case mtpc_webPage : {
_media = new HistoryWebPage ( App : : feedWebPage ( d . c_webPage ( ) ) ) ;
} break ;
}
} break ;
2015-07-15 14:23:59 +03:00
default : initMediaFromText ( currentText ) ; break ;
2014-05-30 12:53:19 +04:00
} ;
2014-08-15 15:19:32 +04:00
if ( _media ) _media - > regItem ( this ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-04 23:01:34 +03:00
void HistoryMessage : : initMediaFromText ( QString & currentText ) {
QString lnk = currentText . trimmed ( ) ;
if ( /*reYouTube1.match(currentText).hasMatch() || reYouTube2.match(currentText).hasMatch() || reInstagram.match(currentText).hasMatch() || */ reVimeo . match ( currentText ) . hasMatch ( ) ) {
_media = new HistoryImageLink ( lnk ) ;
currentText = QString ( ) ;
}
}
2015-01-02 17:55:24 +03:00
void HistoryMessage : : initMediaFromDocument ( DocumentData * doc ) {
2015-07-01 00:07:05 +03:00
if ( doc - > sticker ( ) ) {
2015-01-02 17:55:24 +03:00
_media = new HistorySticker ( doc ) ;
} else {
_media = new HistoryDocument ( doc ) ;
}
_media - > regItem ( this ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryMessage : : initDimensions ( const QString & text ) {
2015-04-04 23:01:34 +03:00
if ( ! _media | | ! text . isEmpty ( ) ) { // !justMedia()
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) ) {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , text , itemTextParseOptions ( this ) ) ;
2015-04-04 23:01:34 +03:00
} else {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , text + textcmdSkipBlock ( timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) , itemTextParseOptions ( this ) ) ;
2015-04-04 23:01:34 +03:00
}
2014-10-10 16:46:20 +04:00
}
}
void HistoryMessage : : initDimensions ( const HistoryItem * parent ) {
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-08-15 15:19:32 +04:00
_media - > initDimensions ( this ) ;
_maxw = _media - > maxWidth ( ) ;
2015-04-04 23:01:34 +03:00
_minh = _media - > minHeight ( ) ;
2014-05-30 12:53:19 +04:00
} else {
_maxw = _text . maxWidth ( ) ;
_minh = _text . minHeight ( ) ;
_maxw + = st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
2015-04-04 23:01:34 +03:00
if ( _media ) {
_media - > initDimensions ( this ) ;
2015-05-20 22:28:24 +03:00
if ( _media - > isDisplayed ( ) & & _text . hasSkipBlock ( ) ) {
QString was = HistoryMessage : : selectedText ( FullItemSel ) ;
if ( ! was . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , was , itemTextParseOptions ( this ) ) ; // without date skip
2015-05-20 22:28:24 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
}
} else if ( ! _media - > isDisplayed ( ) & & ! _text . hasSkipBlock ( ) ) {
QString was = HistoryMessage : : selectedText ( FullItemSel ) ;
if ( ! was . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , was + textcmdSkipBlock ( timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) , itemTextParseOptions ( this ) ) ; // without date skip
2015-05-20 22:28:24 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
}
}
if ( _media - > isDisplayed ( ) ) {
int32 maxw = _media - > maxWidth ( ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
if ( maxw > _maxw ) _maxw = maxw ;
_minh + = st : : msgPadding . bottom ( ) + _media - > minHeight ( ) ;
}
2015-04-04 23:01:34 +03:00
}
2014-05-30 12:53:19 +04:00
}
fromNameUpdated ( ) ;
}
void HistoryMessage : : fromNameUpdated ( ) const {
2014-08-15 15:19:32 +04:00
if ( _media ) return ;
2015-03-19 12:18:19 +03:00
int32 _namew = ( ( ! out ( ) & & _history - > peer - > chat ) ? _from - > nameText . maxWidth ( ) : 0 ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( _namew > _maxw ) _maxw = _namew ;
}
bool HistoryMessage : : uploading ( ) const {
2014-08-15 15:19:32 +04:00
return _media ? _media - > uploading ( ) : false ;
2014-05-30 12:53:19 +04:00
}
QString HistoryMessage : : selectedText ( uint32 selection ) const {
2014-08-15 15:19:32 +04:00
if ( _media & & selection = = FullItemSel ) {
2015-04-04 23:01:34 +03:00
QString text = _text . original ( 0 , 0xFFFF ) , mediaText = _media - > inHistoryText ( ) ;
return text . isEmpty ( ) ? mediaText : ( mediaText . isEmpty ( ) ? text : ( text + ' ' + mediaText ) ) ;
2014-05-30 12:53:19 +04:00
}
uint16 selectedFrom = ( selection = = FullItemSel ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullItemSel ) ? 0xFFFF : ( selection & 0xFFFF ) ;
return _text . original ( selectedFrom , selectedTo ) ;
}
2015-03-19 12:18:19 +03:00
QString HistoryMessage : : inDialogsText ( ) const {
2015-04-04 23:01:34 +03:00
QString result = _media ? _media - > inDialogsText ( ) : QString ( ) ;
return result . isEmpty ( ) ? _text . original ( 0 , 0xFFFF , false ) : result ;
2015-03-19 12:18:19 +03:00
}
2014-08-11 13:03:45 +04:00
HistoryMedia * HistoryMessage : : getMedia ( bool inOverview ) const {
2014-08-15 15:19:32 +04:00
return _media ;
2014-05-30 12:53:19 +04:00
}
2015-04-04 23:01:34 +03:00
void HistoryMessage : : setMedia ( const MTPmessageMedia & media ) {
2015-04-11 11:04:10 +01:00
if ( ( ! _media | | _media - > isImageLink ( ) ) & & media . type ( ) = = mtpc_messageMediaEmpty ) return ;
2015-05-20 22:28:24 +03:00
bool mediaWasDisplayed = false ;
2015-04-08 02:03:32 +03:00
if ( _media ) {
2015-05-20 22:28:24 +03:00
mediaWasDisplayed = _media - > isDisplayed ( ) ;
2015-04-08 02:03:32 +03:00
delete _media ;
_media = 0 ;
}
2015-04-05 11:40:56 +03:00
QString t ;
initMedia ( media , t ) ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) & & ! mediaWasDisplayed ) {
2015-04-04 23:01:34 +03:00
QString was = HistoryMessage : : selectedText ( FullItemSel ) ;
2015-04-30 16:53:36 +03:00
if ( ! was . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , was , itemTextParseOptions ( this ) ) ; // without date skip
2015-04-04 23:01:34 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
}
2015-05-20 22:28:24 +03:00
} else if ( mediaWasDisplayed & & ( ! _media | | ! _media - > isDisplayed ( ) ) ) {
QString was = HistoryMessage : : selectedText ( FullItemSel ) ;
if ( ! was . isEmpty ( ) ) {
2015-06-15 20:19:24 +03:00
_text . setText ( st : : msgFont , was + textcmdSkipBlock ( timeWidth ( true ) , st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ) , itemTextParseOptions ( this ) ) ; // without date skip
2015-05-20 22:28:24 +03:00
_textWidth = 0 ;
_textHeight = 0 ;
}
2015-04-04 23:01:34 +03:00
}
initDimensions ( 0 ) ;
if ( App : : main ( ) ) App : : main ( ) - > itemResized ( this ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryMessage : : draw ( QPainter & p , uint32 selection ) const {
textstyleSet ( & ( out ( ) ? st : : outTextStyle : st : : inTextStyle ) ) ;
2015-07-17 22:17:37 +03:00
uint64 ms = App : : main ( ) ? App : : main ( ) - > animActiveTime ( id ) : 0 ;
if ( ms ) {
if ( ms > st : : activeFadeInDuration + st : : activeFadeOutDuration ) {
App : : main ( ) - > stopAnimActive ( ) ;
} else {
float64 dt = ( ms > st : : activeFadeInDuration ) ? ( 1 - ( ms - st : : activeFadeInDuration ) / float64 ( st : : activeFadeOutDuration ) ) : ( ms / float64 ( st : : activeFadeInDuration ) ) ;
float64 o = p . opacity ( ) ;
p . setOpacity ( o * dt ) ;
p . fillRect ( 0 , 0 , _history - > width , _height , textstyleCurrent ( ) - > selectOverlay - > b ) ;
p . setOpacity ( o ) ;
2014-07-04 15:12:54 +04:00
}
}
2014-05-30 12:53:19 +04:00
bool selected = ( selection = = FullItemSel ) ;
if ( _from - > nameVersion > _fromVersion ) {
fromNameUpdated ( ) ;
_fromVersion = _from - > nameVersion ;
}
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) , mwidth = st : : msgMaxWidth ;
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-11-18 15:41:33 +03:00
if ( _media - > maxWidth ( ) > mwidth ) mwidth = _media - > maxWidth ( ) ;
if ( _media - > currentWidth ( ) < mwidth ) mwidth = _media - > currentWidth ( ) ;
}
2014-10-10 17:47:39 +04:00
if ( width > mwidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - mwidth ;
2014-10-10 17:47:39 +04:00
width = mwidth ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) {
2015-05-20 22:28:24 +03:00
p . drawPixmap ( left , _height - st : : msgMargin . bottom ( ) - st : : msgPhotoSize , _from - > photo - > pixRounded ( st : : msgPhotoSize ) ) ;
2014-05-30 12:53:19 +04:00
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-05-30 12:53:19 +04:00
p . save ( ) ;
p . translate ( left , st : : msgMargin . top ( ) ) ;
2014-08-15 15:19:32 +04:00
_media - > draw ( p , this , selected ) ;
2014-05-30 12:53:19 +04:00
p . restore ( ) ;
} else {
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-05-20 22:28:24 +03:00
style : : color bg ( selected ? ( out ( ) ? st : : msgOutSelectBg : st : : msgInSelectBg ) : ( out ( ) ? st : : msgOutBg : st : : msgInBg ) ) ;
style : : color sh ( selected ? ( out ( ) ? st : : msgOutSelectShadow : st : : msgInSelectShadow ) : ( out ( ) ? st : : msgOutShadow : st : : msgInShadow ) ) ;
RoundCorners cors ( selected ? ( out ( ) ? MessageOutSelectedCorners : MessageInSelectedCorners ) : ( out ( ) ? MessageOutCorners : MessageInCorners ) ) ;
App : : roundRect ( p , r , bg , cors , & sh ) ;
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) {
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgNameFont - > f ) ;
p . setPen ( _from - > color - > p ) ;
_from - > nameText . drawElided ( p , r . left ( ) + st : : msgPadding . left ( ) , r . top ( ) + st : : msgPadding . top ( ) , width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) ;
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
drawMessageText ( p , trect , selection ) ;
2015-04-04 23:01:34 +03:00
if ( _media ) {
p . save ( ) ;
p . translate ( left + st : : msgPadding . left ( ) , _height - st : : msgMargin . bottom ( ) - st : : msgPadding . bottom ( ) - _media - > height ( ) ) ;
_media - > draw ( p , this , selected ) ;
p . restore ( ) ;
}
2014-05-30 12:53:19 +04:00
p . setFont ( st : : msgDateFont - > f ) ;
2015-03-19 12:18:19 +03:00
style : : color date ( selected ? ( out ( ) ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ( ) ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
2014-05-30 12:53:19 +04:00
p . setPen ( date - > p ) ;
2015-04-30 16:53:36 +03:00
p . drawText ( r . right ( ) - st : : msgPadding . right ( ) + st : : msgDateDelta . x ( ) - timeWidth ( true ) + st : : msgDateSpace , r . bottom ( ) - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > descent , _time ) ;
2015-03-19 12:18:19 +03:00
if ( out ( ) ) {
2015-04-04 23:01:34 +03:00
QPoint iconPos ( r . right ( ) + st : : msgCheckPos . x ( ) - st : : msgPadding . right ( ) - st : : msgCheckRect . pxWidth ( ) , r . bottom ( ) + st : : msgCheckPos . y ( ) - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgCheckRect . pxHeight ( ) ) ;
2014-05-30 12:53:19 +04:00
const QRect * iconRect ;
if ( id > 0 ) {
if ( unread ( ) ) {
iconRect = & ( selected ? st : : msgSelectCheckRect : st : : msgCheckRect ) ;
} else {
iconRect = & ( selected ? st : : msgSelectDblCheckRect : st : : msgDblCheckRect ) ;
}
} else {
iconRect = & st : : msgSendingRect ;
}
p . drawPixmap ( iconPos , App : : sprite ( ) , * iconRect ) ;
}
}
}
void HistoryMessage : : drawMessageText ( QPainter & p , const QRect & trect , uint32 selection ) const {
p . setPen ( st : : msgColor - > p ) ;
p . setFont ( st : : msgFont - > f ) ;
uint16 selectedFrom = ( selection = = FullItemSel ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullItemSel ) ? 0 : selection & 0xFFFF ;
_text . draw ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , Qt : : AlignLeft , 0 , - 1 , selectedFrom , selectedTo ) ;
textstyleRestore ( ) ;
}
2014-10-10 16:46:20 +04:00
int32 HistoryMessage : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
width - = st : : msgMargin . left ( ) + st : : msgMargin . right ( ) ;
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-10-10 16:46:20 +04:00
_height = _media - > resize ( width , dontRecountText , this ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-04-04 23:01:34 +03:00
if ( dontRecountText & & ! _media ) return _height ;
2014-10-10 16:46:20 +04:00
2014-05-30 12:53:19 +04:00
if ( width < st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ) {
width = st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ;
} else if ( width > st : : msgMaxWidth ) {
width = st : : msgMaxWidth ;
}
int32 nwidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 0 ) ;
if ( nwidth ! = _textWidth ) {
_textWidth = nwidth ;
_textHeight = _text . countHeight ( nwidth ) ;
}
if ( width > = _maxw ) {
_height = _minh ;
2015-04-04 23:01:34 +03:00
if ( _media ) _media - > resize ( _maxw - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , dontRecountText , this ) ;
2014-05-30 12:53:19 +04:00
} else {
_height = _textHeight ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) ) _height + = st : : msgPadding . bottom ( ) + _media - > resize ( nwidth , dontRecountText , this ) ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) {
2014-05-30 12:53:19 +04:00
_height + = st : : msgNameFont - > height ;
}
_height + = st : : msgPadding . top ( ) + st : : msgPadding . bottom ( ) ;
}
_height + = st : : msgMargin . top ( ) + st : : msgMargin . bottom ( ) ;
return _height ;
}
bool HistoryMessage : : hasPoint ( int32 x , int32 y ) const {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) , mwidth = st : : msgMaxWidth ;
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-11-18 16:59:18 +03:00
if ( _media - > maxWidth ( ) > mwidth ) mwidth = _media - > maxWidth ( ) ;
if ( _media - > currentWidth ( ) < mwidth ) mwidth = _media - > currentWidth ( ) ;
}
2014-10-10 17:47:39 +04:00
if ( width > mwidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - mwidth ;
2014-10-10 17:47:39 +04:00
width = mwidth ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return false ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-10-10 16:46:20 +04:00
return _media - > hasPoint ( x - left , y - st : : msgMargin . top ( ) , this ) ;
2014-05-30 12:53:19 +04:00
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryMessage : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) , mwidth = st : : msgMaxWidth ;
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2014-11-18 16:59:18 +03:00
if ( _media - > maxWidth ( ) > mwidth ) mwidth = _media - > maxWidth ( ) ;
if ( _media - > currentWidth ( ) < mwidth ) mwidth = _media - > currentWidth ( ) ;
}
2014-10-10 17:47:39 +04:00
if ( width > mwidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - mwidth ;
2014-10-10 17:47:39 +04:00
width = mwidth ;
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
if ( x > = left & & x < left + st : : msgPhotoSize & & y > = _height - st : : msgMargin . bottom ( ) - st : : msgPhotoSize & & y < _height - st : : msgMargin . bottom ( ) ) {
lnk = _from - > lnk ;
return ;
}
2015-05-14 19:50:04 +03:00
// width -= st::msgPhotoSkip;
2014-05-30 12:53:19 +04:00
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) {
2015-06-27 16:02:00 +03:00
_media - > getState ( lnk , state , x - left , y - st : : msgMargin . top ( ) , this ) ;
2014-05-30 12:53:19 +04:00
return ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left name
2015-06-27 16:02:00 +03:00
if ( x > = r . left ( ) + st : : msgPadding . left ( ) & & y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + st : : msgNameFont - > height & & x < r . left ( ) + r . width ( ) - st : : msgPadding . right ( ) & & x < r . left ( ) + st : : msgPadding . left ( ) + _from - > nameText . maxWidth ( ) ) {
2014-05-30 12:53:19 +04:00
lnk = _from - > lnk ;
return ;
}
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
}
2015-06-27 16:02:00 +03:00
getStateFromMessageText ( lnk , state , x , y , r ) ;
2015-05-14 19:50:04 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryMessage : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
int32 dateX = r . right ( ) - st : : msgPadding . right ( ) + st : : msgDateDelta . x ( ) - timeWidth ( true ) + st : : msgDateSpace ;
int32 dateY = r . bottom ( ) - st : : msgPadding . bottom ( ) + st : : msgDateDelta . y ( ) - st : : msgDateFont - > height ;
bool inDate = QRect ( dateX , dateY , timeWidth ( true ) - st : : msgDateSpace , st : : msgDateFont - > height ) . contains ( x , y ) ;
2014-05-30 12:53:19 +04:00
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
TextLinkPtr medialnk ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) ) {
2015-04-04 23:01:34 +03:00
if ( y > = trect . bottom ( ) - _media - > height ( ) & & y < trect . bottom ( ) ) {
2015-06-27 16:02:00 +03:00
_media - > getState ( lnk , state , x - trect . left ( ) , y + _media - > height ( ) - trect . bottom ( ) , this ) ;
if ( inDate ) state = HistoryInDateCursorState ;
2015-04-08 02:03:32 +03:00
return ;
2015-04-04 23:01:34 +03:00
}
trect . setBottom ( trect . bottom ( ) - _media - > height ( ) - st : : msgPadding . bottom ( ) ) ;
}
2015-06-27 16:02:00 +03:00
bool inText = false ;
2014-05-30 12:53:19 +04:00
_text . getState ( lnk , inText , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) ) ;
2015-06-27 16:02:00 +03:00
if ( inDate ) {
state = HistoryInDateCursorState ;
} else if ( inText ) {
state = HistoryInTextCursorState ;
} else {
state = HistoryDefaultCursorState ;
}
2014-05-30 12:53:19 +04:00
}
void HistoryMessage : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-04-04 23:01:34 +03:00
if ( justMedia ( ) ) return ;
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( width > st : : msgMaxWidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
2014-05-30 12:53:19 +04:00
width = st : : msgMaxWidth ;
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left name
2014-05-30 12:53:19 +04:00
r . setTop ( r . top ( ) + st : : msgNameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-05-20 22:28:24 +03:00
if ( _media & & _media - > isDisplayed ( ) ) {
2015-04-04 23:01:34 +03:00
trect . setBottom ( trect . bottom ( ) - _media - > height ( ) - st : : msgPadding . bottom ( ) ) ;
}
2014-05-30 12:53:19 +04:00
_text . getSymbol ( symbol , after , upon , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) ) ;
}
void HistoryMessage : : drawInDialog ( QPainter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
if ( cacheFor ! = this ) {
cacheFor = this ;
2015-03-19 12:18:19 +03:00
QString msg ( inDialogsText ( ) ) ;
2014-05-30 12:53:19 +04:00
if ( _history - > peer - > chat | | out ( ) ) {
2014-10-07 21:57:57 +04:00
TextCustomTagsMap custom ;
2014-05-30 12:53:19 +04:00
custom . insert ( QChar ( ' c ' ) , qMakePair ( textcmdStartLink ( 1 ) , textcmdStopLink ( ) ) ) ;
2014-12-18 21:40:49 +03:00
msg = lng_message_with_from ( lt_from , textRichPrepare ( ( _from = = App : : self ( ) ) ? lang ( lng_from_you ) : _from - > firstName ) , lt_message , textRichPrepare ( msg ) ) ;
2014-10-07 21:57:57 +04:00
cache . setRichText ( st : : dlgHistFont , msg , _textDlgOptions , custom ) ;
} else {
cache . setText ( st : : dlgHistFont , msg , _textDlgOptions ) ;
2014-05-30 12:53:19 +04:00
}
}
if ( r . width ( ) ) {
textstyleSet ( & ( act ? st : : dlgActiveTextStyle : st : : dlgTextStyle ) ) ;
p . setFont ( st : : dlgHistFont - > f ) ;
2015-04-04 23:01:34 +03:00
p . setPen ( ( act ? st : : dlgActiveColor : ( justMedia ( ) ? st : : dlgSystemColor : st : : dlgTextColor ) ) - > p ) ;
2014-05-30 12:53:19 +04:00
cache . drawElided ( p , r . left ( ) , r . top ( ) , r . width ( ) , r . height ( ) / st : : dlgHistFont - > height ) ;
2014-12-05 16:44:27 +03:00
textstyleRestore ( ) ;
2014-05-30 12:53:19 +04:00
}
}
2014-06-14 23:32:11 +04:00
QString HistoryMessage : : notificationHeader ( ) const {
return _history - > peer - > chat ? from ( ) - > name : QString ( ) ;
}
QString HistoryMessage : : notificationText ( ) const {
2015-03-19 12:18:19 +03:00
QString msg ( inDialogsText ( ) ) ;
2014-06-14 23:32:11 +04:00
if ( msg . size ( ) > 0xFF ) msg = msg . mid ( 0 , 0xFF ) + qsl ( " .. " ) ;
return msg ;
}
2014-05-30 12:53:19 +04:00
HistoryMessage : : ~ HistoryMessage ( ) {
2014-08-15 15:19:32 +04:00
if ( _media ) {
_media - > unregItem ( this ) ;
2015-04-04 23:01:34 +03:00
delete _media ;
2014-08-11 13:03:45 +04:00
}
2015-06-15 20:19:24 +03:00
if ( _flags & MTPDmessage : : flag_reply_markup ) {
App : : clearReplyMarkup ( id ) ;
}
2014-05-30 12:53:19 +04:00
}
2015-03-19 12:18:19 +03:00
HistoryForwarded : : HistoryForwarded ( History * history , HistoryBlock * block , const MTPDmessage & msg ) : HistoryMessage ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . vfrom_id . v , textClean ( qs ( msg . vmessage ) ) , msg . vmedia )
2014-06-16 13:31:10 +04:00
, fwdDate ( : : date ( msg . vfwd_date ) )
, fwdFrom ( App : : user ( msg . vfwd_from_id . v ) )
, fwdFromVersion ( fwdFrom - > nameVersion )
2014-12-23 02:11:37 +03:00
, fromWidth ( st : : msgServiceFont - > m . width ( lang ( lng_forwarded_from ) ) + st : : msgServiceFont - > spacew )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
}
2015-04-30 16:53:36 +03:00
HistoryForwarded : : HistoryForwarded ( History * history , HistoryBlock * block , MsgId id , HistoryMessage * msg ) : HistoryMessage ( history , block , id , ( ( history - > peer - > input . type ( ) ! = mtpc_inputPeerSelf ) ? ( MTPDmessage_flag_out | MTPDmessage_flag_unread ) : 0 ) | ( msg - > getMedia ( ) & & ( msg - > getMedia ( ) - > type ( ) = = MediaTypeAudio /* || msg->getMedia()->type() == MediaTypeVideo*/ ) ? MTPDmessage_flag_media_unread : 0 ) , : : date ( unixtime ( ) ) , MTP : : authedId ( ) , msg - > justMedia ( ) ? QString ( ) : msg - > HistoryMessage : : selectedText ( FullItemSel ) , msg - > getMedia ( ) )
2015-03-19 12:18:19 +03:00
, fwdDate ( msg - > dateForwarded ( ) )
, fwdFrom ( msg - > fromForwarded ( ) )
2014-06-16 13:31:10 +04:00
, fwdFromVersion ( fwdFrom - > nameVersion )
2014-12-23 02:11:37 +03:00
, fromWidth ( st : : msgServiceFont - > m . width ( lang ( lng_forwarded_from ) ) + st : : msgServiceFont - > spacew )
2014-06-16 13:31:10 +04:00
{
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
}
QString HistoryForwarded : : selectedText ( uint32 selection ) const {
if ( selection ! = FullItemSel ) return HistoryMessage : : selectedText ( selection ) ;
QString result , original = HistoryMessage : : selectedText ( selection ) ;
2015-03-19 12:18:19 +03:00
result . reserve ( lang ( lng_forwarded_from ) . size ( ) + fwdFrom - > name . size ( ) + 4 + original . size ( ) ) ;
result . append ( ' [ ' ) . append ( lang ( lng_forwarded_from ) ) . append ( ' ' ) . append ( fwdFrom - > name ) . append ( qsl ( " ] \n " ) ) . append ( original ) ;
2014-05-30 12:53:19 +04:00
return result ;
}
2015-03-19 12:18:19 +03:00
void HistoryForwarded : : initDimensions ( const HistoryItem * parent ) {
HistoryMessage : : initDimensions ( parent ) ;
fwdNameUpdated ( ) ;
}
2014-05-30 12:53:19 +04:00
void HistoryForwarded : : fwdNameUpdated ( ) const {
fwdFromName . setText ( st : : msgServiceNameFont , App : : peerName ( fwdFrom ) , _textNameOptions ) ;
2015-04-23 18:50:11 +03:00
if ( justMedia ( ) ) return ;
2014-05-30 12:53:19 +04:00
int32 _namew = fromWidth + fwdFromName . maxWidth ( ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
if ( _namew > _maxw ) _maxw = _namew ;
}
void HistoryForwarded : : draw ( QPainter & p , uint32 selection ) const {
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) & & fwdFrom - > nameVersion > fwdFromVersion ) {
2014-05-30 12:53:19 +04:00
fwdNameUpdated ( ) ;
fwdFromVersion = fwdFrom - > nameVersion ;
}
HistoryMessage : : draw ( p , selection ) ;
}
2015-04-23 18:50:11 +03:00
void HistoryForwarded : : drawForwardedFrom ( QPainter & p , int32 x , int32 y , int32 w , bool selected ) const {
2014-05-30 12:53:19 +04:00
style : : font serviceFont ( st : : msgServiceFont ) , serviceName ( st : : msgServiceNameFont ) ;
2015-04-23 18:50:11 +03:00
2015-03-19 12:18:19 +03:00
p . setPen ( ( selected ? ( out ( ) ? st : : msgOutServiceSelColor : st : : msgInServiceSelColor ) : ( out ( ) ? st : : msgOutServiceColor : st : : msgInServiceColor ) ) - > p ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( serviceFont - > f ) ;
2015-04-23 18:50:11 +03:00
if ( w > = fromWidth ) {
p . drawText ( x , y + serviceFont - > ascent , lang ( lng_forwarded_from ) ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( serviceName - > f ) ;
2015-04-23 18:50:11 +03:00
fwdFromName . drawElided ( p , x + fromWidth , y , w - fromWidth ) ;
2014-05-30 12:53:19 +04:00
} else {
2015-04-23 18:50:11 +03:00
p . drawText ( x , y + serviceFont - > ascent , serviceFont - > m . elidedText ( lang ( lng_forwarded_from ) , Qt : : ElideRight , w ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-23 18:50:11 +03:00
}
void HistoryForwarded : : drawMessageText ( QPainter & p , const QRect & trect , uint32 selection ) const {
drawForwardedFrom ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , ( selection = = FullItemSel ) ) ;
2014-05-30 12:53:19 +04:00
QRect realtrect ( trect ) ;
2015-05-14 19:50:04 +03:00
realtrect . setY ( trect . y ( ) + st : : msgServiceNameFont - > height ) ;
2014-05-30 12:53:19 +04:00
HistoryMessage : : drawMessageText ( p , realtrect , selection ) ;
}
2014-10-10 16:46:20 +04:00
int32 HistoryForwarded : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
HistoryMessage : : resize ( width , dontRecountText , parent ) ;
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) & & ( _media | | ! dontRecountText ) ) {
_height + = st : : msgServiceNameFont - > height ;
2014-05-30 12:53:19 +04:00
}
return _height ;
}
bool HistoryForwarded : : hasPoint ( int32 x , int32 y ) const {
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( width > st : : msgMaxWidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
2014-05-30 12:53:19 +04:00
width = st : : msgMaxWidth ;
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return false ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
}
return HistoryMessage : : hasPoint ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( width > st : : msgMaxWidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
2014-05-30 12:53:19 +04:00
width = st : : msgMaxWidth ;
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
if ( x > = left & & x < left + st : : msgPhotoSize ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) {
2014-05-30 12:53:19 +04:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
if ( y > = trect . top ( ) & & y < trect . top ( ) + st : : msgServiceNameFont - > height ) {
2015-06-27 16:02:00 +03:00
return getForwardedState ( lnk , state , x - trect . left ( ) , trect . right ( ) - trect . left ( ) ) ;
2014-05-30 12:53:19 +04:00
}
2015-04-04 23:01:34 +03:00
y - = st : : msgServiceNameFont - > height ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2014-05-30 12:53:19 +04:00
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
2015-05-14 19:50:04 +03:00
QRect realr ( r ) ;
realr . setHeight ( r . height ( ) - st : : msgServiceNameFont - > height ) ;
2015-06-27 16:02:00 +03:00
HistoryMessage : : getStateFromMessageText ( lnk , state , x , y , realr ) ;
2015-05-14 19:50:04 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryForwarded : : getForwardedState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 w ) const {
state = HistoryDefaultCursorState ;
2015-04-23 18:50:11 +03:00
if ( x > = fromWidth & & x < w & & x < fromWidth + fwdFromName . maxWidth ( ) ) {
lnk = fwdFrom - > lnk ;
} else {
lnk = TextLinkPtr ( ) ;
}
}
2014-05-30 12:53:19 +04:00
void HistoryForwarded : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
2014-05-30 12:53:19 +04:00
if ( width > st : : msgMaxWidth ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
2014-05-30 12:53:19 +04:00
width = st : : msgMaxWidth ;
}
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
2014-05-30 12:53:19 +04:00
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
2015-03-19 12:18:19 +03:00
if ( out ( ) ) left + = width - _maxw ;
2014-05-30 12:53:19 +04:00
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
2015-03-19 12:18:19 +03:00
if ( ! out ( ) & & _history - > peer - > chat ) {
2014-05-30 12:53:19 +04:00
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
2015-04-04 23:01:34 +03:00
y - = st : : msgServiceNameFont - > height ;
2014-05-30 12:53:19 +04:00
}
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
2015-03-19 12:18:19 +03:00
HistoryReply : : HistoryReply ( History * history , HistoryBlock * block , const MTPDmessage & msg ) : HistoryMessage ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . vfrom_id . v , textClean ( qs ( msg . vmessage ) ) , msg . vmedia )
, replyToMsgId ( msg . vreply_to_msg_id . v )
, replyToMsg ( 0 )
, replyToVersion ( 0 )
, _maxReplyWidth ( 0 )
{
if ( ! updateReplyTo ( ) ) {
App : : api ( ) - > requestReplyTo ( this , replyToMsgId ) ;
}
}
HistoryReply : : HistoryReply ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc ) : HistoryMessage ( history , block , msgId , flags , date , from , doc )
, replyToMsgId ( replyTo )
, replyToMsg ( 0 )
, replyToVersion ( 0 )
, _maxReplyWidth ( 0 )
{
if ( ! updateReplyTo ( ) ) {
App : : api ( ) - > requestReplyTo ( this , replyToMsgId ) ;
}
}
QString HistoryReply : : selectedText ( uint32 selection ) const {
if ( selection ! = FullItemSel | | ! replyToMsg ) return HistoryMessage : : selectedText ( selection ) ;
QString result , original = HistoryMessage : : selectedText ( selection ) ;
result . reserve ( lang ( lng_in_reply_to ) . size ( ) + replyToMsg - > from ( ) - > name . size ( ) + 4 + original . size ( ) ) ;
result . append ( ' [ ' ) . append ( lang ( lng_in_reply_to ) ) . append ( ' ' ) . append ( replyToMsg - > from ( ) - > name ) . append ( qsl ( " ] \n " ) ) . append ( original ) ;
return result ;
}
void HistoryReply : : initDimensions ( const HistoryItem * parent ) {
if ( ! replyToMsg ) {
_maxReplyWidth = st : : msgReplyBarSkip + st : : msgDateFont - > m . width ( lang ( replyToMsgId ? lng_profile_loading : lng_deleted_message ) ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
}
HistoryMessage : : initDimensions ( parent ) ;
if ( replyToMsg ) {
replyToNameUpdated ( ) ;
2015-04-04 23:01:34 +03:00
} else if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int maxw = _maxReplyWidth - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
if ( maxw > _maxw ) _maxw = maxw ;
}
}
bool HistoryReply : : updateReplyTo ( bool force ) {
if ( replyToMsg | | ! replyToMsgId ) return true ;
replyToMsg = App : : histItemById ( replyToMsgId ) ;
if ( replyToMsg ) {
App : : historyRegReply ( this , replyToMsg ) ;
replyToText . setText ( st : : msgFont , replyToMsg - > inReplyText ( ) , _textDlgOptions ) ;
replyToNameUpdated ( ) ;
replyToLnk = TextLinkPtr ( new MessageLink ( replyToMsg - > history ( ) - > peer - > id , replyToMsg - > id ) ) ;
} else if ( force ) {
replyToMsgId = 0 ;
}
if ( force ) {
initDimensions ( ) ;
if ( App : : main ( ) ) App : : main ( ) - > msgUpdated ( history ( ) - > peer - > id , this ) ;
}
return ( replyToMsg | | ! replyToMsgId ) ;
}
void HistoryReply : : replyToNameUpdated ( ) const {
if ( ! replyToMsg ) return ;
replyToName . setText ( st : : msgServiceNameFont , App : : peerName ( replyToMsg - > from ( ) ) , _textNameOptions ) ;
replyToVersion = replyToMsg - > from ( ) - > nameVersion ;
bool hasPreview = replyToMsg - > getMedia ( ) ? replyToMsg - > getMedia ( ) - > hasReplyPreview ( ) : false ;
int previewSkip = hasPreview ? ( st : : msgReplyBarSize . height ( ) + st : : msgReplyBarSkip - st : : msgReplyBarSize . width ( ) - st : : msgReplyBarPos . x ( ) ) : 0 ;
_maxReplyWidth = st : : msgReplyPadding . left ( ) + st : : msgReplyBarSkip + previewSkip + replyToName . maxWidth ( ) + st : : msgReplyPadding . right ( ) ;
2015-03-24 13:00:27 +03:00
int32 _textw = st : : msgReplyPadding . left ( ) + st : : msgReplyBarSkip + previewSkip + qMin ( replyToText . maxWidth ( ) , 4 * replyToName . maxWidth ( ) ) + st : : msgReplyPadding . right ( ) ;
2015-03-19 12:18:19 +03:00
if ( _textw > _maxReplyWidth ) _maxReplyWidth = _textw ;
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int maxw = _maxReplyWidth - st : : msgReplyPadding . left ( ) - st : : msgReplyPadding . right ( ) + st : : msgPadding . left ( ) + st : : msgPadding . right ( ) ;
if ( maxw > _maxw ) _maxw = maxw ;
}
}
int32 HistoryReply : : replyToWidth ( ) const {
return _maxReplyWidth ;
}
TextLinkPtr HistoryReply : : replyToLink ( ) const {
return replyToLnk ;
}
MsgId HistoryReply : : replyToId ( ) const {
return replyToMsgId ;
}
HistoryItem * HistoryReply : : replyToMessage ( ) const {
return replyToMsg ;
}
void HistoryReply : : replyToReplaced ( HistoryItem * oldItem , HistoryItem * newItem ) {
if ( replyToMsg = = oldItem ) {
replyToMsg = newItem ;
if ( ! newItem ) {
replyToMsgId = 0 ;
initDimensions ( ) ;
}
}
}
void HistoryReply : : draw ( QPainter & p , uint32 selection ) const {
if ( replyToMsg & & replyToMsg - > from ( ) - > nameVersion > replyToVersion ) {
replyToNameUpdated ( ) ;
}
HistoryMessage : : draw ( p , selection ) ;
}
void HistoryReply : : drawReplyTo ( QPainter & p , int32 x , int32 y , int32 w , bool selected , bool likeService ) const {
style : : color bar ;
if ( likeService ) {
bar = st : : white ;
} else {
bar = ( selected ? ( out ( ) ? st : : msgOutReplyBarSelColor : st : : msgInReplyBarSelColor ) : ( out ( ) ? st : : msgOutReplyBarColor : st : : msgInReplyBarColor ) ) ;
}
p . fillRect ( x + st : : msgReplyBarPos . x ( ) , y + st : : msgReplyPadding . top ( ) + st : : msgReplyBarPos . y ( ) , st : : msgReplyBarSize . width ( ) , st : : msgReplyBarSize . height ( ) , bar - > b ) ;
if ( w > st : : msgReplyBarSkip ) {
if ( replyToMsg ) {
bool hasPreview = replyToMsg - > getMedia ( ) ? replyToMsg - > getMedia ( ) - > hasReplyPreview ( ) : false ;
int previewSkip = hasPreview ? ( st : : msgReplyBarSize . height ( ) + st : : msgReplyBarSkip - st : : msgReplyBarSize . width ( ) - st : : msgReplyBarPos . x ( ) ) : 0 ;
if ( hasPreview ) {
ImagePtr replyPreview = replyToMsg - > getMedia ( ) - > replyPreview ( ) ;
if ( ! replyPreview - > isNull ( ) ) {
QRect to ( x + st : : msgReplyBarSkip , y + st : : msgReplyPadding . top ( ) + st : : msgReplyBarPos . y ( ) , st : : msgReplyBarSize . height ( ) , st : : msgReplyBarSize . height ( ) ) ;
2015-05-20 22:28:24 +03:00
p . drawPixmap ( to . x ( ) , to . y ( ) , replyPreview - > pixSingle ( replyPreview - > width ( ) / cIntRetinaFactor ( ) , replyPreview - > height ( ) / cIntRetinaFactor ( ) , to . width ( ) , to . height ( ) ) ) ;
2015-03-19 12:18:19 +03:00
if ( selected ) {
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , to , textstyleCurrent ( ) - > selectOverlay , SelectedOverlayCorners ) ;
2015-03-19 12:18:19 +03:00
}
}
}
if ( w > st : : msgReplyBarSkip + previewSkip ) {
if ( likeService ) {
p . setPen ( st : : white - > p ) ;
} else {
p . setPen ( ( selected ? ( out ( ) ? st : : msgOutServiceSelColor : st : : msgInServiceSelColor ) : ( out ( ) ? st : : msgOutServiceColor : st : : msgInServiceColor ) ) - > p ) ;
}
replyToName . drawElided ( p , x + st : : msgReplyBarSkip + previewSkip , y + st : : msgReplyPadding . top ( ) , w - st : : msgReplyBarSkip - previewSkip ) ;
2015-04-13 09:58:13 +01:00
HistoryMessage * replyToAsMsg = replyToMsg - > toHistoryMessage ( ) ;
2015-03-19 12:18:19 +03:00
if ( likeService ) {
2015-04-13 09:58:13 +01:00
} else if ( ( replyToAsMsg & & replyToAsMsg - > justMedia ( ) ) | | replyToMsg - > serviceMsg ( ) ) {
2015-03-19 12:18:19 +03:00
style : : color date ( selected ? ( out ( ) ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ( ) ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
p . setPen ( date - > p ) ;
} else {
p . setPen ( st : : msgColor - > p ) ;
}
replyToText . drawElided ( p , x + st : : msgReplyBarSkip + previewSkip , y + st : : msgReplyPadding . top ( ) + st : : msgServiceNameFont - > height , w - st : : msgReplyBarSkip - previewSkip ) ;
}
} else {
p . setFont ( st : : msgDateFont - > f ) ;
style : : color date ( selected ? ( out ( ) ? st : : msgOutSelectDateColor : st : : msgInSelectDateColor ) : ( out ( ) ? st : : msgOutDateColor : st : : msgInDateColor ) ) ;
if ( likeService ) {
p . setPen ( st : : white - > p ) ;
} else {
p . setPen ( date - > p ) ;
}
p . drawText ( x + st : : msgReplyBarSkip , y + st : : msgReplyPadding . top ( ) + ( st : : msgReplyBarSize . height ( ) - st : : msgDateFont - > height ) / 2 + st : : msgDateFont - > ascent , st : : msgDateFont - > m . elidedText ( lang ( replyToMsgId ? lng_profile_loading : lng_deleted_message ) , Qt : : ElideRight , w - st : : msgReplyBarSkip ) ) ;
}
}
}
void HistoryReply : : drawMessageText ( QPainter & p , const QRect & trect , uint32 selection ) const {
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
drawReplyTo ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , ( selection = = FullItemSel ) ) ;
QRect realtrect ( trect ) ;
realtrect . setY ( trect . y ( ) + h ) ;
HistoryMessage : : drawMessageText ( p , realtrect , selection ) ;
}
int32 HistoryReply : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
HistoryMessage : : resize ( width , dontRecountText , parent ) ;
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) & & ( _media | | ! dontRecountText ) ) {
2015-03-19 12:18:19 +03:00
_height + = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
}
return _height ;
}
bool HistoryReply : : hasPoint ( int32 x , int32 y ) const {
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
if ( width > st : : msgMaxWidth ) {
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
width = st : : msgMaxWidth ;
}
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return false ;
if ( width > = _maxw ) {
if ( out ( ) ) left + = width - _maxw ;
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
return r . contains ( x , y ) ;
}
return HistoryMessage : : hasPoint ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryReply : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2015-03-19 12:18:19 +03:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2015-03-19 12:18:19 +03:00
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
if ( width > st : : msgMaxWidth ) {
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
width = st : : msgMaxWidth ;
}
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
if ( x > = left & & x < left + st : : msgPhotoSize ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
if ( out ( ) ) left + = width - _maxw ;
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
if ( ! out ( ) & & _history - > peer - > chat ) {
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
if ( y > = trect . top ( ) & & y < trect . top ( ) + h ) {
if ( replyToMsg & & y > = trect . top ( ) + st : : msgReplyPadding . top ( ) & & y < trect . top ( ) + st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) & & x > = trect . left ( ) & & x < trect . right ( ) ) {
lnk = replyToLnk ;
}
return ;
}
y - = h ;
}
2015-06-27 16:02:00 +03:00
return HistoryMessage : : getState ( lnk , state , x , y ) ;
2015-03-19 12:18:19 +03:00
}
2015-06-27 16:02:00 +03:00
void HistoryReply : : getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const {
2015-05-14 19:50:04 +03:00
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
QRect realr ( r ) ;
realr . setHeight ( r . height ( ) - h ) ;
2015-06-27 16:02:00 +03:00
HistoryMessage : : getStateFromMessageText ( lnk , state , x , y , realr ) ;
2015-05-14 19:50:04 +03:00
}
2015-03-19 12:18:19 +03:00
void HistoryReply : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
2015-04-04 23:01:34 +03:00
if ( ! justMedia ( ) ) {
2015-03-19 12:18:19 +03:00
int32 left = out ( ) ? st : : msgMargin . right ( ) : st : : msgMargin . left ( ) , width = _history - > width - st : : msgMargin . left ( ) - st : : msgMargin . right ( ) ;
if ( width > st : : msgMaxWidth ) {
if ( out ( ) ) left + = width - st : : msgMaxWidth ;
width = st : : msgMaxWidth ;
}
if ( ! out ( ) & & _history - > peer - > chat ) { // from user left photo
// width -= st::msgPhotoSkip;
left + = st : : msgPhotoSkip ;
}
if ( width < 1 ) return ;
if ( width > = _maxw ) {
if ( out ( ) ) left + = width - _maxw ;
width = _maxw ;
}
QRect r ( left , st : : msgMargin . top ( ) , width , _height - st : : msgMargin . top ( ) - st : : msgMargin . bottom ( ) ) ;
if ( ! out ( ) & & _history - > peer - > chat ) {
style : : font nameFont ( st : : msgNameFont ) ;
if ( y > = r . top ( ) + st : : msgPadding . top ( ) & & y < r . top ( ) + st : : msgPadding . top ( ) + nameFont - > height ) {
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
r . setTop ( r . top ( ) + nameFont - > height ) ;
}
QRect trect ( r . marginsAdded ( - st : : msgPadding ) ) ;
int32 h = st : : msgReplyPadding . top ( ) + st : : msgReplyBarSize . height ( ) + st : : msgReplyPadding . bottom ( ) ;
y - = h ;
}
return HistoryMessage : : getSymbol ( symbol , after , upon , x , y ) ;
}
HistoryReply : : ~ HistoryReply ( ) {
if ( replyToMsg ) {
App : : historyUnregReply ( this , replyToMsg ) ;
} else if ( replyToMsgId ) {
App : : api ( ) - > itemRemoved ( this ) ;
}
}
2014-12-18 21:40:49 +03:00
void HistoryServiceMsg : : setMessageByAction ( const MTPmessageAction & action ) {
TextLinkPtr second ;
LangString text = lang ( lng_message_empty ) ;
QString from = textcmdLink ( 1 , _from - > name ) ;
2014-05-30 12:53:19 +04:00
switch ( action . type ( ) ) {
case mtpc_messageActionChatAddUser : {
const MTPDmessageActionChatAddUser & d ( action . c_messageActionChatAddUser ( ) ) ;
if ( App : : peerFromUser ( d . vuser_id ) = = _from - > id ) {
2014-12-18 21:40:49 +03:00
text = lng_action_user_joined ( lt_from , from ) ;
} else {
UserData * u = App : : user ( App : : peerFromUser ( d . vuser_id ) ) ;
second = TextLinkPtr ( new PeerLink ( u ) ) ;
text = lng_action_add_user ( lt_from , from , lt_user , textcmdLink ( 2 , u - > name ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
2015-04-30 16:53:36 +03:00
case mtpc_messageActionChatJoinedByLink : {
const MTPDmessageActionChatJoinedByLink & d ( action . c_messageActionChatJoinedByLink ( ) ) ;
if ( true | | App : : peerFromUser ( d . vinviter_id ) = = _from - > id ) {
text = lng_action_user_joined_by_link ( lt_from , from ) ;
//} else {
//UserData *u = App::user(App::peerFromUser(d.vinviter_id));
//second = TextLinkPtr(new PeerLink(u));
//text = lng_action_user_joined_by_link_from(lt_from, from, lt_inviter, textcmdLink(2, u->name));
}
} break ;
2014-05-30 12:53:19 +04:00
case mtpc_messageActionChatCreate : {
const MTPDmessageActionChatCreate & d ( action . c_messageActionChatCreate ( ) ) ;
2014-12-18 21:40:49 +03:00
text = lng_action_created_chat ( lt_from , from , lt_title , textClean ( qs ( d . vtitle ) ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatDeletePhoto : {
2014-12-18 21:40:49 +03:00
text = lng_action_removed_photo ( lt_from , from ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatDeleteUser : {
const MTPDmessageActionChatDeleteUser & d ( action . c_messageActionChatDeleteUser ( ) ) ;
if ( App : : peerFromUser ( d . vuser_id ) = = _from - > id ) {
2014-12-18 21:40:49 +03:00
text = lng_action_user_left ( lt_from , from ) ;
} else {
UserData * u = App : : user ( App : : peerFromUser ( d . vuser_id ) ) ;
second = TextLinkPtr ( new PeerLink ( u ) ) ;
text = lng_action_kick_user ( lt_from , from , lt_user , textcmdLink ( 2 , u - > name ) ) ;
2014-05-30 12:53:19 +04:00
}
} break ;
case mtpc_messageActionChatEditPhoto : {
const MTPDmessageActionChatEditPhoto & d ( action . c_messageActionChatEditPhoto ( ) ) ;
if ( d . vphoto . type ( ) = = mtpc_photo ) {
2014-10-07 21:57:57 +04:00
_media = new HistoryPhoto ( history ( ) - > peer , d . vphoto . c_photo ( ) , st : : msgServicePhotoWidth ) ;
2014-05-30 12:53:19 +04:00
}
2014-12-18 21:40:49 +03:00
text = lng_action_changed_photo ( lt_from , from ) ;
2014-05-30 12:53:19 +04:00
} break ;
case mtpc_messageActionChatEditTitle : {
const MTPDmessageActionChatEditTitle & d ( action . c_messageActionChatEditTitle ( ) ) ;
2014-12-18 21:40:49 +03:00
text = lng_action_changed_title ( lt_from , from , lt_title , textClean ( qs ( d . vtitle ) ) ) ;
2014-05-30 12:53:19 +04:00
} break ;
2014-12-18 21:40:49 +03:00
default : from = QString ( ) ; break ;
2014-05-30 12:53:19 +04:00
}
2014-12-18 21:40:49 +03:00
_text . setText ( st : : msgServiceFont , text , _historySrvOptions ) ;
if ( ! from . isEmpty ( ) ) {
_text . setLink ( 1 , TextLinkPtr ( new PeerLink ( _from ) ) ) ;
}
if ( second ) {
_text . setLink ( 2 , second ) ;
}
return ;
2014-05-30 12:53:19 +04:00
}
HistoryServiceMsg : : HistoryServiceMsg ( History * history , HistoryBlock * block , const MTPDmessageService & msg ) :
2015-03-19 12:18:19 +03:00
HistoryItem ( history , block , msg . vid . v , msg . vflags . v , : : date ( msg . vdate ) , msg . vfrom_id . v )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgMinWidth )
2014-08-15 15:19:32 +04:00
, _media ( 0 )
2014-06-16 13:31:10 +04:00
{
2014-12-18 21:40:49 +03:00
setMessageByAction ( msg . vaction ) ;
2014-05-30 12:53:19 +04:00
}
2015-07-15 14:23:59 +03:00
HistoryServiceMsg : : HistoryServiceMsg ( History * history , HistoryBlock * block , MsgId msgId , QDateTime date , const QString & msg , int32 flags , HistoryMedia * media , int32 from ) :
HistoryItem ( history , block , msgId , flags , date , from )
2014-06-16 13:31:10 +04:00
, _text ( st : : msgServiceFont , msg , _historySrvOptions , st : : dlgMinWidth )
2014-08-15 15:19:32 +04:00
, _media ( media )
2014-06-16 13:31:10 +04:00
{
2014-10-10 16:46:20 +04:00
}
void HistoryServiceMsg : : initDimensions ( const HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
_maxw = _text . maxWidth ( ) + st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) ;
_minh = _text . minHeight ( ) ;
2014-10-10 16:46:20 +04:00
if ( _media ) _media - > initDimensions ( ) ;
2014-05-30 12:53:19 +04:00
}
QString HistoryServiceMsg : : selectedText ( uint32 selection ) const {
uint16 selectedFrom = ( selection = = FullItemSel ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullItemSel ) ? 0xFFFF : ( selection & 0xFFFF ) ;
return _text . original ( selectedFrom , selectedTo ) ;
}
2015-03-19 12:18:19 +03:00
QString HistoryServiceMsg : : inDialogsText ( ) const {
return _text . original ( 0 , 0xFFFF , false ) ;
}
QString HistoryServiceMsg : : inReplyText ( ) const {
QString result = HistoryServiceMsg : : inDialogsText ( ) ;
return result . trimmed ( ) . startsWith ( from ( ) - > name ) ? result . trimmed ( ) . mid ( from ( ) - > name . size ( ) ) . trimmed ( ) : result ;
}
2014-05-30 12:53:19 +04:00
void HistoryServiceMsg : : draw ( QPainter & p , uint32 selection ) const {
2015-07-17 22:17:37 +03:00
uint64 ms = App : : main ( ) ? App : : main ( ) - > animActiveTime ( id ) : 0 ;
if ( ms ) {
if ( ms > st : : activeFadeInDuration + st : : activeFadeOutDuration ) {
App : : main ( ) - > stopAnimActive ( ) ;
} else {
textstyleSet ( & st : : inTextStyle ) ;
float64 dt = ( ms > st : : activeFadeInDuration ) ? ( 1 - ( ms - st : : activeFadeInDuration ) / float64 ( st : : activeFadeOutDuration ) ) : ( ms / float64 ( st : : activeFadeInDuration ) ) ;
float64 o = p . opacity ( ) ;
p . setOpacity ( o * dt ) ;
p . fillRect ( 0 , 0 , _history - > width , _height , textstyleCurrent ( ) - > selectOverlay - > b ) ;
p . setOpacity ( o ) ;
2015-03-19 12:18:19 +03:00
}
}
2014-05-30 12:53:19 +04:00
textstyleSet ( & st : : serviceTextStyle ) ;
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
p . save ( ) ;
2014-08-15 15:19:32 +04:00
p . translate ( st : : msgServiceMargin . left ( ) + ( width - _media - > maxWidth ( ) ) / 2 , st : : msgServiceMargin . top ( ) + height + st : : msgServiceMargin . top ( ) ) ;
_media - > draw ( p , this , selection = = FullItemSel ) ;
2014-05-30 12:53:19 +04:00
p . restore ( ) ;
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
if ( width > _maxw ) {
left + = ( width - _maxw ) / 2 ;
width = _maxw ;
}
2015-05-20 22:28:24 +03:00
App : : roundRect ( p , left , st : : msgServiceMargin . top ( ) , width , height , App : : msgServiceBg ( ) , ( selection = = FullItemSel ) ? ServiceSelectedCorners : ServiceCorners ) ;
2014-05-30 12:53:19 +04:00
p . setBrush ( Qt : : NoBrush ) ;
p . setPen ( st : : msgServiceColor - > p ) ;
p . setFont ( st : : msgServiceFont - > f ) ;
uint16 selectedFrom = ( selection = = FullItemSel ) ? 0 : ( selection > > 16 ) & 0xFFFF ;
uint16 selectedTo = ( selection = = FullItemSel ) ? 0 : selection & 0xFFFF ;
_text . draw ( p , trect . x ( ) , trect . y ( ) , trect . width ( ) , Qt : : AlignCenter , 0 , - 1 , selectedFrom , selectedTo ) ;
textstyleRestore ( ) ;
}
2014-10-10 16:46:20 +04:00
int32 HistoryServiceMsg : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
if ( dontRecountText ) return _height ;
2014-05-30 12:53:19 +04:00
width - = st : : msgServiceMargin . left ( ) + st : : msgServiceMargin . left ( ) ; // two small margins
if ( width < st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) + 1 ) width = st : : msgServicePadding . left ( ) + st : : msgServicePadding . right ( ) + 1 ;
int32 nwidth = qMax ( width - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) , 0 ) ;
if ( nwidth ! = _textWidth ) {
_textWidth = nwidth ;
_textHeight = _text . countHeight ( nwidth ) ;
}
if ( width > = _maxw ) {
_height = _minh ;
} else {
_height = _textHeight ;
}
_height + = st : : msgServicePadding . top ( ) + st : : msgServicePadding . bottom ( ) + st : : msgServiceMargin . top ( ) + st : : msgServiceMargin . bottom ( ) ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
2015-03-19 12:18:19 +03:00
_height + = st : : msgServiceMargin . top ( ) + _media - > resize ( _media - > currentWidth ( ) ) ;
2014-05-30 12:53:19 +04:00
}
return _height ;
}
bool HistoryServiceMsg : : hasPoint ( int32 x , int32 y ) const {
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return false ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
return QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . contains ( x , y ) ;
}
2015-06-27 16:02:00 +03:00
void HistoryServiceMsg : : getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2014-05-30 12:53:19 +04:00
lnk = TextLinkPtr ( ) ;
2015-06-27 16:02:00 +03:00
state = HistoryDefaultCursorState ;
2014-05-30 12:53:19 +04:00
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
if ( trect . contains ( x , y ) ) {
2015-06-27 16:02:00 +03:00
bool inText = false ;
_text . getState ( lnk , inText , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) , Qt : : AlignCenter ) ;
state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState ;
} else if ( _media ) {
_media - > getState ( lnk , state , x - st : : msgServiceMargin . left ( ) - ( width - _media - > maxWidth ( ) ) / 2 , y - st : : msgServiceMargin . top ( ) - height - st : : msgServiceMargin . top ( ) , this ) ;
2014-05-30 12:53:19 +04:00
}
}
void HistoryServiceMsg : : getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0 ;
after = false ;
upon = false ;
int32 left = st : : msgServiceMargin . left ( ) , width = _history - > width - st : : msgServiceMargin . left ( ) - st : : msgServiceMargin . left ( ) , height = _height - st : : msgServiceMargin . top ( ) - st : : msgServiceMargin . bottom ( ) ; // two small margins
if ( width < 1 ) return ;
2014-08-15 15:19:32 +04:00
if ( _media ) {
height - = st : : msgServiceMargin . top ( ) + _media - > height ( ) ;
2014-05-30 12:53:19 +04:00
}
QRect trect ( QRect ( left , st : : msgServiceMargin . top ( ) , width , height ) . marginsAdded ( - st : : msgServicePadding ) ) ;
return _text . getSymbol ( symbol , after , upon , x - trect . x ( ) , y - trect . y ( ) , trect . width ( ) , Qt : : AlignCenter ) ;
}
void HistoryServiceMsg : : drawInDialog ( QPainter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
if ( cacheFor ! = this ) {
cacheFor = this ;
2015-03-19 12:18:19 +03:00
cache . setText ( st : : dlgHistFont , inDialogsText ( ) , _textDlgOptions ) ;
2014-05-30 12:53:19 +04:00
}
QRect tr ( r ) ;
p . setPen ( ( act ? st : : dlgActiveColor : st : : dlgSystemColor ) - > p ) ;
cache . drawElided ( p , tr . left ( ) , tr . top ( ) , tr . width ( ) , tr . height ( ) / st : : dlgHistFont - > height ) ;
}
2014-06-14 23:32:11 +04:00
QString HistoryServiceMsg : : notificationText ( ) const {
QString msg = _text . original ( 0 , 0xFFFF ) ;
if ( msg . size ( ) > 0xFF ) msg = msg . mid ( 0 , 0xFF ) + qsl ( " .. " ) ;
return msg ;
}
2014-08-11 13:03:45 +04:00
HistoryMedia * HistoryServiceMsg : : getMedia ( bool inOverview ) const {
2014-08-15 15:19:32 +04:00
return inOverview ? 0 : _media ;
2014-08-11 13:03:45 +04:00
}
2014-05-30 12:53:19 +04:00
HistoryServiceMsg : : ~ HistoryServiceMsg ( ) {
2014-08-15 15:19:32 +04:00
delete _media ;
2014-05-30 12:53:19 +04:00
}
HistoryDateMsg : : HistoryDateMsg ( History * history , HistoryBlock * block , const QDate & date ) : HistoryServiceMsg ( history , block , clientMsgId ( ) , QDateTime ( date ) , langDayOfMonth ( date ) ) {
}
HistoryItem * createDayServiceMsg ( History * history , HistoryBlock * block , QDateTime date ) {
return regItem ( new HistoryDateMsg ( history , block , date . date ( ) ) ) ;
}
2015-03-19 12:18:19 +03:00
HistoryUnreadBar : : HistoryUnreadBar ( History * history , HistoryBlock * block , int32 count , const QDateTime & date ) : HistoryItem ( history , block , clientMsgId ( ) , 0 , date , 0 ) , freezed ( false ) {
2014-05-30 12:53:19 +04:00
setCount ( count ) ;
2014-10-10 16:46:20 +04:00
initDimensions ( ) ;
}
void HistoryUnreadBar : : initDimensions ( const HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
_maxw = st : : msgPadding . left ( ) + st : : msgPadding . right ( ) + 1 ;
_minh = st : : unreadBarHeight ;
}
void HistoryUnreadBar : : setCount ( int32 count ) {
if ( ! count ) freezed = true ;
if ( freezed ) return ;
2014-12-18 21:40:49 +03:00
text = lng_unread_bar ( lt_count , count ) ;
2014-05-30 12:53:19 +04:00
}
void HistoryUnreadBar : : draw ( QPainter & p , uint32 selection ) const {
2014-07-13 13:50:38 +04:00
p . fillRect ( 0 , st : : lineWidth , _history - > width , st : : unreadBarHeight - 2 * st : : lineWidth , st : : unreadBarBG - > b ) ;
2014-07-06 07:32:21 +04:00
p . fillRect ( 0 , st : : unreadBarHeight - st : : lineWidth , _history - > width , st : : lineWidth , st : : unreadBarBorder - > b ) ;
2014-05-30 12:53:19 +04:00
p . setFont ( st : : unreadBarFont - > f ) ;
p . setPen ( st : : unreadBarColor - > p ) ;
2014-07-13 13:50:38 +04:00
p . drawText ( QRect ( 0 , 0 , _history - > width , st : : unreadBarHeight - st : : lineWidth ) , text , style : : al_center ) ;
2014-05-30 12:53:19 +04:00
}
2014-10-10 16:46:20 +04:00
int32 HistoryUnreadBar : : resize ( int32 width , bool dontRecountText , const HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
_height = st : : unreadBarHeight ;
return _height ;
}
void HistoryUnreadBar : : drawInDialog ( QPainter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const {
}
2014-06-14 23:32:11 +04:00
QString HistoryUnreadBar : : notificationText ( ) const {
return QString ( ) ;
}