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 .
2015-10-03 16:16:42 +03:00
In addition , as a special exception , the copyright holders give permission
to link the code of portions of this program with the OpenSSL library .
2014-05-30 12:53:19 +04:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2016-02-08 13:56:18 +03:00
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
2014-05-30 12:53:19 +04:00
*/
# pragma once
void historyInit ( ) ;
class HistoryItem ;
2014-10-10 16:46:20 +04:00
2014-08-20 09:32:50 +04:00
typedef QMap < int32 , HistoryItem * > SelectedItemSet ;
2015-04-04 23:01:34 +03:00
# include "structs.h"
2014-12-23 02:11:37 +03:00
2015-09-20 11:55:41 +03:00
enum NewMessageType {
NewMessageUnread ,
NewMessageLast ,
NewMessageExisting ,
} ;
2015-09-19 12:13:21 +03:00
class History ;
2015-12-08 15:33:37 +03:00
class Histories {
2015-09-19 12:13:21 +03:00
public :
typedef QHash < PeerId , History * > Map ;
Map map ;
2014-05-30 12:53:19 +04:00
2015-12-15 18:06:51 +03:00
Histories ( ) : _a_typings ( animation ( this , & Histories : : step_typings ) ) , unreadFull ( 0 ) , unreadMuted ( 0 ) {
2014-05-30 12:53:19 +04:00
}
2015-08-01 11:33:00 +03:00
void regSendAction ( History * history , UserData * user , const MTPSendMessageAction & action ) ;
2015-12-08 15:33:37 +03:00
void step_typings ( uint64 ms , bool timer ) ;
2014-12-12 19:27:03 +03:00
2015-09-19 12:13:21 +03:00
History * find ( const PeerId & peerId ) ;
History * findOrInsert ( const PeerId & peerId , int32 unreadCount , int32 maxInboxRead ) ;
2014-05-30 12:53:19 +04:00
void clear ( ) ;
2014-12-18 21:40:49 +03:00
void remove ( const PeerId & peer ) ;
2014-05-30 12:53:19 +04:00
~ Histories ( ) {
unreadFull = unreadMuted = 0 ;
}
2015-09-21 23:57:42 +03:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
2015-04-04 23:01:34 +03:00
// HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true);
2014-05-30 12:53:19 +04:00
typedef QMap < History * , uint64 > TypingHistories ; // when typing in this history started
TypingHistories typing ;
2015-12-08 15:33:37 +03:00
Animation _a_typings ;
2014-05-30 12:53:19 +04:00
int32 unreadFull , unreadMuted ;
} ;
2015-09-19 12:13:21 +03:00
class HistoryBlock ;
2014-05-30 12:53:19 +04:00
struct DialogRow {
DialogRow ( History * history = 0 , DialogRow * prev = 0 , DialogRow * next = 0 , int32 pos = 0 ) : prev ( prev ) , next ( next ) , history ( history ) , pos ( pos ) , attached ( 0 ) {
}
2015-09-29 16:24:39 +03:00
void paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const ;
2014-05-30 12:53:19 +04:00
DialogRow * prev , * next ;
History * history ;
int32 pos ;
void * attached ; // for any attached data, for example View in contacts list
} ;
2014-07-04 15:12:54 +04:00
struct FakeDialogRow {
FakeDialogRow ( HistoryItem * item ) : _item ( item ) , _cacheFor ( 0 ) , _cache ( st : : dlgRichMinWidth ) {
}
2015-09-29 16:24:39 +03:00
void paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const ;
2014-07-04 15:12:54 +04:00
HistoryItem * _item ;
mutable const HistoryItem * _cacheFor ;
mutable Text _cache ;
} ;
2014-08-15 15:19:32 +04:00
enum HistoryMediaType {
MediaTypePhoto ,
MediaTypeVideo ,
MediaTypeGeo ,
MediaTypeContact ,
2016-02-12 19:35:06 +03:00
MediaTypeFile ,
2015-12-08 22:07:50 +03:00
MediaTypeGif ,
2014-12-23 02:11:37 +03:00
MediaTypeSticker ,
2014-11-12 23:18:00 +03:00
MediaTypeImageLink ,
2015-04-04 23:01:34 +03:00
MediaTypeWebPage ,
2016-02-12 19:35:06 +03:00
MediaTypeMusicFile ,
MediaTypeVoiceFile ,
2014-08-15 15:19:32 +04:00
MediaTypeCount
} ;
enum MediaOverviewType {
2016-02-12 19:35:06 +03:00
OverviewPhotos = 0 ,
OverviewVideos = 1 ,
OverviewMusicFiles = 2 ,
OverviewFiles = 3 ,
OverviewVoiceFiles = 4 ,
OverviewLinks = 5 ,
2014-08-15 15:19:32 +04:00
OverviewCount
} ;
inline MTPMessagesFilter typeToMediaFilter ( MediaOverviewType & type ) {
switch ( type ) {
case OverviewPhotos : return MTP_inputMessagesFilterPhotos ( ) ;
case OverviewVideos : return MTP_inputMessagesFilterVideo ( ) ;
2016-02-12 19:35:06 +03:00
case OverviewMusicFiles : return MTP_inputMessagesFilterMusic ( ) ;
case OverviewFiles : return MTP_inputMessagesFilterDocument ( ) ;
case OverviewVoiceFiles : return MTP_inputMessagesFilterVoice ( ) ;
2015-08-21 14:23:44 +03:00
case OverviewLinks : return MTP_inputMessagesFilterUrl ( ) ;
2014-08-15 15:19:32 +04:00
default : type = OverviewCount ; break ;
}
return MTPMessagesFilter ( ) ;
}
2015-08-01 11:33:00 +03:00
enum SendActionType {
SendActionTyping ,
SendActionRecordVideo ,
SendActionUploadVideo ,
2016-02-12 19:35:06 +03:00
SendActionRecordVoice ,
SendActionUploadVoice ,
2015-08-01 11:33:00 +03:00
SendActionUploadPhoto ,
SendActionUploadFile ,
SendActionChooseLocation ,
SendActionChooseContact ,
} ;
struct SendAction {
SendAction ( SendActionType type , uint64 until , int32 progress = 0 ) : type ( type ) , until ( until ) , progress ( progress ) {
}
SendActionType type ;
uint64 until ;
int32 progress ;
} ;
2016-02-25 13:32:31 +03:00
struct HistoryDraft {
HistoryDraft ( ) : msgId ( 0 ) , previewCancelled ( false ) {
}
HistoryDraft ( const QString & text , MsgId msgId , const MessageCursor & cursor , bool previewCancelled )
: text ( text )
, msgId ( msgId )
, cursor ( cursor )
, previewCancelled ( previewCancelled ) {
}
HistoryDraft ( const FlatTextarea & field , MsgId msgId , bool previewCancelled )
: text ( field . getLastText ( ) )
, msgId ( msgId )
, cursor ( field )
, previewCancelled ( previewCancelled ) {
}
QString text ;
MsgId msgId ; // replyToId for message draft, editMsgId for edit draft
MessageCursor cursor ;
bool previewCancelled ;
} ;
struct HistoryEditDraft : public HistoryDraft {
HistoryEditDraft ( )
: HistoryDraft ( )
, saveRequest ( 0 ) {
}
HistoryEditDraft ( const QString & text , MsgId msgId , const MessageCursor & cursor , bool previewCancelled , mtpRequestId saveRequest = 0 )
: HistoryDraft ( text , msgId , cursor , previewCancelled )
, saveRequest ( saveRequest ) {
}
HistoryEditDraft ( const FlatTextarea & field , MsgId msgId , bool previewCancelled , mtpRequestId saveRequest = 0 )
: HistoryDraft ( field , msgId , previewCancelled )
, saveRequest ( saveRequest ) {
}
mtpRequestId saveRequest ;
} ;
2014-05-30 12:53:19 +04:00
class HistoryMedia ;
class HistoryMessage ;
class HistoryUnreadBar ;
2015-09-19 12:13:21 +03:00
2016-01-03 09:43:42 +08:00
enum AddToOverviewMethod {
AddToOverviewNew , // when new message is added to history
AddToOverviewFront , // when old messages slice was received
AddToOverviewBack , // when new messages slice was received and it is the last one, we index all media
} ;
2015-09-19 12:13:21 +03:00
class ChannelHistory ;
class History {
public :
2014-05-30 12:53:19 +04:00
History ( const PeerId & peerId ) ;
2015-09-03 13:48:40 +03:00
ChannelId channelId ( ) const {
return peerToChannel ( peer - > id ) ;
}
2015-09-19 12:13:21 +03:00
bool isChannel ( ) const {
return peerIsChannel ( peer - > id ) ;
}
2015-11-02 17:33:57 -05:00
bool isMegagroup ( ) const {
return peer - > isMegagroup ( ) ;
}
2015-09-19 12:13:21 +03:00
ChannelHistory * asChannelHistory ( ) ;
const ChannelHistory * asChannelHistory ( ) const ;
2014-05-30 12:53:19 +04:00
2015-09-19 12:13:21 +03:00
bool isEmpty ( ) const {
return blocks . isEmpty ( ) ;
}
2014-07-04 15:12:54 +04:00
void clear ( bool leaveItems = false ) ;
2015-11-13 18:14:33 +03:00
void clearUpto ( MsgId msgId ) ;
2014-05-30 12:53:19 +04:00
void blockResized ( HistoryBlock * block , int32 dh ) ;
void removeBlock ( HistoryBlock * block ) ;
2016-02-25 13:32:31 +03:00
virtual ~ History ( ) ;
2014-05-30 12:53:19 +04:00
2015-12-23 15:55:32 +03:00
HistoryItem * createItem ( HistoryBlock * block , const MTPMessage & msg , bool applyServiceAction ) ;
2016-02-17 19:37:21 +03:00
HistoryItem * createItemForwarded ( HistoryBlock * block , MsgId id , int32 flags , QDateTime date , int32 from , HistoryMessage * msg ) ;
2015-12-31 13:34:43 +08:00
HistoryItem * createItemDocument ( HistoryBlock * block , MsgId id , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ;
HistoryItem * createItemPhoto ( HistoryBlock * block , MsgId id , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ;
2015-01-02 17:55:24 +03:00
2015-09-19 12:13:21 +03:00
HistoryItem * addNewService ( MsgId msgId , QDateTime date , const QString & text , int32 flags = 0 , HistoryMedia * media = 0 , bool newMsg = true ) ;
2015-09-21 23:57:42 +03:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
HistoryItem * addToHistory ( const MTPMessage & msg ) ;
2016-02-17 19:37:21 +03:00
HistoryItem * addNewForwarded ( MsgId id , int32 flags , QDateTime date , int32 from , HistoryMessage * item ) ;
2015-12-31 13:34:43 +08:00
HistoryItem * addNewDocument ( MsgId id , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ;
HistoryItem * addNewPhoto ( MsgId id , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ;
2015-01-02 17:55:24 +03:00
2015-09-19 12:13:21 +03:00
void addOlderSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) ;
void addNewerSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) ;
2016-01-03 09:43:42 +08:00
bool addToOverview ( MediaOverviewType type , MsgId msgId , AddToOverviewMethod method ) ;
void eraseFromOverview ( MediaOverviewType type , MsgId msgId ) ;
2014-07-04 15:12:54 +04:00
void newItemAdded ( HistoryItem * item ) ;
2014-10-22 22:39:03 +04:00
void unregTyping ( UserData * from ) ;
2014-07-04 15:12:54 +04:00
2015-09-06 13:17:09 +03:00
int32 countUnread ( MsgId upTo ) ;
2015-09-19 12:13:21 +03:00
void updateShowFrom ( ) ;
2015-09-06 13:17:09 +03:00
MsgId inboxRead ( MsgId upTo ) ;
MsgId inboxRead ( HistoryItem * wasRead ) ;
MsgId outboxRead ( MsgId upTo ) ;
MsgId outboxRead ( HistoryItem * wasRead ) ;
2014-05-30 12:53:19 +04:00
2015-09-20 11:55:41 +03:00
HistoryItem * lastImportantMessage ( ) const ;
2014-05-30 12:53:19 +04:00
void setUnreadCount ( int32 newUnreadCount , bool psUpdate = true ) ;
void setMute ( bool newMute ) ;
void getNextShowFrom ( HistoryBlock * block , int32 i ) ;
void addUnreadBar ( ) ;
2014-07-04 15:12:54 +04:00
void clearNotifications ( ) ;
bool loadedAtBottom ( ) const ; // last message is in the list
2015-09-13 11:41:27 +03:00
void setNotLoadedAtBottom ( ) ;
2014-07-04 15:12:54 +04:00
bool loadedAtTop ( ) const ; // nothing was added after loading history back
2015-09-19 12:13:21 +03:00
bool isReadyFor ( MsgId msgId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) ; // has messages for showing history at msgId
void getReadyFor ( MsgId msgId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) ;
2014-07-04 15:12:54 +04:00
2015-09-21 23:57:42 +03:00
void setLastMessage ( HistoryItem * msg ) ;
2015-09-06 13:17:09 +03:00
void setPosInDialogsDate ( const QDateTime & date ) ;
2014-07-04 15:12:54 +04:00
void fixLastMessage ( bool wasAtBottom ) ;
MsgId minMsgId ( ) const ;
MsgId maxMsgId ( ) const ;
2015-09-06 13:17:09 +03:00
MsgId msgIdForRead ( ) const ;
2014-05-30 12:53:19 +04:00
2015-12-22 11:01:02 +03:00
int32 geomResize ( int32 newWidth , int32 * ytransform = 0 , const HistoryItem * resizedItem = 0 ) ; // return new size
2014-07-04 15:12:54 +04:00
void removeNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) ) {
for ( NotifyQueue : : iterator i = notifies . begin ( ) , e = notifies . end ( ) ; i ! = e ; + + i ) {
if ( ( * i ) = = item ) {
notifies . erase ( i ) ;
break ;
}
}
}
}
HistoryItem * currentNotification ( ) {
return notifies . isEmpty ( ) ? 0 : notifies . front ( ) ;
}
2015-04-23 18:50:11 +03:00
bool hasNotification ( ) const {
return ! notifies . isEmpty ( ) ;
}
2014-07-04 15:12:54 +04:00
void skipNotification ( ) {
if ( ! notifies . isEmpty ( ) ) {
notifies . pop_front ( ) ;
}
}
2015-03-19 12:18:19 +03:00
void popNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) & & notifies . back ( ) = = item ) notifies . pop_back ( ) ;
}
2014-07-04 15:12:54 +04:00
2015-09-19 12:13:21 +03:00
void paintDialog ( Painter & p , int32 w , bool sel ) const ;
2016-01-05 12:52:40 +08:00
bool updateTyping ( uint64 ms , bool force = false ) ;
2015-09-19 12:13:21 +03:00
void clearLastKeyboard ( ) ;
typedef QList < HistoryBlock * > Blocks ;
Blocks blocks ;
int32 width , height , msgCount , unreadCount ;
int32 inboxReadBefore , outboxReadBefore ;
HistoryItem * showFrom ;
HistoryUnreadBar * unreadBar ;
PeerData * peer ;
bool oldLoaded , newLoaded ;
HistoryItem * lastMsg ;
QDateTime lastMsgDate ;
typedef QList < HistoryItem * > NotifyQueue ;
NotifyQueue notifies ;
2016-02-25 13:32:31 +03:00
HistoryDraft * msgDraft ;
HistoryEditDraft * editDraft ;
HistoryDraft * draft ( ) {
return editDraft ? editDraft : msgDraft ;
}
void setMsgDraft ( HistoryDraft * draft ) {
if ( msgDraft ) delete msgDraft ;
msgDraft = draft ;
}
void setEditDraft ( HistoryEditDraft * draft ) {
if ( editDraft ) delete editDraft ;
editDraft = draft ;
}
2014-05-30 12:53:19 +04:00
int32 lastWidth , lastScrollTop ;
2015-07-17 22:17:37 +03:00
MsgId lastShowAtMsgId ;
2014-05-30 12:53:19 +04:00
bool mute ;
2015-06-17 22:43:03 +03:00
bool lastKeyboardInited , lastKeyboardUsed ;
2015-11-23 18:34:38 +03:00
MsgId lastKeyboardId , lastKeyboardHiddenId ;
2015-06-15 20:19:24 +03:00
PeerId lastKeyboardFrom ;
2014-11-05 20:43:32 +03:00
mtpRequestId sendRequestId ;
2014-05-30 12:53:19 +04:00
mutable const HistoryItem * textCachedFor ; // cache
mutable Text lastItemTextCache ;
typedef QMap < QChar , DialogRow * > DialogLinks ;
DialogLinks dialogs ;
2015-09-06 13:17:09 +03:00
uint64 posInDialogs ; // like ((unixtime) << 32) | (incremented counter)
2014-05-30 12:53:19 +04:00
typedef QMap < UserData * , uint64 > TypingUsers ;
TypingUsers typing ;
2015-08-01 11:33:00 +03:00
typedef QMap < UserData * , SendAction > SendActionUsers ;
SendActionUsers sendActions ;
2014-05-30 12:53:19 +04:00
QString typingStr ;
Text typingText ;
2016-01-05 12:52:40 +08:00
uint32 typingDots ;
2015-08-01 11:33:00 +03:00
QMap < SendActionType , uint64 > mySendActions ;
2014-05-30 12:53:19 +04:00
2014-08-11 13:03:45 +04:00
typedef QList < MsgId > MediaOverview ;
2015-09-19 12:13:21 +03:00
MediaOverview overview [ OverviewCount ] ;
2015-11-18 16:11:56 +03:00
bool overviewCountLoaded ( int32 overviewIndex ) const {
return overviewCountData [ overviewIndex ] > = 0 ;
2015-11-16 19:04:37 +03:00
}
2015-11-18 16:11:56 +03:00
bool overviewLoaded ( int32 overviewIndex ) const {
return overviewCount ( overviewIndex ) = = overview [ overviewIndex ] . size ( ) ;
}
int32 overviewCount ( int32 overviewIndex , int32 defaultValue = - 1 ) const {
int32 result = overviewCountData [ overviewIndex ] , loaded = overview [ overviewIndex ] . size ( ) ;
if ( result < 0 ) return defaultValue ;
if ( result < loaded ) {
if ( result > 0 ) {
const_cast < History * > ( this ) - > overviewCountData [ overviewIndex ] = 0 ;
}
return loaded ;
}
return result ;
}
MsgId overviewMinId ( int32 overviewIndex ) const {
for ( MediaOverviewIds : : const_iterator i = overviewIds [ overviewIndex ] . cbegin ( ) , e = overviewIds [ overviewIndex ] . cend ( ) ; i ! = e ; + + i ) {
if ( i . key ( ) > 0 ) {
return i . key ( ) ;
}
}
return 0 ;
}
void overviewSliceDone ( int32 overviewIndex , const MTPmessages_Messages & result , bool onlyCounts = false ) ;
bool overviewHasMsgId ( int32 overviewIndex , MsgId msgId ) const {
return overviewIds [ overviewIndex ] . constFind ( msgId ) ! = overviewIds [ overviewIndex ] . cend ( ) ;
2015-11-16 19:04:37 +03:00
}
2015-11-18 16:11:56 +03:00
void changeMsgId ( MsgId oldId , MsgId newId ) ;
2015-09-19 12:13:21 +03:00
private :
2014-08-15 15:19:32 +04:00
2015-11-18 16:11:56 +03:00
typedef QMap < MsgId , NullType > MediaOverviewIds ;
MediaOverviewIds overviewIds [ OverviewCount ] ;
int32 overviewCountData [ OverviewCount ] ; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
2015-09-20 11:55:41 +03:00
friend class HistoryBlock ;
friend class ChannelHistory ;
2015-09-19 12:13:21 +03:00
void createInitialDateBlock ( const QDateTime & date ) ;
HistoryItem * addItemAfterPrevToBlock ( HistoryItem * item , HistoryItem * prev , HistoryBlock * block ) ;
HistoryItem * addNewInTheMiddle ( HistoryItem * newItem , int32 blockIndex , int32 itemIndex ) ;
2015-09-20 11:55:41 +03:00
HistoryItem * addNewItem ( HistoryBlock * to , bool newBlock , HistoryItem * adding , bool newMsg ) ;
HistoryItem * addMessageGroupAfterPrevToBlock ( const MTPDmessageGroup & group , HistoryItem * prev , HistoryBlock * block ) ;
HistoryItem * addMessageGroupAfterPrev ( HistoryItem * newItem , HistoryItem * prev ) ;
2015-09-19 12:13:21 +03:00
} ;
class HistoryGroup ;
class HistoryCollapse ;
2015-09-21 23:57:42 +03:00
class HistoryJoined ;
2015-09-19 12:13:21 +03:00
class ChannelHistory : public History {
public :
ChannelHistory ( const PeerId & peer ) ;
void messageDetached ( HistoryItem * msg ) ;
void messageDeleted ( HistoryItem * msg ) ;
void messageWithIdDeleted ( MsgId msgId ) ;
bool isSwitchReadyFor ( MsgId switchId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) ; // has messages for showing history after switching mode at switchId
void getSwitchReadyFor ( MsgId switchId , MsgId & fixInScrollMsgId , int32 & fixInScrollMsgTop ) ;
void insertCollapseItem ( MsgId wasMinId ) ;
2015-09-21 23:57:42 +03:00
void getRangeDifference ( ) ;
void getRangeDifferenceNext ( int32 pts ) ;
void addNewGroup ( const MTPMessageGroup & group ) ;
2015-09-19 12:13:21 +03:00
int32 unreadCountAll ;
bool onlyImportant ( ) const {
return _onlyImportant ;
}
HistoryCollapse * collapse ( ) const {
2015-09-21 23:57:42 +03:00
return _collapseMessage ;
2015-09-19 12:13:21 +03:00
}
2015-09-20 11:55:41 +03:00
void clearOther ( ) {
_otherNewLoaded = true ;
_otherOldLoaded = false ;
_otherList . clear ( ) ;
}
2015-09-21 23:57:42 +03:00
HistoryJoined * insertJoinedMessage ( bool unread ) ;
2015-09-25 10:47:32 +03:00
void checkJoinedMessage ( bool createUnread = false ) ;
2015-09-21 23:57:42 +03:00
const QDateTime & maxReadMessageDate ( ) ;
2015-09-19 12:13:21 +03:00
private :
2015-09-20 11:55:41 +03:00
friend class History ;
HistoryItem * addNewChannelMessage ( const MTPMessage & msg , NewMessageType type ) ;
HistoryItem * addNewToBlocks ( const MTPMessage & msg , NewMessageType type ) ;
void addNewToOther ( HistoryItem * item , NewMessageType type ) ;
2015-09-21 23:57:42 +03:00
void checkMaxReadMessageDate ( ) ;
2015-09-19 12:13:21 +03:00
HistoryGroup * findGroup ( MsgId msgId ) const ;
HistoryBlock * findGroupBlock ( MsgId msgId ) const ;
HistoryGroup * findGroupInOther ( MsgId msgId ) const ;
HistoryItem * findPrevItem ( HistoryItem * item ) const ;
2015-09-21 23:57:42 +03:00
void switchMode ( ) ;
void cleared ( ) ;
2015-09-19 12:13:21 +03:00
bool _onlyImportant ;
2015-09-21 23:57:42 +03:00
QDateTime _maxReadMessageDate ;
2015-09-19 12:13:21 +03:00
typedef QList < HistoryItem * > OtherList ;
OtherList _otherList ;
bool _otherOldLoaded , _otherNewLoaded ;
2015-09-21 23:57:42 +03:00
HistoryCollapse * _collapseMessage ;
HistoryJoined * _joinedMessage ;
2015-09-19 12:13:21 +03:00
2015-09-21 23:57:42 +03:00
MsgId _rangeDifferenceFromId , _rangeDifferenceToId ;
int32 _rangeDifferencePts ;
mtpRequestId _rangeDifferenceRequestId ;
2015-07-03 11:47:16 +03:00
2014-05-30 12:53:19 +04:00
} ;
2015-06-15 20:19:24 +03:00
enum DialogsSortMode {
DialogsSortByDate ,
DialogsSortByName ,
DialogsSortByAdd
} ;
2014-05-30 12:53:19 +04:00
struct DialogsList {
2015-06-15 20:19:24 +03:00
DialogsList ( DialogsSortMode sortMode ) : begin ( & last ) , end ( & last ) , sortMode ( sortMode ) , count ( 0 ) , current ( & last ) {
2014-05-30 12:53:19 +04:00
}
void adjustCurrent ( int32 y , int32 h ) const {
int32 pos = ( y > 0 ) ? ( y / h ) : 0 ;
while ( current - > pos > pos & & current ! = begin ) {
current = current - > prev ;
}
while ( current - > pos + 1 < = pos & & current - > next ! = end ) {
current = current - > next ;
}
}
2015-09-29 16:24:39 +03:00
void paint ( Painter & p , int32 w , int32 hFrom , int32 hTo , PeerData * act , PeerData * sel , bool onlyBackground ) const {
2014-05-30 12:53:19 +04:00
adjustCurrent ( hFrom , st : : dlgHeight ) ;
DialogRow * drawFrom = current ;
p . translate ( 0 , drawFrom - > pos * st : : dlgHeight ) ;
while ( drawFrom ! = end & & drawFrom - > pos * st : : dlgHeight < hTo ) {
2015-11-18 16:11:56 +03:00
bool active = ( drawFrom - > history - > peer = = act ) | | ( drawFrom - > history - > peer - > migrateTo ( ) & & drawFrom - > history - > peer - > migrateTo ( ) = = act ) ;
bool selected = ( drawFrom - > history - > peer = = sel ) ;
drawFrom - > paint ( p , w , active , selected , onlyBackground ) ;
2014-05-30 12:53:19 +04:00
drawFrom = drawFrom - > next ;
p . translate ( 0 , st : : dlgHeight ) ;
}
}
DialogRow * rowAtY ( int32 y , int32 h ) const {
if ( ! count ) return 0 ;
int32 pos = ( y > 0 ) ? ( y / h ) : 0 ;
adjustCurrent ( y , h ) ;
return ( pos = = current - > pos ) ? current : 0 ;
}
2015-09-06 13:17:09 +03:00
DialogRow * addToEnd ( History * history ) {
2014-05-30 12:53:19 +04:00
DialogRow * result = new DialogRow ( history , end - > prev , end , end - > pos ) ;
end - > pos + + ;
if ( begin = = end ) {
begin = current = result ;
} else {
end - > prev - > next = result ;
}
rowByPeer . insert ( history - > peer - > id , result ) ;
+ + count ;
2015-09-06 13:17:09 +03:00
end - > prev = result ;
if ( sortMode = = DialogsSortByDate ) {
adjustByPos ( result ) ;
2014-05-30 12:53:19 +04:00
}
2015-09-06 13:17:09 +03:00
return result ;
2014-05-30 12:53:19 +04:00
}
bool insertBefore ( DialogRow * row , DialogRow * before ) {
if ( row = = before ) return false ;
if ( current = = row ) current = row - > prev ;
DialogRow * updateTill = row - > prev ;
remove ( row ) ;
// insert row
row - > next = before ; // update row
row - > prev = before - > prev ;
row - > next - > prev = row ; // update row->next
if ( row - > prev ) { // update row->prev
row - > prev - > next = row ;
} else {
begin = row ;
}
// update y
for ( DialogRow * n = row ; n ! = updateTill ; n = n - > next ) {
n - > next - > pos + + ;
row - > pos - - ;
}
return true ;
}
bool insertAfter ( DialogRow * row , DialogRow * after ) {
if ( row = = after ) return false ;
if ( current = = row ) current = row - > next ;
DialogRow * updateFrom = row - > next ;
remove ( row ) ;
// insert row
row - > prev = after ; // update row
row - > next = after - > next ;
row - > prev - > next = row ; // update row->prev
row - > next - > prev = row ; // update row->next
// update y
for ( DialogRow * n = updateFrom ; n ! = row ; n = n - > next ) {
n - > pos - - ;
row - > pos + + ;
}
return true ;
}
DialogRow * adjustByName ( const PeerData * peer ) {
2015-06-15 20:19:24 +03:00
if ( sortMode ! = DialogsSortByName ) return 0 ;
2014-05-30 12:53:19 +04:00
RowByPeer : : iterator i = rowByPeer . find ( peer - > id ) ;
if ( i = = rowByPeer . cend ( ) ) return 0 ;
DialogRow * row = i . value ( ) , * change = row ;
while ( change - > prev & & change - > prev - > history - > peer - > name > peer - > name ) {
change = change - > prev ;
}
if ( ! insertBefore ( row , change ) ) {
while ( change - > next ! = end & & change - > next - > history - > peer - > name < peer - > name ) {
change = change - > next ;
}
insertAfter ( row , change ) ;
}
return row ;
}
DialogRow * addByName ( History * history ) {
2015-06-15 20:19:24 +03:00
if ( sortMode ! = DialogsSortByName ) return 0 ;
2014-05-30 12:53:19 +04:00
DialogRow * row = addToEnd ( history ) , * change = row ;
const QString & peerName ( history - > peer - > name ) ;
2015-08-07 15:11:50 +03:00
while ( change - > prev & & change - > prev - > history - > peer - > name . compare ( peerName , Qt : : CaseInsensitive ) > 0 ) {
2014-05-30 12:53:19 +04:00
change = change - > prev ;
}
if ( ! insertBefore ( row , change ) ) {
2015-08-07 15:11:50 +03:00
while ( change - > next ! = end & & change - > next - > history - > peer - > name . compare ( peerName , Qt : : CaseInsensitive ) < 0 ) {
2014-05-30 12:53:19 +04:00
change = change - > next ;
}
insertAfter ( row , change ) ;
}
return row ;
}
void adjustByPos ( DialogRow * row ) {
2015-06-15 20:19:24 +03:00
if ( sortMode ! = DialogsSortByDate ) return ;
2014-05-30 12:53:19 +04:00
DialogRow * change = row ;
2015-09-06 13:17:09 +03:00
if ( change ! = begin & & begin - > history - > posInDialogs < row - > history - > posInDialogs ) {
change = begin ;
} else while ( change - > prev & & change - > prev - > history - > posInDialogs < row - > history - > posInDialogs ) {
2014-05-30 12:53:19 +04:00
change = change - > prev ;
}
if ( ! insertBefore ( row , change ) ) {
2015-09-06 13:17:09 +03:00
if ( change - > next ! = end & & end - > prev - > history - > posInDialogs > row - > history - > posInDialogs ) {
change = end - > prev ;
} else while ( change - > next ! = end & & change - > next - > history - > posInDialogs > row - > history - > posInDialogs ) {
2014-05-30 12:53:19 +04:00
change = change - > next ;
}
insertAfter ( row , change ) ;
}
}
bool del ( const PeerId & peerId , DialogRow * replacedBy = 0 ) ;
void remove ( DialogRow * row ) {
row - > next - > prev = row - > prev ; // update row->next
if ( row - > prev ) { // update row->prev
row - > prev - > next = row - > next ;
} else {
begin = row - > next ;
}
}
void clear ( ) {
while ( begin ! = end ) {
current = begin ;
begin = begin - > next ;
delete current ;
}
current = begin ;
rowByPeer . clear ( ) ;
count = 0 ;
}
~ DialogsList ( ) {
clear ( ) ;
}
DialogRow last ;
DialogRow * begin , * end ;
2015-06-15 20:19:24 +03:00
DialogsSortMode sortMode ;
2014-05-30 12:53:19 +04:00
int32 count ;
typedef QHash < PeerId , DialogRow * > RowByPeer ;
RowByPeer rowByPeer ;
mutable DialogRow * current ; // cache
} ;
struct DialogsIndexed {
2015-06-15 20:19:24 +03:00
DialogsIndexed ( DialogsSortMode sortMode ) : sortMode ( sortMode ) , list ( sortMode ) {
2014-05-30 12:53:19 +04:00
}
History : : DialogLinks addToEnd ( History * history ) {
History : : DialogLinks result ;
DialogsList : : RowByPeer : : const_iterator i = list . rowByPeer . find ( history - > peer - > id ) ;
if ( i ! = list . rowByPeer . cend ( ) ) {
return i . value ( ) - > history - > dialogs ;
}
result . insert ( 0 , list . addToEnd ( history ) ) ;
for ( PeerData : : NameFirstChars : : const_iterator i = history - > peer - > chars . cbegin ( ) , e = history - > peer - > chars . 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
}
result . insert ( * i , j . value ( ) - > addToEnd ( history ) ) ;
}
return result ;
}
DialogRow * addByName ( History * history ) {
DialogsList : : RowByPeer : : const_iterator i = list . rowByPeer . constFind ( history - > peer - > id ) ;
if ( i ! = list . rowByPeer . cend ( ) ) {
return i . value ( ) ;
}
DialogRow * res = list . addByName ( history ) ;
for ( PeerData : : NameFirstChars : : const_iterator i = history - > peer - > chars . cbegin ( ) , e = history - > peer - > chars . 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 ) ;
}
return res ;
}
2015-09-06 13:17:09 +03:00
void adjustByPos ( const History : : DialogLinks & links ) {
2014-05-30 12:53:19 +04:00
for ( History : : DialogLinks : : const_iterator i = links . cbegin ( ) , e = links . cend ( ) ; i ! = e ; + + i ) {
if ( i . key ( ) = = QChar ( 0 ) ) {
2015-09-06 13:17:09 +03:00
list . adjustByPos ( i . value ( ) ) ;
2014-05-30 12:53:19 +04:00
} else {
DialogsIndex : : iterator j = index . find ( i . key ( ) ) ;
if ( j ! = index . cend ( ) ) {
2015-09-06 13:17:09 +03:00
j . value ( ) - > adjustByPos ( i . value ( ) ) ;
2014-05-30 12:53:19 +04:00
}
}
}
}
void peerNameChanged ( PeerData * peer , const PeerData : : Names & oldNames , const PeerData : : NameFirstChars & oldChars ) ;
void del ( const PeerData * peer , DialogRow * replacedBy = 0 ) {
if ( list . del ( peer - > id , replacedBy ) ) {
for ( PeerData : : NameFirstChars : : const_iterator i = peer - > chars . cbegin ( ) , e = peer - > chars . cend ( ) ; i ! = e ; + + i ) {
DialogsIndex : : iterator j = index . find ( * i ) ;
if ( j ! = index . cend ( ) ) {
j . value ( ) - > del ( peer - > id , replacedBy ) ;
}
}
}
}
~ DialogsIndexed ( ) {
clear ( ) ;
}
void clear ( ) ;
2015-06-15 20:19:24 +03:00
DialogsSortMode sortMode ;
2014-05-30 12:53:19 +04:00
DialogsList list ;
typedef QMap < QChar , DialogsList * > DialogsIndex ;
DialogsIndex index ;
} ;
2015-09-19 12:13:21 +03:00
class HistoryBlock {
public :
2014-05-30 12:53:19 +04:00
HistoryBlock ( History * hist ) : y ( 0 ) , height ( 0 ) , history ( hist ) {
}
2015-09-19 12:13:21 +03:00
typedef QVector < HistoryItem * > Items ;
Items items ;
2014-07-04 15:12:54 +04:00
void clear ( bool leaveItems = false ) ;
2014-05-30 12:53:19 +04:00
~ HistoryBlock ( ) {
clear ( ) ;
}
void removeItem ( HistoryItem * item ) ;
2015-12-22 11:01:02 +03:00
int32 geomResize ( int32 newWidth , int32 * ytransform , const HistoryItem * resizedItem ) ; // return new size
2014-05-30 12:53:19 +04:00
int32 y , height ;
History * history ;
} ;
class HistoryElem {
public :
2015-12-20 17:05:07 +03:00
HistoryElem ( ) : _maxw ( 0 ) , _minh ( 0 ) , _height ( 0 ) {
2014-05-30 12:53:19 +04:00
}
int32 maxWidth ( ) const {
return _maxw ;
}
2015-04-04 23:01:34 +03:00
int32 minHeight ( ) const {
return _minh ;
}
2015-12-20 17:05:07 +03:00
int32 height ( ) const {
return _height ;
}
2014-05-30 12:53:19 +04:00
virtual ~ HistoryElem ( ) {
}
protected :
2015-12-20 17:05:07 +03:00
mutable int32 _maxw , _minh , _height ;
2015-12-17 20:31:28 +03:00
HistoryElem & operator = ( const HistoryElem & ) ;
2014-05-30 12:53:19 +04:00
} ;
2015-03-19 12:18:19 +03:00
class HistoryReply ; // dynamic_cast optimize
2015-04-13 09:58:13 +01:00
class HistoryMessage ; // dynamic_cast optimize
2015-03-19 12:18:19 +03:00
2015-06-27 16:02:00 +03:00
enum HistoryCursorState {
HistoryDefaultCursorState ,
HistoryInTextCursorState ,
2016-02-19 14:53:49 +03:00
HistoryInDateCursorState ,
HistoryInForwardedCursorState ,
2015-06-27 16:02:00 +03:00
} ;
2015-09-15 11:50:54 +03:00
enum InfoDisplayType {
InfoDisplayDefault ,
InfoDisplayOverImage ,
} ;
2015-09-21 23:57:42 +03:00
inline bool isImportantChannelMessage ( MsgId id , int32 flags ) { // client-side important msgs always has_views or has_from_id
2016-02-17 19:37:21 +03:00
return ( flags & MTPDmessage : : flag_out ) | | ( flags & MTPDmessage : : flag_mentioned ) | | ( flags & MTPDmessage : : flag_post ) ;
2015-09-19 12:13:21 +03:00
}
enum HistoryItemType {
HistoryItemMsg = 0 ,
HistoryItemDate ,
HistoryItemUnreadBar ,
HistoryItemGroup ,
2015-09-21 23:57:42 +03:00
HistoryItemCollapse ,
HistoryItemJoined
2015-09-19 12:13:21 +03:00
} ;
2016-02-18 22:12:50 +03:00
struct HistoryMessageVia : public BasicInterface < HistoryMessageVia > {
HistoryMessageVia ( Interfaces * ) ;
void create ( int32 userId ) ;
void resize ( int32 availw ) const ;
UserData * _bot ;
mutable QString _text ;
mutable int32 _width , _maxWidth ;
TextLinkPtr _lnk ;
} ;
struct HistoryMessageViews : public BasicInterface < HistoryMessageViews > {
HistoryMessageViews ( Interfaces * ) ;
QString _viewsText ;
int32 _views , _viewsWidth ;
} ;
struct HistoryMessageSigned : public BasicInterface < HistoryMessageSigned > {
HistoryMessageSigned ( Interfaces * ) ;
void create ( UserData * from , const QDateTime & date ) ;
int32 maxWidth ( ) const ;
Text _signature ;
} ;
struct HistoryMessageForwarded : public BasicInterface < HistoryMessageForwarded > {
HistoryMessageForwarded ( Interfaces * ) ;
2016-02-19 14:53:49 +03:00
void create ( const HistoryMessageVia * via ) const ;
2016-02-18 22:12:50 +03:00
bool display ( bool hasVia ) const ;
PeerData * _authorOriginal , * _fromOriginal ;
2016-02-19 14:53:49 +03:00
MsgId _originalId ;
mutable Text _text ;
2016-02-18 22:12:50 +03:00
} ;
2014-08-11 13:03:45 +04:00
class HistoryMedia ;
2016-02-18 22:12:50 +03:00
class HistoryItem : public HistoryElem , public Interfaces {
2014-05-30 12:53:19 +04:00
public :
2015-03-19 12:18:19 +03:00
HistoryItem ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime msgDate , int32 from ) ;
2014-05-30 12:53:19 +04:00
2015-09-10 13:30:59 +03:00
virtual void initDimensions ( ) = 0 ;
virtual int32 resize ( int32 width ) = 0 ; // return new height
2015-12-11 21:11:38 +03:00
virtual void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const = 0 ;
2015-09-10 13:30:59 +03:00
2015-12-31 23:27:21 +08:00
virtual UserData * viaBot ( ) const {
return 0 ;
}
2015-12-22 11:01:02 +03:00
History * history ( ) const {
2014-05-30 12:53:19 +04:00
return _history ;
}
2015-09-04 16:01:31 +03:00
PeerData * from ( ) const {
2014-05-30 12:53:19 +04:00
return _from ;
}
HistoryBlock * block ( ) {
return _block ;
}
const HistoryBlock * block ( ) const {
return _block ;
}
2016-01-03 09:43:42 +08:00
virtual void destroy ( ) ;
2014-07-04 15:12:54 +04:00
void detach ( ) ;
void detachFast ( ) ;
bool detached ( ) const {
return ! _block ;
2014-05-30 12:53:19 +04:00
}
2015-05-01 02:05:19 +03:00
void attach ( HistoryBlock * block ) {
_block = block ;
}
2014-05-30 12:53:19 +04:00
bool out ( ) const {
2015-10-28 20:16:52 -04:00
return _flags & MTPDmessage : : flag_out ;
2014-05-30 12:53:19 +04:00
}
bool unread ( ) const {
2015-11-13 18:14:33 +03:00
if ( out ( ) & & id > 0 & & id < _history - > outboxReadBefore ) return false ;
if ( ! out ( ) & & id > 0 ) {
if ( id < _history - > inboxReadBefore ) return false ;
if ( channelId ( ) ! = NoChannel ) return true ; // no unread flag for incoming messages in channels
}
if ( history ( ) - > peer - > isSelf ( ) ) return false ; // messages from myself are always read
if ( out ( ) & & history ( ) - > peer - > migrateTo ( ) ) return false ; // outgoing messages in converted chats are always read
return ( _flags & MTPDmessage : : flag_unread ) ;
2015-03-19 12:18:19 +03:00
}
2015-10-28 20:16:52 -04:00
bool mentionsMe ( ) const {
return _flags & MTPDmessage : : flag_mentioned ;
2014-05-30 12:53:19 +04:00
}
2015-04-30 16:53:36 +03:00
bool isMediaUnread ( ) const {
2015-10-28 20:16:52 -04:00
return ( _flags & MTPDmessage : : flag_media_unread ) & & ( channelId ( ) = = NoChannel ) ;
2015-04-30 16:53:36 +03:00
}
void markMediaRead ( ) {
2015-10-28 20:16:52 -04:00
_flags & = ~ MTPDmessage : : flag_media_unread ;
2015-04-30 16:53:36 +03:00
}
2015-06-15 20:19:24 +03:00
bool hasReplyMarkup ( ) const {
return _flags & MTPDmessage : : flag_reply_markup ;
}
2015-08-21 14:23:44 +03:00
bool hasTextLinks ( ) const {
return _flags & MTPDmessage_flag_HAS_TEXT_LINKS ;
}
2015-11-13 18:14:33 +03:00
bool isGroupMigrate ( ) const {
return _flags & MTPDmessage_flag_IS_GROUP_MIGRATE ;
}
2015-09-21 23:57:42 +03:00
bool hasViews ( ) const {
return _flags & MTPDmessage : : flag_views ;
}
2016-02-17 19:37:21 +03:00
bool isPost ( ) const {
return _flags & MTPDmessage : : flag_post ;
2015-09-13 20:27:29 +03:00
}
2015-09-19 12:13:21 +03:00
bool isImportant ( ) const {
2015-09-21 23:57:42 +03:00
return _history - > isChannel ( ) & & isImportantChannelMessage ( id , _flags ) ;
2015-09-19 12:13:21 +03:00
}
2015-11-02 17:33:57 -05:00
bool indexInOverview ( ) const {
2016-02-17 19:37:21 +03:00
return ( id > 0 ) & & ( ! history ( ) - > isChannel ( ) | | history ( ) - > isMegagroup ( ) | | isPost ( ) ) ;
}
bool isSilent ( ) const {
return _flags & MTPDmessage : : flag_silent ;
}
virtual int32 viewsCount ( ) const {
return hasViews ( ) ? 1 : - 1 ;
2015-11-02 17:33:57 -05:00
}
2014-05-30 12:53:19 +04:00
virtual bool needCheck ( ) const {
2015-10-27 20:29:39 -04:00
return out ( ) | | ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) ;
2014-05-30 12:53:19 +04:00
}
virtual bool hasPoint ( int32 x , int32 y ) const {
return false ;
}
2015-06-27 16:02:00 +03:00
virtual void 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
}
virtual void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const { // from text
upon = hasPoint ( x , y ) ;
symbol = upon ? 0xFFFF : 0 ;
after = false ;
}
virtual uint32 adjustSelection ( uint16 from , uint16 to , TextSelectType type ) const {
return ( from < < 16 ) | to ;
}
2015-12-11 21:11:38 +03:00
virtual void linkOver ( const TextLinkPtr & lnk ) {
}
virtual void linkOut ( const TextLinkPtr & lnk ) {
}
2015-09-19 12:13:21 +03:00
virtual HistoryItemType type ( ) const {
return HistoryItemMsg ;
2014-05-30 12:53:19 +04:00
}
virtual bool serviceMsg ( ) const {
return false ;
}
2016-02-18 19:36:33 +03:00
virtual void updateMedia ( const MTPMessageMedia * media , bool edited = false ) {
2014-05-30 12:53:19 +04:00
}
2016-01-03 09:43:42 +08:00
virtual int32 addToOverview ( AddToOverviewMethod method ) {
return 0 ;
}
2015-12-09 21:06:20 +03:00
virtual bool hasBubble ( ) const {
return false ;
}
2014-05-30 12:53:19 +04:00
virtual QString selectedText ( uint32 selection ) const {
return qsl ( " [-] " ) ;
}
2015-03-19 12:18:19 +03:00
virtual QString inDialogsText ( ) const {
return qsl ( " - " ) ;
}
virtual QString inReplyText ( ) const {
return inDialogsText ( ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
virtual void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const {
2015-09-15 11:50:54 +03:00
}
2016-01-09 15:11:23 +08:00
virtual void setViewsCount ( int32 count , bool reinit = true ) {
2015-09-15 11:50:54 +03:00
}
2015-11-18 16:11:56 +03:00
virtual void setId ( MsgId newId ) ;
2015-12-23 17:18:42 +03:00
virtual void setDate ( const QDateTime & date ) { // for date items
this - > date = date ;
}
2015-09-15 11:50:54 +03:00
virtual void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const = 0 ;
2014-06-14 23:32:11 +04:00
virtual QString notificationHeader ( ) const {
return QString ( ) ;
}
virtual QString notificationText ( ) const = 0 ;
2014-05-30 12:53:19 +04:00
2015-09-21 23:57:42 +03:00
bool canDelete ( ) const {
ChannelData * channel = _history - > peer - > asChannel ( ) ;
2015-11-13 18:14:33 +03:00
if ( ! channel ) return ! ( _flags & MTPDmessage_flag_IS_GROUP_MIGRATE ) ;
2015-09-21 23:57:42 +03:00
if ( id = = 1 ) return false ;
if ( channel - > amCreator ( ) ) return true ;
2016-02-17 19:37:21 +03:00
if ( isPost ( ) ) {
2015-09-21 23:57:42 +03:00
if ( channel - > amEditor ( ) & & out ( ) ) return true ;
return false ;
}
return ( channel - > amEditor ( ) | | channel - > amModerator ( ) | | out ( ) ) ;
}
2016-02-21 15:30:16 +03:00
bool canEdit ( const QDateTime & cur ) const ;
2016-02-25 20:23:42 +03:00
bool hasDirectLink ( ) const {
return id > 0 & & _history - > peer - > isChannel ( ) & & _history - > peer - > asChannel ( ) - > isPublic ( ) ;
}
QString directLink ( ) const {
return hasDirectLink ( ) ? qsl ( " https://telegram.me/ " ) + _history - > peer - > asChannel ( ) - > username + ' / ' + QString : : number ( id ) : QString ( ) ;
}
2016-02-21 15:30:16 +03:00
2015-09-03 13:48:40 +03:00
int32 y ;
MsgId id ;
2014-05-30 12:53:19 +04:00
QDateTime date ;
2015-09-03 13:48:40 +03:00
ChannelId channelId ( ) const {
return _history - > channelId ( ) ;
}
FullMsgId fullId ( ) const {
return FullMsgId ( channelId ( ) , id ) ;
}
2014-08-11 13:03:45 +04:00
virtual HistoryMedia * getMedia ( bool inOverview = false ) const {
return 0 ;
}
2015-10-23 18:06:56 +02:00
virtual void setText ( const QString & text , const EntitiesInText & links ) {
2015-08-24 13:53:04 +03:00
}
2015-10-25 18:08:45 +01:00
virtual QString originalText ( ) const {
return QString ( ) ;
}
virtual EntitiesInText originalEntities ( ) const {
return EntitiesInText ( ) ;
2015-08-28 18:15:56 +03:00
}
2015-09-02 00:33:44 +03:00
virtual bool textHasLinks ( ) {
return false ;
}
2015-09-15 11:50:54 +03:00
virtual int32 infoWidth ( ) const {
return 0 ;
}
virtual int32 timeLeft ( ) const {
return 0 ;
}
virtual int32 timeWidth ( ) const {
return 0 ;
}
virtual bool pointInTime ( int32 right , int32 bottom , int32 x , int32 y , InfoDisplayType type ) const {
return false ;
}
int32 skipBlockWidth ( ) const {
return st : : msgDateSpace + infoWidth ( ) - st : : msgDateDelta . x ( ) ;
}
int32 skipBlockHeight ( ) const {
return st : : msgDateFont - > height - st : : msgDateDelta . y ( ) ;
}
QString skipBlock ( ) const {
return textcmdSkipBlock ( skipBlockWidth ( ) , skipBlockHeight ( ) ) ;
}
2015-04-23 18:50:11 +03:00
virtual HistoryMessage * toHistoryMessage ( ) { // dynamic_cast optimize
2015-03-19 12:18:19 +03:00
return 0 ;
}
2015-04-23 18:50:11 +03:00
virtual const HistoryMessage * toHistoryMessage ( ) const { // dynamic_cast optimize
2015-03-19 12:18:19 +03:00
return 0 ;
}
2015-04-23 18:50:11 +03:00
virtual HistoryReply * toHistoryReply ( ) { // dynamic_cast optimize
return 0 ;
}
virtual const HistoryReply * toHistoryReply ( ) const { // dynamic_cast optimize
2015-04-13 09:58:13 +01:00
return 0 ;
}
2015-03-19 12:18:19 +03:00
2015-12-09 22:09:29 +03:00
bool hasFromName ( ) const {
2016-02-17 19:37:21 +03:00
return ( ! out ( ) | | isPost ( ) ) & & ! history ( ) - > peer - > isUser ( ) ;
}
PeerData * author ( ) const {
return isPost ( ) ? history ( ) - > peer : _from ;
2015-09-13 20:27:29 +03:00
}
2016-02-08 17:54:55 +03:00
bool displayFromPhoto ( ) const ;
2015-09-03 13:48:40 +03:00
2016-02-18 22:12:50 +03:00
PeerData * fromOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _fromOriginal ;
}
2016-02-18 19:36:33 +03:00
return from ( ) ;
}
2016-02-18 22:12:50 +03:00
PeerData * authorOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _authorOriginal ;
}
2016-02-18 19:36:33 +03:00
return author ( ) ;
}
2015-12-29 00:20:04 +03:00
void clipCallback ( ClipReaderNotification notification ) ;
2014-05-30 12:53:19 +04:00
virtual ~ HistoryItem ( ) ;
protected :
2016-02-18 22:12:50 +03:00
HistoryItem ( const HistoryItem & ) ;
HistoryItem & operator = ( const HistoryItem & ) ;
2015-09-04 16:01:31 +03:00
PeerData * _from ;
2014-05-30 12:53:19 +04:00
History * _history ;
HistoryBlock * _block ;
2015-03-19 12:18:19 +03:00
int32 _flags ;
2014-05-30 12:53:19 +04:00
2016-02-17 19:37:21 +03:00
mutable int32 _authorNameVersion ;
2014-05-30 12:53:19 +04:00
} ;
2015-03-19 12:18:19 +03:00
class MessageLink : public ITextLink {
2015-06-27 16:02:00 +03:00
TEXT_LINK_CLASS ( MessageLink )
2015-03-19 12:18:19 +03:00
public :
MessageLink ( PeerId peer , MsgId msgid ) : _peer ( peer ) , _msgid ( msgid ) {
}
2015-12-21 16:14:29 +03:00
MessageLink ( HistoryItem * item ) : _peer ( item - > history ( ) - > peer - > id ) , _msgid ( item - > id ) {
}
2015-03-19 12:18:19 +03:00
void onClick ( Qt : : MouseButton button ) const ;
PeerId peer ( ) const {
return _peer ;
}
MsgId msgid ( ) const {
return _msgid ;
}
private :
PeerId _peer ;
MsgId _msgid ;
} ;
2015-09-19 12:13:21 +03:00
class CommentsLink : public ITextLink {
TEXT_LINK_CLASS ( CommentsLink )
public :
CommentsLink ( HistoryItem * item ) : _item ( item ) {
}
void onClick ( Qt : : MouseButton button ) const ;
2015-12-31 23:27:21 +08:00
2015-09-19 12:13:21 +03:00
private :
HistoryItem * _item ;
} ;
2015-12-23 15:55:32 +03:00
HistoryItem * regItem ( HistoryItem * item ) ;
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
class RadialAnimation {
public :
2015-12-29 00:20:04 +03:00
RadialAnimation ( AnimationCreator creator ) ;
2015-12-11 21:11:38 +03:00
float64 opacity ( ) const {
return _opacity ;
}
bool animating ( ) const {
return _animation . animating ( ) ;
}
void start ( float64 prg ) ;
void update ( float64 prg , bool finished , uint64 ms ) ;
void stop ( ) ;
2015-12-13 01:29:33 +03:00
void step ( uint64 ms ) ;
void step ( ) {
step ( getms ( ) ) ;
}
2015-12-22 15:49:42 +03:00
void draw ( Painter & p , const QRect & inner , int32 thickness , const style : : color & color ) ;
2015-12-11 21:11:38 +03:00
private :
uint64 _firstStart , _lastStart , _lastTime ;
float64 _opacity ;
2015-12-13 01:29:33 +03:00
anim : : ivalue a_arcEnd , a_arcStart ;
2015-12-11 21:11:38 +03:00
Animation _animation ;
} ;
2014-05-30 12:53:19 +04:00
class HistoryMedia : public HistoryElem {
public :
2015-12-19 21:09:24 +03:00
HistoryMedia ( ) : _width ( 0 ) {
2014-11-18 15:41:33 +03:00
}
2015-12-19 21:09:24 +03:00
HistoryMedia ( const HistoryMedia & other ) : _width ( 0 ) {
2015-04-04 23:01:34 +03:00
}
2014-11-18 15:41:33 +03:00
2014-05-30 12:53:19 +04:00
virtual HistoryMediaType type ( ) const = 0 ;
virtual const QString inDialogsText ( ) const = 0 ;
2014-11-22 12:45:04 +03:00
virtual const QString inHistoryText ( ) const = 0 ;
2015-12-19 21:09:24 +03:00
bool hasPoint ( int32 x , int32 y , const HistoryItem * parent ) const {
return ( x > = 0 & & y > = 0 & & x < _width & & y < _height ) ;
}
2015-05-20 22:28:24 +03:00
virtual bool isDisplayed ( ) const {
return true ;
}
2015-09-10 13:30:59 +03:00
virtual void initDimensions ( const HistoryItem * parent ) = 0 ;
virtual int32 resize ( int32 width , const HistoryItem * parent ) { // return new height
2015-12-19 21:09:24 +03:00
_width = qMin ( width , _maxw ) ;
2014-11-18 15:41:33 +03:00
return _height ;
}
2015-12-19 21:09:24 +03:00
virtual void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const = 0 ;
virtual void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const = 0 ;
2015-12-11 21:11:38 +03:00
virtual void linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) {
}
virtual void linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) {
}
2015-12-19 21:09:24 +03:00
2014-05-30 12:53:19 +04:00
virtual bool uploading ( ) const {
return false ;
}
virtual HistoryMedia * clone ( ) const = 0 ;
2015-12-19 00:36:16 +03:00
virtual DocumentData * getDocument ( ) {
return 0 ;
}
2015-12-29 00:20:04 +03:00
virtual ClipReader * getClipReader ( ) {
return 0 ;
}
2015-12-19 00:36:16 +03:00
virtual bool playInline ( HistoryItem * item ) {
return false ;
}
virtual void stopInline ( HistoryItem * item ) {
}
2014-05-30 12:53:19 +04:00
virtual void regItem ( HistoryItem * item ) {
}
virtual void unregItem ( HistoryItem * item ) {
}
2016-01-09 15:11:23 +08:00
virtual void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) {
2014-05-30 12:53:19 +04:00
}
2015-01-05 23:17:33 +03:00
2015-04-11 11:04:10 +01:00
virtual bool isImageLink ( ) const {
return false ;
}
2014-09-30 07:11:09 -07:00
virtual bool animating ( ) const {
return false ;
}
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
virtual bool hasReplyPreview ( ) const {
return false ;
}
virtual ImagePtr replyPreview ( ) {
return ImagePtr ( ) ;
}
2015-10-11 10:37:24 +02:00
virtual QString getCaption ( ) const {
return QString ( ) ;
}
2015-12-08 22:07:50 +03:00
virtual bool needsBubble ( const HistoryItem * parent ) const = 0 ;
2015-12-09 21:06:20 +03:00
virtual bool customInfoLayout ( ) const = 0 ;
2015-12-19 00:36:16 +03:00
virtual QMargins bubbleMargins ( ) const {
return QMargins ( ) ;
}
2015-12-09 22:09:29 +03:00
virtual bool hideFromName ( ) const {
return false ;
}
virtual bool hideForwardedFrom ( ) const {
return false ;
}
2015-03-19 12:18:19 +03:00
2014-11-18 15:41:33 +03:00
int32 currentWidth ( ) const {
2015-12-19 21:09:24 +03:00
return _width ;
2014-11-18 15:41:33 +03:00
}
protected :
2015-12-19 21:09:24 +03:00
int32 _width ;
2014-11-18 15:41:33 +03:00
2014-05-30 12:53:19 +04:00
} ;
2016-01-03 09:43:42 +08:00
inline MediaOverviewType mediaToOverviewType ( HistoryMedia * media ) {
switch ( media - > type ( ) ) {
case MediaTypePhoto : return OverviewPhotos ;
case MediaTypeVideo : return OverviewVideos ;
2016-02-12 19:35:06 +03:00
case MediaTypeFile : return OverviewFiles ;
case MediaTypeMusicFile : return media - > getDocument ( ) - > isMusic ( ) ? OverviewMusicFiles : OverviewFiles ;
case MediaTypeVoiceFile : return OverviewVoiceFiles ;
case MediaTypeGif : return media - > getDocument ( ) - > isGifv ( ) ? OverviewCount : OverviewFiles ;
// case MediaTypeSticker: return OverviewFiles;
2016-01-03 09:43:42 +08:00
}
return OverviewCount ;
}
2015-12-13 01:29:33 +03:00
class HistoryFileMedia : public HistoryMedia {
public :
HistoryFileMedia ( ) ;
void linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) ;
void linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) ;
~ HistoryFileMedia ( ) ;
protected :
TextLinkPtr _openl , _savel , _cancell ;
void setLinks ( ITextLink * openl , ITextLink * savel , ITextLink * cancell ) ;
// >= 0 will contain download / upload string, _statusSize = loaded bytes
// < 0 will contain played string, _statusSize = -(seconds + 1) played
// 0x7FFFFFF0 will contain status for not yet downloaded file
// 0x7FFFFFF1 will contain status for already downloaded file
// 0x7FFFFFF2 will contain status for failed to download / upload file
mutable int32 _statusSize ;
mutable QString _statusText ;
2015-12-13 20:05:32 +03:00
// duration = -1 - no duration, duration = -2 - "GIF" duration
2015-12-13 01:29:33 +03:00
void setStatusSize ( int32 newSize , int32 fullSize , int32 duration , qint64 realDuration ) const ;
void step_thumbOver ( const HistoryItem * parent , float64 ms , bool timer ) ;
void step_radial ( const HistoryItem * parent , uint64 ms , bool timer ) ;
void ensureAnimation ( const HistoryItem * parent ) const ;
void checkAnimationFinished ( ) ;
bool isRadialAnimation ( uint64 ms ) const {
if ( ! _animation | | ! _animation - > radial . animating ( ) ) return false ;
_animation - > radial . step ( ms ) ;
return _animation & & _animation - > radial . animating ( ) ;
}
2015-12-28 00:37:48 +03:00
bool isThumbAnimation ( uint64 ms ) const {
if ( ! _animation | | ! _animation - > _a_thumbOver . animating ( ) ) return false ;
2015-12-31 23:27:21 +08:00
2015-12-28 00:37:48 +03:00
_animation - > _a_thumbOver . step ( ms ) ;
return _animation & & _animation - > _a_thumbOver . animating ( ) ;
}
2015-12-13 01:29:33 +03:00
virtual float64 dataProgress ( ) const = 0 ;
virtual bool dataFinished ( ) const = 0 ;
virtual bool dataLoaded ( ) const = 0 ;
struct AnimationData {
2015-12-29 00:20:04 +03:00
AnimationData ( AnimationCreator thumbOverCallbacks , AnimationCreator radialCallbacks ) : a_thumbOver ( 0 , 0 )
2015-12-13 01:29:33 +03:00
, _a_thumbOver ( thumbOverCallbacks )
2015-12-22 15:49:42 +03:00
, radial ( radialCallbacks ) {
2015-12-13 01:29:33 +03:00
}
anim : : fvalue a_thumbOver ;
Animation _a_thumbOver ;
RadialAnimation radial ;
} ;
mutable AnimationData * _animation ;
2015-12-17 20:31:28 +03:00
private :
HistoryFileMedia ( const HistoryFileMedia & other ) ;
2015-12-13 01:29:33 +03:00
} ;
2015-12-24 22:26:28 +03:00
class HistoryPhoto : public HistoryFileMedia {
public :
2015-12-31 13:34:43 +08:00
HistoryPhoto ( PhotoData * photo , const QString & caption , const HistoryItem * parent ) ;
2015-12-24 22:26:28 +03:00
HistoryPhoto ( PeerData * chat , const MTPDphoto & photo , int32 width = 0 ) ;
HistoryPhoto ( const HistoryPhoto & other ) ;
void init ( ) ;
HistoryMediaType type ( ) const {
return MediaTypePhoto ;
}
HistoryMedia * clone ( ) const {
return new HistoryPhoto ( * this ) ;
}
void initDimensions ( const HistoryItem * parent ) ;
int32 resize ( int32 width , const HistoryItem * parent ) ;
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
const QString inDialogsText ( ) const ;
const QString inHistoryText ( ) const ;
PhotoData * photo ( ) const {
return _data ;
}
2016-01-09 15:11:23 +08:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) ;
2015-12-24 22:26:28 +03:00
2015-12-25 16:09:14 +03:00
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
2015-12-24 22:26:28 +03:00
bool hasReplyPreview ( ) const {
return ! _data - > thumb - > isNull ( ) ;
}
ImagePtr replyPreview ( ) ;
QString getCaption ( ) const {
return _caption . original ( ) ;
}
bool needsBubble ( const HistoryItem * parent ) const {
2016-02-18 22:12:50 +03:00
return ! _caption . isEmpty ( ) | | parent - > Is < HistoryMessageForwarded > ( ) | | parent - > toHistoryReply ( ) | | parent - > viaBot ( ) ;
2015-12-24 22:26:28 +03:00
}
bool customInfoLayout ( ) const {
return _caption . isEmpty ( ) ;
}
bool hideFromName ( ) const {
return true ;
}
protected :
float64 dataProgress ( ) const {
return _data - > progress ( ) ;
}
bool dataFinished ( ) const {
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
}
bool dataLoaded ( ) const {
return _data - > loaded ( ) ;
}
private :
PhotoData * _data ;
int16 _pixw , _pixh ;
Text _caption ;
} ;
2015-12-13 18:21:20 +03:00
class HistoryVideo : public HistoryFileMedia {
public :
2016-02-12 21:18:32 +03:00
HistoryVideo ( DocumentData * document , const QString & caption , HistoryItem * parent ) ;
2015-12-17 20:31:28 +03:00
HistoryVideo ( const HistoryVideo & other ) ;
2015-12-19 21:09:24 +03:00
HistoryMediaType type ( ) const {
return MediaTypeVideo ;
}
HistoryMedia * clone ( ) const {
return new HistoryVideo ( * this ) ;
}
2015-12-17 20:31:28 +03:00
2015-12-13 18:21:20 +03:00
void initDimensions ( const HistoryItem * parent ) ;
2015-12-19 21:09:24 +03:00
int32 resize ( int32 width , const HistoryItem * parent ) ;
2015-12-13 18:21:20 +03:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
2015-12-19 21:09:24 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2015-12-13 18:21:20 +03:00
const QString inDialogsText ( ) const ;
const QString inHistoryText ( ) const ;
2015-12-19 21:09:24 +03:00
2016-02-12 21:18:32 +03:00
DocumentData * getDocument ( ) {
2015-12-19 21:09:24 +03:00
return _data ;
}
2015-12-13 18:21:20 +03:00
bool uploading ( ) const {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2015-12-13 18:21:20 +03:00
}
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
bool hasReplyPreview ( ) const {
return ! _data - > thumb - > isNull ( ) ;
}
ImagePtr replyPreview ( ) ;
bool needsBubble ( const HistoryItem * parent ) const {
2016-02-18 22:12:50 +03:00
return ! _caption . isEmpty ( ) | | parent - > Is < HistoryMessageForwarded > ( ) | | parent - > toHistoryReply ( ) | | parent - > viaBot ( ) ;
2015-12-13 18:21:20 +03:00
}
bool customInfoLayout ( ) const {
return _caption . isEmpty ( ) ;
}
bool hideFromName ( ) const {
return true ;
}
protected :
float64 dataProgress ( ) const {
return _data - > progress ( ) ;
}
bool dataFinished ( ) const {
2015-12-24 22:26:28 +03:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-13 18:21:20 +03:00
}
bool dataLoaded ( ) const {
2015-12-24 22:26:28 +03:00
return _data - > loaded ( ) ;
2015-12-13 18:21:20 +03:00
}
private :
2016-02-12 21:18:32 +03:00
DocumentData * _data ;
int32 _thumbw ;
2015-12-13 18:21:20 +03:00
Text _caption ;
void setStatusSize ( int32 newSize ) const ;
void updateStatusText ( const HistoryItem * parent ) const ;
} ;
2016-02-12 19:35:06 +03:00
struct HistoryDocumentThumbed : public BasicInterface < HistoryDocumentThumbed > {
HistoryDocumentThumbed ( Interfaces * interfaces ) : _thumbw ( 0 ) , _linkw ( 0 ) {
2015-05-29 21:52:43 +03:00
}
2016-02-12 19:35:06 +03:00
TextLinkPtr _linksavel , _linkcancell ;
int32 _thumbw ;
2015-05-29 21:52:43 +03:00
2016-02-12 19:35:06 +03:00
mutable int32 _linkw ;
mutable QString _link ;
} ;
struct HistoryDocumentCaptioned : public BasicInterface < HistoryDocumentCaptioned > {
HistoryDocumentCaptioned ( Interfaces * interfaces ) : _caption ( st : : msgFileMinWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) {
2015-12-08 22:07:50 +03:00
}
2016-02-12 19:35:06 +03:00
Text _caption ;
} ;
struct HistoryDocumentNamed : public BasicInterface < HistoryDocumentNamed > {
HistoryDocumentNamed ( Interfaces * interfaces ) : _namew ( 0 ) {
2015-12-19 00:36:16 +03:00
}
2016-02-12 19:35:06 +03:00
QString _name ;
int32 _namew ;
} ;
class HistoryDocument ;
struct HistoryDocumentVoicePlayback {
HistoryDocumentVoicePlayback ( const HistoryDocument * that ) ;
2015-12-08 22:07:50 +03:00
2016-02-12 19:35:06 +03:00
int32 _position ;
anim : : fvalue a_progress ;
Animation _a_progress ;
} ;
struct HistoryDocumentVoice : public BasicInterface < HistoryDocumentVoice > {
HistoryDocumentVoice ( Interfaces * that ) : _playback ( 0 ) {
2015-12-13 01:29:33 +03:00
}
2016-02-12 19:35:06 +03:00
~ HistoryDocumentVoice ( ) {
deleteAndMark ( _playback ) ;
2015-12-13 01:29:33 +03:00
}
2016-02-12 19:35:06 +03:00
void ensurePlayback ( const HistoryDocument * interfaces ) const ;
void checkPlaybackFinished ( ) const ;
mutable HistoryDocumentVoicePlayback * _playback ;
2014-05-30 12:53:19 +04:00
} ;
2016-02-12 19:35:06 +03:00
class HistoryDocument : public HistoryFileMedia , public Interfaces {
2014-05-30 12:53:19 +04:00
public :
2015-12-28 13:28:00 +03:00
HistoryDocument ( DocumentData * document , const QString & caption , const HistoryItem * parent ) ;
2015-12-17 20:31:28 +03:00
HistoryDocument ( const HistoryDocument & other ) ;
2015-12-19 21:09:24 +03:00
HistoryMediaType type ( ) const {
2016-02-12 19:35:06 +03:00
return _data - > voice ( ) ? MediaTypeVoiceFile : ( _data - > song ( ) ? MediaTypeMusicFile : MediaTypeFile ) ;
2015-12-19 21:09:24 +03:00
}
HistoryMedia * clone ( ) const {
return new HistoryDocument ( * this ) ;
}
2015-12-17 20:31:28 +03:00
2014-08-15 15:19:32 +04:00
void initDimensions ( const HistoryItem * parent ) ;
2015-12-28 13:28:00 +03:00
int32 resize ( int32 width , const HistoryItem * parent ) ;
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
2015-12-19 21:09:24 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2014-05-30 12:53:19 +04:00
const QString inDialogsText ( ) const ;
2014-11-22 12:45:04 +03:00
const QString inHistoryText ( ) const ;
2015-12-19 21:09:24 +03:00
2014-05-30 12:53:19 +04:00
bool uploading ( ) const {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2014-05-30 12:53:19 +04:00
}
2015-12-19 21:09:24 +03:00
2015-12-19 00:36:16 +03:00
DocumentData * getDocument ( ) {
2015-12-08 22:07:50 +03:00
return _data ;
2014-05-30 12:53:19 +04:00
}
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
2016-01-09 15:11:23 +08:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) ;
2014-05-30 12:53:19 +04:00
2015-03-19 12:18:19 +03:00
bool hasReplyPreview ( ) const {
2015-12-08 22:07:50 +03:00
return ! _data - > thumb - > isNull ( ) ;
2015-03-19 12:18:19 +03:00
}
ImagePtr replyPreview ( ) ;
2015-12-28 13:28:00 +03:00
QString getCaption ( ) const {
2016-02-12 19:35:06 +03:00
if ( const HistoryDocumentCaptioned * captioned = Get < HistoryDocumentCaptioned > ( ) ) {
return captioned - > _caption . original ( ) ;
}
return QString ( ) ;
2015-12-28 13:28:00 +03:00
}
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
return true ;
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-08 22:07:50 +03:00
return false ;
}
2015-12-19 00:36:16 +03:00
QMargins bubbleMargins ( ) const {
2016-02-12 19:35:06 +03:00
return Get < HistoryDocumentThumbed > ( ) ? QMargins ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . bottom ( ) ) : st : : msgPadding ;
2015-12-19 00:36:16 +03:00
}
2015-12-09 22:09:29 +03:00
bool hideForwardedFrom ( ) const {
return _data - > song ( ) ;
}
2015-12-08 22:07:50 +03:00
2016-02-12 19:35:06 +03:00
void step_voiceProgress ( float64 ms , bool timer ) ;
2015-12-13 01:29:33 +03:00
protected :
float64 dataProgress ( ) const {
return _data - > progress ( ) ;
}
bool dataFinished ( ) const {
2015-12-24 22:26:28 +03:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-13 01:29:33 +03:00
}
bool dataLoaded ( ) const {
2015-12-23 19:48:44 +03:00
return _data - > loaded ( ) ;
2015-12-13 01:29:33 +03:00
}
2015-12-11 21:11:38 +03:00
2014-05-30 12:53:19 +04:00
private :
2016-02-12 19:35:06 +03:00
void create ( bool caption ) ;
const HistoryItem * _parent ;
2015-12-08 22:07:50 +03:00
DocumentData * _data ;
2015-12-28 13:28:00 +03:00
2015-12-09 21:06:20 +03:00
void setStatusSize ( int32 newSize , qint64 realDuration = 0 ) const ;
bool updateStatusText ( const HistoryItem * parent ) const ; // returns showPause
2015-12-11 21:11:38 +03:00
2015-12-08 22:07:50 +03:00
} ;
2015-12-13 20:05:32 +03:00
class HistoryGif : public HistoryFileMedia {
2015-12-08 22:07:50 +03:00
public :
2015-12-28 13:28:00 +03:00
HistoryGif ( DocumentData * document , const QString & caption , const HistoryItem * parent ) ;
2015-12-17 20:31:28 +03:00
HistoryGif ( const HistoryGif & other ) ;
2015-12-19 21:09:24 +03:00
HistoryMediaType type ( ) const {
return MediaTypeGif ;
}
HistoryMedia * clone ( ) const {
return new HistoryGif ( * this ) ;
}
2015-12-17 20:31:28 +03:00
2015-12-08 22:07:50 +03:00
void initDimensions ( const HistoryItem * parent ) ;
2015-12-19 21:09:24 +03:00
int32 resize ( int32 width , const HistoryItem * parent ) ;
2015-12-08 22:07:50 +03:00
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
2015-12-19 21:09:24 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2015-12-08 22:07:50 +03:00
const QString inDialogsText ( ) const ;
const QString inHistoryText ( ) const ;
2015-12-19 21:09:24 +03:00
2015-12-08 22:07:50 +03:00
bool uploading ( ) const {
2015-12-24 22:26:28 +03:00
return _data - > uploading ( ) ;
2015-12-08 22:07:50 +03:00
}
2015-12-19 00:36:16 +03:00
DocumentData * getDocument ( ) {
2015-12-08 22:07:50 +03:00
return _data ;
}
2015-12-29 00:20:04 +03:00
ClipReader * getClipReader ( ) {
return gif ( ) ;
}
2015-12-19 21:09:24 +03:00
2015-12-19 00:36:16 +03:00
bool playInline ( HistoryItem * item ) ;
void stopInline ( HistoryItem * item ) ;
2015-12-08 22:07:50 +03:00
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
2016-01-09 15:11:23 +08:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) ;
2015-12-08 22:07:50 +03:00
bool hasReplyPreview ( ) const {
return ! _data - > thumb - > isNull ( ) ;
}
ImagePtr replyPreview ( ) ;
2015-12-28 13:28:00 +03:00
QString getCaption ( ) const {
return _caption . original ( ) ;
}
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
2016-02-18 22:12:50 +03:00
return ! _caption . isEmpty ( ) | | parent - > Is < HistoryMessageForwarded > ( ) | | parent - > toHistoryReply ( ) | | parent - > viaBot ( ) ;
2015-12-08 22:07:50 +03:00
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-28 13:28:00 +03:00
return _caption . isEmpty ( ) ;
2015-12-08 22:07:50 +03:00
}
2015-12-13 20:05:32 +03:00
bool hideFromName ( ) const {
return true ;
}
2015-12-15 17:50:51 +03:00
~ HistoryGif ( ) ;
2015-12-13 20:05:32 +03:00
protected :
2015-12-31 23:27:21 +08:00
float64 dataProgress ( ) const ;
bool dataFinished ( ) const ;
bool dataLoaded ( ) const ;
2015-12-08 22:07:50 +03:00
private :
2015-12-31 23:27:21 +08:00
const HistoryItem * _parent ;
2015-12-08 22:07:50 +03:00
DocumentData * _data ;
2015-12-13 20:05:32 +03:00
int32 _thumbw , _thumbh ;
2015-12-28 13:28:00 +03:00
Text _caption ;
2015-12-15 17:50:51 +03:00
ClipReader * _gif ;
2015-12-25 16:10:13 +03:00
ClipReader * gif ( ) {
return ( _gif = = BadClipReader ) ? 0 : _gif ;
}
const ClipReader * gif ( ) const {
return ( _gif = = BadClipReader ) ? 0 : _gif ;
}
2014-05-30 12:53:19 +04:00
2015-12-13 20:05:32 +03:00
void setStatusSize ( int32 newSize ) const ;
void updateStatusText ( const HistoryItem * parent ) const ;
2015-12-08 22:07:50 +03:00
2014-05-30 12:53:19 +04:00
} ;
2014-12-23 02:11:37 +03:00
class HistorySticker : public HistoryMedia {
public :
2015-04-04 23:01:34 +03:00
HistorySticker ( DocumentData * document ) ;
2014-12-23 02:11:37 +03:00
HistoryMediaType type ( ) const {
return MediaTypeSticker ;
}
2015-12-19 21:09:24 +03:00
HistoryMedia * clone ( ) const {
return new HistorySticker ( * this ) ;
}
void initDimensions ( const HistoryItem * parent ) ;
2016-01-03 17:46:30 +08:00
int32 resize ( int32 width , const HistoryItem * parent ) ;
2015-12-19 21:09:24 +03:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2014-12-23 02:11:37 +03:00
const QString inDialogsText ( ) const ;
const QString inHistoryText ( ) const ;
2015-12-23 15:19:32 +03:00
DocumentData * getDocument ( ) {
return _data ;
2014-12-23 02:11:37 +03:00
}
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
2016-01-09 15:11:23 +08:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) ;
2014-12-23 02:11:37 +03:00
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
return false ;
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-08 22:07:50 +03:00
return true ;
}
2014-12-23 02:11:37 +03:00
private :
2015-12-23 15:19:32 +03:00
int16 _pixw , _pixh ;
DocumentData * _data ;
2015-01-05 23:17:33 +03:00
QString _emoji ;
2014-12-23 02:11:37 +03:00
} ;
2015-12-13 01:29:33 +03:00
class SendMessageLink : public PeerLink {
TEXT_LINK_CLASS ( SendMessageLink )
public :
SendMessageLink ( PeerData * peer ) : PeerLink ( peer ) {
}
void onClick ( Qt : : MouseButton button ) const ;
} ;
class AddContactLink : public MessageLink {
TEXT_LINK_CLASS ( AddContactLink )
public :
AddContactLink ( PeerId peer , MsgId msgid ) : MessageLink ( peer , msgid ) {
}
void onClick ( Qt : : MouseButton button ) const ;
} ;
2014-05-30 12:53:19 +04:00
class HistoryContact : public HistoryMedia {
public :
HistoryContact ( int32 userId , const QString & first , const QString & last , const QString & phone ) ;
HistoryMediaType type ( ) const {
return MediaTypeContact ;
}
2015-12-19 21:09:24 +03:00
HistoryMedia * clone ( ) const {
return new HistoryContact ( _userId , _fname , _lname , _phone ) ;
}
void initDimensions ( const HistoryItem * parent ) ;
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2014-05-30 12:53:19 +04:00
const QString inDialogsText ( ) const ;
2014-11-22 12:45:04 +03:00
const QString inHistoryText ( ) const ;
2014-05-30 12:53:19 +04:00
2015-12-13 01:29:33 +03:00
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
2016-01-09 15:11:23 +08:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) ;
2014-08-22 18:55:23 +04:00
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
return true ;
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-08 22:07:50 +03:00
return false ;
}
2015-12-13 01:29:33 +03:00
const QString & fname ( ) const {
return _fname ;
}
const QString & lname ( ) const {
return _lname ;
}
const QString & phone ( ) const {
return _phone ;
}
2014-05-30 12:53:19 +04:00
private :
2015-12-13 01:29:33 +03:00
int32 _userId ;
UserData * _contact ;
int32 _phonew ;
QString _fname , _lname , _phone ;
Text _name ;
TextLinkPtr _linkl ;
int32 _linkw ;
QString _link ;
2014-05-30 12:53:19 +04:00
} ;
2015-04-04 23:01:34 +03:00
class HistoryWebPage : public HistoryMedia {
public :
HistoryWebPage ( WebPageData * data ) ;
2015-12-19 00:36:16 +03:00
HistoryWebPage ( const HistoryWebPage & other ) ;
2015-12-19 21:09:24 +03:00
HistoryMediaType type ( ) const {
return MediaTypeWebPage ;
}
HistoryMedia * clone ( ) const {
return new HistoryWebPage ( * this ) ;
}
2015-04-04 23:01:34 +03:00
void initDimensions ( const HistoryItem * parent ) ;
2015-12-19 21:09:24 +03:00
int32 resize ( int32 width , const HistoryItem * parent ) ;
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
const QString inDialogsText ( ) const ;
const QString inHistoryText ( ) const ;
2015-04-04 23:01:34 +03:00
2015-12-19 00:36:16 +03:00
void linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) ;
void linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) ;
2015-05-20 22:28:24 +03:00
bool isDisplayed ( ) const {
2015-12-19 00:36:16 +03:00
return ! _data - > pendingTill ;
2015-05-20 22:28:24 +03:00
}
2015-12-19 00:36:16 +03:00
DocumentData * getDocument ( ) {
return _attach ? _attach - > getDocument ( ) : 0 ;
}
2016-01-01 09:56:21 +08:00
ClipReader * getClipReader ( ) {
return _attach ? _attach - > getClipReader ( ) : 0 ;
}
2015-12-19 00:36:16 +03:00
bool playInline ( HistoryItem * item ) {
return _attach ? _attach - > playInline ( item ) : false ;
}
void stopInline ( HistoryItem * item ) {
if ( _attach ) _attach - > stopInline ( item ) ;
}
2015-04-04 23:01:34 +03:00
void regItem ( HistoryItem * item ) ;
void unregItem ( HistoryItem * item ) ;
bool hasReplyPreview ( ) const {
2015-12-19 00:36:16 +03:00
return ( _data - > photo & & ! _data - > photo - > thumb - > isNull ( ) ) | | ( _data - > doc & & ! _data - > doc - > thumb - > isNull ( ) ) ;
2015-04-04 23:01:34 +03:00
}
ImagePtr replyPreview ( ) ;
2015-08-28 18:15:56 +03:00
WebPageData * webpage ( ) {
2015-12-19 00:36:16 +03:00
return _data ;
2015-08-28 18:15:56 +03:00
}
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
return true ;
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-08 22:07:50 +03:00
return false ;
}
2015-12-28 00:37:48 +03:00
HistoryMedia * attach ( ) const {
return _attach ;
}
2015-12-31 23:27:21 +08:00
2015-12-28 00:37:48 +03:00
~ HistoryWebPage ( ) ;
2015-04-04 23:01:34 +03:00
private :
2015-12-19 00:36:16 +03:00
WebPageData * _data ;
TextLinkPtr _openl ;
HistoryMedia * _attach ;
2015-04-04 23:01:34 +03:00
bool _asArticle ;
2015-12-19 00:36:16 +03:00
int32 _titleLines , _descriptionLines ;
2015-04-04 23:01:34 +03:00
Text _title , _description ;
int32 _siteNameWidth ;
2015-12-19 00:36:16 +03:00
QString _duration ;
int32 _durationWidth ;
2015-04-04 23:01:34 +03:00
int16 _pixw , _pixh ;
} ;
2015-12-31 23:28:54 +08:00
void initImageLinkManager ( ) ;
void reinitImageLinkManager ( ) ;
void deinitImageLinkManager ( ) ;
enum ImageLinkType {
InvalidImageLink = 0 ,
GoogleMapsLink
} ;
struct ImageLinkData {
ImageLinkData ( const QString & id ) : id ( id ) , type ( InvalidImageLink ) , loading ( false ) {
}
QString id ;
ImagePtr thumb ;
ImageLinkType type ;
bool loading ;
void load ( ) ;
} ;
class ImageLinkManager : public QObject {
Q_OBJECT
public :
ImageLinkManager ( ) : manager ( 0 ) , black ( 0 ) {
}
void init ( ) ;
void reinit ( ) ;
void deinit ( ) ;
void getData ( ImageLinkData * data ) ;
~ ImageLinkManager ( ) {
deinit ( ) ;
}
public slots :
void onFinished ( QNetworkReply * reply ) ;
void onFailed ( QNetworkReply * reply ) ;
private :
void failed ( ImageLinkData * data ) ;
QNetworkAccessManager * manager ;
QMap < QNetworkReply * , ImageLinkData * > dataLoadings , imageLoadings ;
QMap < ImageLinkData * , int32 > serverRedirects ;
ImagePtr * black ;
} ;
2014-11-12 23:18:00 +03:00
class HistoryImageLink : public HistoryMedia {
public :
2015-04-30 16:53:36 +03:00
HistoryImageLink ( const QString & url , const QString & title = QString ( ) , const QString & description = QString ( ) ) ;
2014-11-12 23:18:00 +03:00
HistoryMediaType type ( ) const {
return MediaTypeImageLink ;
}
2015-12-19 21:09:24 +03:00
HistoryMedia * clone ( ) const {
return new HistoryImageLink ( * this ) ;
}
void initDimensions ( const HistoryItem * parent ) ;
int32 resize ( int32 width , const HistoryItem * parent ) ;
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const ;
2014-11-12 23:18:00 +03:00
const QString inDialogsText ( ) const ;
2014-11-22 12:45:04 +03:00
const QString inHistoryText ( ) const ;
2014-11-12 23:18:00 +03:00
2015-04-11 11:04:10 +01:00
bool isImageLink ( ) const {
return true ;
}
2015-12-08 22:07:50 +03:00
bool needsBubble ( const HistoryItem * parent ) const {
2016-02-18 22:12:50 +03:00
return ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) | | parent - > Is < HistoryMessageForwarded > ( ) | | parent - > toHistoryReply ( ) | | parent - > viaBot ( ) ;
2015-12-08 22:07:50 +03:00
}
2015-12-09 21:06:20 +03:00
bool customInfoLayout ( ) const {
2015-12-08 22:07:50 +03:00
return true ;
}
2014-11-12 23:18:00 +03:00
private :
2015-12-19 15:27:03 +03:00
ImageLinkData * _data ;
2015-04-30 16:53:36 +03:00
Text _title , _description ;
2015-12-19 15:27:03 +03:00
TextLinkPtr _link ;
2014-11-18 15:41:33 +03:00
2015-12-19 21:09:24 +03:00
int32 fullWidth ( ) const ;
int32 fullHeight ( ) const ;
2014-11-12 23:18:00 +03:00
} ;
2015-12-31 23:27:21 +08:00
class ViaInlineBotLink : public ITextLink {
TEXT_LINK_CLASS ( ViaInlineBotLink )
public :
ViaInlineBotLink ( UserData * bot ) : _bot ( bot ) {
}
void onClick ( Qt : : MouseButton button ) const ;
private :
UserData * _bot ;
} ;
2016-02-18 22:12:50 +03:00
class HistoryMessage : public HistoryItem {
2014-05-30 12:53:19 +04:00
public :
HistoryMessage ( History * history , HistoryBlock * block , const MTPDmessage & msg ) ;
2016-02-18 22:12:50 +03:00
HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , QDateTime date , int32 from , HistoryMessage * fwd ) ; // local forwarded
HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , int32 viaBotId , QDateTime date , int32 from , const QString & msg , const EntitiesInText & entities ) ; // local message
2015-12-31 13:34:43 +08:00
HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , int32 viaBotId , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ; // local document
HistoryMessage ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , int32 viaBotId , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ; // local photo
2014-05-30 12:53:19 +04:00
2015-04-30 16:53:36 +03:00
void initTime ( ) ;
2015-08-30 17:57:21 +03:00
void initMedia ( const MTPMessageMedia * media , QString & currentText ) ;
2015-12-28 13:28:00 +03:00
void initMediaFromDocument ( DocumentData * doc , const QString & caption ) ;
2015-09-10 13:30:59 +03:00
void initDimensions ( ) ;
2016-01-09 15:11:23 +08:00
void fromNameUpdated ( int32 width ) const ;
2014-05-30 12:53:19 +04:00
2015-12-31 23:27:21 +08:00
virtual UserData * viaBot ( ) const {
2016-02-18 22:12:50 +03:00
if ( const HistoryMessageVia * via = Get < HistoryMessageVia > ( ) ) {
return via - > _bot ;
}
return 0 ;
2015-12-31 13:34:43 +08:00
}
2015-12-09 21:06:20 +03:00
int32 plainMaxWidth ( ) const ;
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2015-12-09 22:09:29 +03:00
bool emptyText ( ) const {
2015-12-08 22:07:50 +03:00
return _text . isEmpty ( ) ;
}
bool drawBubble ( ) const {
2015-12-09 22:09:29 +03:00
return _media ? ( ! emptyText ( ) | | _media - > needsBubble ( this ) ) : true ;
2015-04-04 23:01:34 +03:00
}
2015-12-09 21:06:20 +03:00
bool hasBubble ( ) const {
return drawBubble ( ) ;
}
2015-12-09 22:09:29 +03:00
bool displayFromName ( ) const {
2016-02-18 22:12:50 +03:00
return hasFromName ( ) & & ( ! emptyText ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | toHistoryReply ( ) | | Is < HistoryMessageForwarded > ( ) | | viaBot ( ) | | ! _media - > hideFromName ( ) ) ;
2015-12-09 22:09:29 +03:00
}
2015-12-24 22:26:28 +03:00
bool uploading ( ) const {
return _media & & _media - > uploading ( ) ;
}
2014-05-30 12:53:19 +04:00
2015-12-11 21:11:38 +03:00
void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const ;
2016-01-09 15:11:23 +08:00
void setViewsCount ( int32 count , bool reinit = true ) ;
2015-10-27 20:29:39 -04:00
void setId ( MsgId newId ) ;
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-12-31 23:27:21 +08:00
virtual void drawMessageText ( Painter & p , QRect trect , uint32 selection ) const ;
2014-05-30 12:53:19 +04:00
2016-01-03 09:43:42 +08:00
void destroy ( ) ;
2015-09-10 13:30:59 +03:00
int32 resize ( int32 width ) ;
2014-05-30 12:53:19 +04:00
bool hasPoint ( int32 x , int32 y ) const ;
2015-09-15 11:50:54 +03:00
bool pointInTime ( int32 right , int32 bottom , int32 x , int32 y , InfoDisplayType type ) const ;
2015-05-14 19:50:04 +03:00
2015-06-27 16:02:00 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const ;
virtual void getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const ;
2015-05-14 19:50:04 +03:00
2014-05-30 12:53:19 +04:00
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const ;
uint32 adjustSelection ( uint16 from , uint16 to , TextSelectType type ) const {
return _text . adjustSelection ( from , to , type ) ;
}
2015-12-11 21:11:38 +03:00
void linkOver ( const TextLinkPtr & lnk ) {
if ( _media ) _media - > linkOver ( this , lnk ) ;
}
void linkOut ( const TextLinkPtr & lnk ) {
if ( _media ) _media - > linkOut ( this , lnk ) ;
}
2014-05-30 12:53:19 +04:00
2015-09-15 11:50:54 +03:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const ;
2014-06-14 23:32:11 +04:00
QString notificationHeader ( ) const ;
QString notificationText ( ) const ;
2015-12-31 23:27:21 +08:00
2016-02-18 19:36:33 +03:00
void updateMedia ( const MTPMessageMedia * media , bool edited = false ) {
if ( ! edited & & media & & _media & & _media - > type ( ) ! = MediaTypeWebPage ) {
2016-01-09 15:11:23 +08:00
_media - > updateFrom ( * media , this ) ;
2015-10-01 20:15:23 +03:00
} else {
2016-01-09 15:11:23 +08:00
setMedia ( media ) ;
2015-05-20 22:28:24 +03:00
}
2014-05-30 12:53:19 +04:00
}
2016-01-03 09:43:42 +08:00
int32 addToOverview ( AddToOverviewMethod method ) ;
void eraseFromOverview ( ) ;
2014-05-30 12:53:19 +04:00
QString selectedText ( uint32 selection ) const ;
2015-03-19 12:18:19 +03:00
QString inDialogsText ( ) const ;
2014-08-11 13:03:45 +04:00
HistoryMedia * getMedia ( bool inOverview = false ) const ;
2016-01-09 15:11:23 +08:00
void setMedia ( const MTPMessageMedia * media ) ;
2015-10-23 18:06:56 +02:00
void setText ( const QString & text , const EntitiesInText & entities ) ;
2015-10-25 18:08:45 +01:00
QString originalText ( ) const ;
EntitiesInText originalEntities ( ) const ;
2015-09-02 00:33:44 +03:00
bool textHasLinks ( ) ;
2014-05-30 12:53:19 +04:00
2015-09-15 11:50:54 +03:00
int32 infoWidth ( ) const {
2015-09-13 20:27:29 +03:00
int32 result = _timeWidth ;
2016-02-17 19:37:21 +03:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-27 20:29:39 -04:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 11:50:54 +03:00
}
2016-02-17 19:37:21 +03:00
if ( out ( ) & & ! isPost ( ) ) {
2015-09-15 11:50:54 +03:00
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-13 20:27:29 +03:00
}
return result ;
2014-08-15 15:19:32 +04:00
}
2015-09-15 11:50:54 +03:00
int32 timeLeft ( ) const {
int32 result = 0 ;
2016-02-17 19:37:21 +03:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-27 20:29:39 -04:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 11:50:54 +03:00
}
return result ;
}
int32 timeWidth ( ) const {
return _timeWidth ;
}
2016-02-17 19:37:21 +03:00
int32 viewsCount ( ) const {
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
return views - > _views ;
}
return HistoryItem : : viewsCount ( ) ;
2015-09-15 11:50:54 +03:00
}
2014-08-15 15:19:32 +04:00
2015-04-13 09:58:13 +01:00
HistoryMessage * toHistoryMessage ( ) { // dynamic_cast optimize
return this ;
}
const HistoryMessage * toHistoryMessage ( ) const { // dynamic_cast optimize
return this ;
}
2014-05-30 12:53:19 +04:00
~ HistoryMessage ( ) ;
protected :
2016-02-19 14:53:49 +03:00
void create ( int32 viaBotId , int32 viewsCount , const PeerId & authorIdOriginal = 0 , const PeerId & fromIdOriginal = 0 , MsgId originalId = 0 ) ;
2016-02-18 22:12:50 +03:00
bool displayForwardedFrom ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return Is < HistoryMessageVia > ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | fwd - > _authorOriginal - > isChannel ( ) | | ! _media - > hideForwardedFrom ( ) ;
}
return false ;
}
void paintForwardedInfo ( Painter & p , int32 x , int32 y , int32 w , bool selected ) const ;
2016-02-17 19:37:21 +03:00
2014-05-30 12:53:19 +04:00
Text _text ;
int32 _textWidth , _textHeight ;
2014-08-15 15:19:32 +04:00
HistoryMedia * _media ;
2015-09-15 11:50:54 +03:00
QString _timeText ;
2014-08-15 15:19:32 +04:00
int32 _timeWidth ;
2015-12-31 23:27:21 +08:00
2014-05-30 12:53:19 +04:00
} ;
2015-03-19 12:18:19 +03:00
class HistoryReply : public HistoryMessage {
public :
HistoryReply ( History * history , HistoryBlock * block , const MTPDmessage & msg ) ;
2015-12-31 13:34:43 +08:00
HistoryReply ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ;
HistoryReply ( History * history , HistoryBlock * block , MsgId msgId , int32 flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ;
2015-03-19 12:18:19 +03:00
2015-09-10 13:30:59 +03:00
void initDimensions ( ) ;
2015-04-04 23:01:34 +03:00
2015-03-19 12:18:19 +03:00
bool updateReplyTo ( bool force = false ) ;
void replyToNameUpdated ( ) const ;
int32 replyToWidth ( ) const ;
TextLinkPtr replyToLink ( ) const ;
MsgId replyToId ( ) const ;
HistoryItem * replyToMessage ( ) const ;
void replyToReplaced ( HistoryItem * oldItem , HistoryItem * newItem ) ;
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-09-15 11:50:54 +03:00
void drawReplyTo ( Painter & p , int32 x , int32 y , int32 w , bool selected , bool likeService = false ) const ;
2015-12-31 23:27:21 +08:00
void drawMessageText ( Painter & p , QRect trect , uint32 selection ) const ;
2015-09-10 13:30:59 +03:00
int32 resize ( int32 width ) ;
2016-01-03 17:46:30 +08:00
void resizeVia ( int32 w ) const ;
2015-03-19 12:18:19 +03:00
bool hasPoint ( int32 x , int32 y ) const ;
2015-06-27 16:02:00 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const ;
void getStateFromMessageText ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const QRect & r ) const ;
2015-03-19 12:18:19 +03:00
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const ;
2015-09-04 16:01:31 +03:00
PeerData * replyTo ( ) const {
2016-02-17 19:37:21 +03:00
return replyToMsg ? replyToMsg - > author ( ) : 0 ;
2015-03-19 12:18:19 +03:00
}
QString selectedText ( uint32 selection ) const ;
HistoryReply * toHistoryReply ( ) { // dynamic_cast optimize
return this ;
}
const HistoryReply * toHistoryReply ( ) const { // dynamic_cast optimize
return this ;
}
~ HistoryReply ( ) ;
protected :
MsgId replyToMsgId ;
HistoryItem * replyToMsg ;
TextLinkPtr replyToLnk ;
mutable Text replyToName , replyToText ;
mutable int32 replyToVersion ;
mutable int32 _maxReplyWidth ;
2016-01-03 17:46:30 +08:00
HistoryMessageVia * _replyToVia ;
2015-03-19 12:18:19 +03:00
int32 toWidth ;
} ;
2016-01-11 12:45:07 +08:00
inline int32 newMessageFlags ( PeerData * p ) {
return p - > isSelf ( ) ? 0 : ( ( ( p - > isChat ( ) | | ( p - > isUser ( ) & & ! p - > asUser ( ) - > botInfo ) ) ? MTPDmessage : : flag_unread : 0 ) | MTPDmessage : : flag_out ) ;
}
2016-02-18 22:12:50 +03:00
inline int32 newForwardedFlags ( PeerData * p , int32 from , HistoryMessage * fwd ) {
2016-02-12 19:35:06 +03:00
int32 result = newMessageFlags ( p ) | ( from ? MTPDmessage : : flag_from_id : 0 ) ;
2016-02-18 22:12:50 +03:00
if ( fwd - > Is < HistoryMessageVia > ( ) ) {
2016-02-12 19:35:06 +03:00
result | = MTPDmessage : : flag_via_bot_id ;
}
if ( ! p - > isChannel ( ) ) {
2016-02-18 22:12:50 +03:00
if ( HistoryMedia * media = fwd - > getMedia ( ) ) {
2016-02-12 19:35:06 +03:00
if ( media - > type ( ) = = MediaTypeVoiceFile ) {
result | = MTPDmessage : : flag_media_unread ;
// } else if (media->type() == MediaTypeVideo) {
// result |= MTPDmessage::flag_media_unread;
}
}
}
return result ;
2016-01-11 12:45:07 +08:00
}
2014-05-30 12:53:19 +04:00
class HistoryServiceMsg : public HistoryItem {
public :
HistoryServiceMsg ( History * history , HistoryBlock * block , const MTPDmessageService & msg ) ;
2015-07-15 14:23:59 +03:00
HistoryServiceMsg ( History * history , HistoryBlock * block , MsgId msgId , QDateTime date , const QString & msg , int32 flags = 0 , HistoryMedia * media = 0 , int32 from = 0 ) ;
2014-05-30 12:53:19 +04:00
2015-09-10 13:30:59 +03:00
void initDimensions ( ) ;
2014-10-10 16:46:20 +04:00
2016-02-09 19:05:08 +03:00
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-09-10 13:30:59 +03:00
int32 resize ( int32 width ) ;
2014-05-30 12:53:19 +04:00
bool hasPoint ( int32 x , int32 y ) const ;
2015-06-27 16:02:00 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const ;
2014-05-30 12:53:19 +04:00
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const ;
uint32 adjustSelection ( uint16 from , uint16 to , TextSelectType type ) const {
return _text . adjustSelection ( from , to , type ) ;
}
2015-12-28 00:37:48 +03:00
void linkOver ( const TextLinkPtr & lnk ) {
if ( _media ) _media - > linkOver ( this , lnk ) ;
}
void linkOut ( const TextLinkPtr & lnk ) {
if ( _media ) _media - > linkOut ( this , lnk ) ;
}
2015-09-15 11:50:54 +03:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const ;
2014-06-14 23:32:11 +04:00
QString notificationText ( ) const ;
2014-05-30 12:53:19 +04:00
bool needCheck ( ) const {
return false ;
}
bool serviceMsg ( ) const {
return true ;
}
QString selectedText ( uint32 selection ) const ;
2015-03-19 12:18:19 +03:00
QString inDialogsText ( ) const ;
QString inReplyText ( ) const ;
2014-05-30 12:53:19 +04:00
2014-08-11 13:03:45 +04:00
HistoryMedia * getMedia ( bool inOverview = false ) const ;
2015-09-22 13:19:57 +03:00
void setServiceText ( const QString & text ) ;
2015-09-19 12:13:21 +03:00
2014-05-30 12:53:19 +04:00
~ HistoryServiceMsg ( ) ;
protected :
2014-12-18 21:40:49 +03:00
void setMessageByAction ( const MTPmessageAction & action ) ;
2014-05-30 12:53:19 +04:00
Text _text ;
2014-08-15 15:19:32 +04:00
HistoryMedia * _media ;
2014-05-30 12:53:19 +04:00
int32 _textWidth , _textHeight ;
} ;
class HistoryDateMsg : public HistoryServiceMsg {
public :
HistoryDateMsg ( History * history , HistoryBlock * block , const QDate & date ) ;
2015-06-27 16:02:00 +03:00
void 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
}
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0xFFFF ;
after = false ;
upon = false ;
}
2015-12-23 17:18:42 +03:00
void setDate ( const QDateTime & date ) ;
2014-05-30 12:53:19 +04:00
QString selectedText ( uint32 selection ) const {
return QString ( ) ;
}
2015-09-19 12:13:21 +03:00
HistoryItemType type ( ) const {
return HistoryItemDate ;
}
} ;
class HistoryGroup : public HistoryServiceMsg {
public :
HistoryGroup ( History * history , HistoryBlock * block , const MTPDmessageGroup & group , const QDateTime & date ) ;
2015-09-20 11:55:41 +03:00
HistoryGroup ( History * history , HistoryBlock * block , HistoryItem * newItem , const QDateTime & date ) ;
2015-09-19 12:13:21 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const ;
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0xFFFF ;
after = false ;
upon = false ;
2014-05-30 12:53:19 +04:00
}
2015-09-19 12:13:21 +03:00
QString selectedText ( uint32 selection ) const {
return QString ( ) ;
}
HistoryItemType type ( ) const {
return HistoryItemGroup ;
}
void uniteWith ( MsgId minId , MsgId maxId , int32 count ) ;
2015-09-20 11:55:41 +03:00
void uniteWith ( HistoryItem * item ) {
uniteWith ( item - > id - 1 , item - > id + 1 , 1 ) ;
}
void uniteWith ( HistoryGroup * other ) {
2015-09-19 12:13:21 +03:00
uniteWith ( other - > _minId , other - > _maxId , other - > _count ) ;
}
bool decrementCount ( ) ; // returns true if result count > 0
MsgId minId ( ) const {
return _minId ;
}
MsgId maxId ( ) const {
return _maxId ;
}
private :
MsgId _minId , _maxId ;
int32 _count ;
TextLinkPtr _lnk ;
void updateText ( ) ;
} ;
class HistoryCollapse : public HistoryServiceMsg {
public :
HistoryCollapse ( History * history , HistoryBlock * block , MsgId wasMinId , const QDateTime & date ) ;
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-09-19 12:13:21 +03:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const ;
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const {
symbol = 0xFFFF ;
after = false ;
upon = false ;
}
QString selectedText ( uint32 selection ) const {
return QString ( ) ;
}
HistoryItemType type ( ) const {
return HistoryItemCollapse ;
}
MsgId wasMinId ( ) const {
return _wasMinId ;
}
private :
MsgId _wasMinId ;
2014-05-30 12:53:19 +04:00
} ;
2015-09-21 23:57:42 +03:00
class HistoryJoined : public HistoryServiceMsg {
public :
HistoryJoined ( History * history , HistoryBlock * block , const QDateTime & date , UserData * from , int32 flags ) ;
HistoryItemType type ( ) const {
return HistoryItemJoined ;
}
} ;
2014-05-30 12:53:19 +04:00
HistoryItem * createDayServiceMsg ( History * history , HistoryBlock * block , QDateTime date ) ;
class HistoryUnreadBar : public HistoryItem {
public :
HistoryUnreadBar ( History * history , HistoryBlock * block , int32 count , const QDateTime & date ) ;
2015-09-10 13:30:59 +03:00
void initDimensions ( ) ;
2014-10-10 16:46:20 +04:00
2014-05-30 12:53:19 +04:00
void setCount ( int32 count ) ;
2015-12-11 21:11:38 +03:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-09-10 13:30:59 +03:00
int32 resize ( int32 width ) ;
2014-05-30 12:53:19 +04:00
2015-09-15 11:50:54 +03:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const ;
2014-06-14 23:32:11 +04:00
QString notificationText ( ) const ;
2014-05-30 12:53:19 +04:00
QString selectedText ( uint32 selection ) const {
return QString ( ) ;
}
2015-09-19 12:13:21 +03:00
HistoryItemType type ( ) const {
return HistoryItemUnreadBar ;
2014-05-30 12:53:19 +04:00
}
protected :
QString text ;
bool freezed ;
} ;