2014-05-30 08:53:19 +00:00
/*
This file is part of Telegram Desktop ,
2014-12-01 10:47:38 +00:00
the official desktop version of Telegram messaging app , see https : //telegram.org
2014-05-30 08:53:19 +00: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 13:16:42 +00: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 08:53:19 +00:00
Full license : https : //github.com/telegramdesktop/tdesktop/blob/master/LICENSE
2016-02-08 10:56:18 +00:00
Copyright ( c ) 2014 - 2016 John Preston , https : //desktop.telegram.org
2014-05-30 08:53:19 +00:00
*/
# pragma once
void historyInit ( ) ;
class HistoryItem ;
2014-10-10 12:46:20 +00:00
2014-08-20 05:32:50 +00:00
typedef QMap < int32 , HistoryItem * > SelectedItemSet ;
2015-04-04 20:01:34 +00:00
# include "structs.h"
2014-12-22 23:11:37 +00:00
2015-09-20 08:55:41 +00:00
enum NewMessageType {
NewMessageUnread ,
NewMessageLast ,
NewMessageExisting ,
} ;
2015-09-19 09:13:21 +00:00
class History ;
2015-12-08 12:33:37 +00:00
class Histories {
2015-09-19 09:13:21 +00:00
public :
typedef QHash < PeerId , History * > Map ;
Map map ;
2014-05-30 08:53:19 +00:00
2016-02-28 11:58:30 +00:00
Histories ( ) : _a_typings ( animation ( this , & Histories : : step_typings ) ) , _unreadFull ( 0 ) , _unreadMuted ( 0 ) {
2014-05-30 08:53:19 +00:00
}
2015-08-01 08:33:00 +00:00
void regSendAction ( History * history , UserData * user , const MTPSendMessageAction & action ) ;
2015-12-08 12:33:37 +00:00
void step_typings ( uint64 ms , bool timer ) ;
2014-12-12 16:27:03 +00:00
2015-09-19 09:13:21 +00:00
History * find ( const PeerId & peerId ) ;
History * findOrInsert ( const PeerId & peerId , int32 unreadCount , int32 maxInboxRead ) ;
2014-05-30 08:53:19 +00:00
void clear ( ) ;
2014-12-18 18:40:49 +00:00
void remove ( const PeerId & peer ) ;
2014-05-30 08:53:19 +00:00
~ Histories ( ) {
2016-02-28 11:58:30 +00:00
_unreadFull = _unreadMuted = 0 ;
2014-05-30 08:53:19 +00:00
}
2015-09-21 20:57:42 +00:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
2014-05-30 08:53:19 +00:00
typedef QMap < History * , uint64 > TypingHistories ; // when typing in this history started
TypingHistories typing ;
2015-12-08 12:33:37 +00:00
Animation _a_typings ;
2014-05-30 08:53:19 +00:00
2016-02-28 11:58:30 +00:00
int32 unreadBadge ( ) const {
return _unreadFull - ( cIncludeMuted ( ) ? 0 : _unreadMuted ) ;
}
bool unreadOnlyMuted ( ) const {
return cIncludeMuted ( ) ? ( _unreadMuted > = _unreadFull ) : false ;
}
void unreadIncrement ( int32 count , bool muted ) {
_unreadFull + = count ;
if ( muted ) {
_unreadMuted + = count ;
}
}
void unreadMuteChanged ( int32 count , bool muted ) {
if ( muted ) {
_unreadMuted + = count ;
} else {
_unreadMuted - = count ;
}
}
private :
int32 _unreadFull , _unreadMuted ;
2014-05-30 08:53:19 +00:00
} ;
2015-09-19 09:13:21 +00:00
class HistoryBlock ;
2014-05-30 08:53:19 +00: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 13:24:39 +00:00
void paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const ;
2014-05-30 08:53:19 +00:00
DialogRow * prev , * next ;
History * history ;
int32 pos ;
void * attached ; // for any attached data, for example View in contacts list
} ;
2014-07-04 11:12:54 +00:00
struct FakeDialogRow {
FakeDialogRow ( HistoryItem * item ) : _item ( item ) , _cacheFor ( 0 ) , _cache ( st : : dlgRichMinWidth ) {
}
2015-09-29 13:24:39 +00:00
void paint ( Painter & p , int32 w , bool act , bool sel , bool onlyBackground ) const ;
2014-07-04 11:12:54 +00:00
HistoryItem * _item ;
mutable const HistoryItem * _cacheFor ;
mutable Text _cache ;
} ;
2014-08-15 11:19:32 +00:00
enum HistoryMediaType {
MediaTypePhoto ,
MediaTypeVideo ,
MediaTypeContact ,
2016-02-12 16:35:06 +00:00
MediaTypeFile ,
2015-12-08 19:07:50 +00:00
MediaTypeGif ,
2014-12-22 23:11:37 +00:00
MediaTypeSticker ,
2016-02-28 13:54:04 +00:00
MediaTypeLocation ,
2015-04-04 20:01:34 +00:00
MediaTypeWebPage ,
2016-02-12 16:35:06 +00:00
MediaTypeMusicFile ,
MediaTypeVoiceFile ,
2014-08-15 11:19:32 +00:00
MediaTypeCount
} ;
enum MediaOverviewType {
2016-02-12 16:35:06 +00:00
OverviewPhotos = 0 ,
OverviewVideos = 1 ,
OverviewMusicFiles = 2 ,
OverviewFiles = 3 ,
OverviewVoiceFiles = 4 ,
OverviewLinks = 5 ,
2014-08-15 11:19:32 +00:00
OverviewCount
} ;
inline MTPMessagesFilter typeToMediaFilter ( MediaOverviewType & type ) {
switch ( type ) {
case OverviewPhotos : return MTP_inputMessagesFilterPhotos ( ) ;
case OverviewVideos : return MTP_inputMessagesFilterVideo ( ) ;
2016-02-12 16:35:06 +00:00
case OverviewMusicFiles : return MTP_inputMessagesFilterMusic ( ) ;
case OverviewFiles : return MTP_inputMessagesFilterDocument ( ) ;
case OverviewVoiceFiles : return MTP_inputMessagesFilterVoice ( ) ;
2015-08-21 11:23:44 +00:00
case OverviewLinks : return MTP_inputMessagesFilterUrl ( ) ;
2014-08-15 11:19:32 +00:00
default : type = OverviewCount ; break ;
}
return MTPMessagesFilter ( ) ;
}
2015-08-01 08:33:00 +00:00
enum SendActionType {
SendActionTyping ,
SendActionRecordVideo ,
SendActionUploadVideo ,
2016-02-12 16:35:06 +00:00
SendActionRecordVoice ,
SendActionUploadVoice ,
2015-08-01 08:33:00 +00: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 10:32:31 +00: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 08:53:19 +00:00
class HistoryMedia ;
class HistoryMessage ;
2015-09-19 09:13:21 +00:00
2016-01-03 01:43:42 +00: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
} ;
2016-02-28 11:58:30 +00:00
struct DialogsIndexed ;
2015-09-19 09:13:21 +00:00
class ChannelHistory ;
class History {
public :
2014-05-30 08:53:19 +00:00
History ( const PeerId & peerId ) ;
2016-03-22 09:51:20 +00:00
History ( const History & ) = delete ;
History & operator = ( const History & ) = delete ;
2015-09-03 10:48:40 +00:00
ChannelId channelId ( ) const {
return peerToChannel ( peer - > id ) ;
}
2015-09-19 09:13:21 +00:00
bool isChannel ( ) const {
return peerIsChannel ( peer - > id ) ;
}
2015-11-02 22:33:57 +00:00
bool isMegagroup ( ) const {
return peer - > isMegagroup ( ) ;
}
2015-09-19 09:13:21 +00:00
ChannelHistory * asChannelHistory ( ) ;
const ChannelHistory * asChannelHistory ( ) const ;
2014-05-30 08:53:19 +00:00
2015-09-19 09:13:21 +00:00
bool isEmpty ( ) const {
return blocks . isEmpty ( ) ;
}
2014-07-04 11:12:54 +00:00
void clear ( bool leaveItems = false ) ;
2014-05-30 08:53:19 +00:00
2016-02-25 10:32:31 +00:00
virtual ~ History ( ) ;
2014-05-30 08:53:19 +00:00
2016-03-19 16:55:15 +00:00
HistoryItem * addNewService ( MsgId msgId , QDateTime date , const QString & text , MTPDmessage : : Flags flags = 0 , HistoryMedia * media = 0 , bool newMsg = true ) ;
2015-09-21 20:57:42 +00:00
HistoryItem * addNewMessage ( const MTPMessage & msg , NewMessageType type ) ;
HistoryItem * addToHistory ( const MTPMessage & msg ) ;
2016-03-19 16:55:15 +00:00
HistoryItem * addNewForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * item ) ;
HistoryItem * addNewDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ;
HistoryItem * addNewPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ;
2015-01-02 14:55:24 +00:00
2015-09-19 09:13:21 +00:00
void addOlderSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) ;
void addNewerSlice ( const QVector < MTPMessage > & slice , const QVector < MTPMessageGroup > * collapsed ) ;
2016-01-03 01:43:42 +00:00
bool addToOverview ( MediaOverviewType type , MsgId msgId , AddToOverviewMethod method ) ;
void eraseFromOverview ( MediaOverviewType type , MsgId msgId ) ;
2014-07-04 11:12:54 +00:00
void newItemAdded ( HistoryItem * item ) ;
2014-10-22 18:39:03 +00:00
void unregTyping ( UserData * from ) ;
2014-07-04 11:12:54 +00:00
2016-03-22 15:23:34 +00:00
int countUnread ( MsgId upTo ) ;
2015-09-19 09:13:21 +00:00
void updateShowFrom ( ) ;
2015-09-06 10:17:09 +00:00
MsgId inboxRead ( MsgId upTo ) ;
MsgId inboxRead ( HistoryItem * wasRead ) ;
MsgId outboxRead ( MsgId upTo ) ;
MsgId outboxRead ( HistoryItem * wasRead ) ;
2014-05-30 08:53:19 +00:00
2015-09-20 08:55:41 +00:00
HistoryItem * lastImportantMessage ( ) const ;
2016-03-22 15:23:34 +00:00
void setUnreadCount ( int newUnreadCount , bool psUpdate = true ) ;
2014-05-30 08:53:19 +00:00
void setMute ( bool newMute ) ;
2016-03-22 15:23:34 +00:00
void getNextShowFrom ( HistoryBlock * block , int i ) ;
2014-05-30 08:53:19 +00:00
void addUnreadBar ( ) ;
2016-03-18 19:05:08 +00:00
void destroyUnreadBar ( ) ;
2014-07-04 11:12:54 +00:00
void clearNotifications ( ) ;
bool loadedAtBottom ( ) const ; // last message is in the list
2015-09-13 08:41:27 +00:00
void setNotLoadedAtBottom ( ) ;
2014-07-04 11:12:54 +00:00
bool loadedAtTop ( ) const ; // nothing was added after loading history back
2015-09-19 09:13:21 +00: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 11:12:54 +00:00
2015-09-21 20:57:42 +00:00
void setLastMessage ( HistoryItem * msg ) ;
2014-07-04 11:12:54 +00:00
void fixLastMessage ( bool wasAtBottom ) ;
2016-02-28 11:58:30 +00:00
typedef QMap < QChar , DialogRow * > ChatListLinksMap ;
void setChatsListDate ( const QDateTime & date ) ;
QPair < int32 , int32 > adjustByPosInChatsList ( DialogsIndexed & indexed ) ;
uint64 sortKeyInChatList ( ) const {
return _sortKeyInChatList ;
}
bool inChatList ( ) const {
return ! _chatListLinks . isEmpty ( ) ;
}
int32 posInChatList ( ) const {
2016-03-24 13:27:34 +00:00
return mainChatListLink ( ) - > pos ;
2016-02-28 11:58:30 +00:00
}
DialogRow * addToChatList ( DialogsIndexed & indexed ) ;
void removeFromChatList ( DialogsIndexed & indexed ) ;
void removeChatListEntryByLetter ( QChar letter ) ;
void addChatListEntryByLetter ( QChar letter , DialogRow * row ) ;
void updateChatListEntry ( ) const ;
2014-07-04 11:12:54 +00:00
MsgId minMsgId ( ) const ;
MsgId maxMsgId ( ) const ;
2015-09-06 10:17:09 +00:00
MsgId msgIdForRead ( ) const ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:40:00 +00:00
int resizeGetHeight ( int newWidth ) ;
2014-07-04 11:12:54 +00:00
void removeNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) ) {
2016-03-15 10:37:56 +00:00
for ( auto i = notifies . begin ( ) , e = notifies . end ( ) ; i ! = e ; + + i ) {
2014-07-04 11:12:54 +00:00
if ( ( * i ) = = item ) {
notifies . erase ( i ) ;
break ;
}
}
}
}
HistoryItem * currentNotification ( ) {
return notifies . isEmpty ( ) ? 0 : notifies . front ( ) ;
}
2015-04-23 15:50:11 +00:00
bool hasNotification ( ) const {
return ! notifies . isEmpty ( ) ;
}
2014-07-04 11:12:54 +00:00
void skipNotification ( ) {
if ( ! notifies . isEmpty ( ) ) {
notifies . pop_front ( ) ;
}
}
2015-03-19 09:18:19 +00:00
void popNotification ( HistoryItem * item ) {
if ( ! notifies . isEmpty ( ) & & notifies . back ( ) = = item ) notifies . pop_back ( ) ;
}
2014-07-04 11:12:54 +00:00
2016-03-19 16:55:15 +00:00
bool hasPendingResizedItems ( ) const {
return _flags & Flag : : f_has_pending_resized_items ;
}
void setHasPendingResizedItems ( ) ;
void setPendingResize ( ) {
_flags | = Flag : : f_pending_resize ;
setHasPendingResizedItems ( ) ;
}
2015-09-19 09:13:21 +00:00
void paintDialog ( Painter & p , int32 w , bool sel ) const ;
2016-01-05 04:52:40 +00:00
bool updateTyping ( uint64 ms , bool force = false ) ;
2015-09-19 09:13:21 +00:00
void clearLastKeyboard ( ) ;
2016-03-23 11:47:32 +00:00
// optimization for userpics displayed on the left
// if this returns false there is no need to even try to handle them
bool canHaveFromPhotos ( ) const ;
2015-09-19 09:13:21 +00:00
typedef QList < HistoryBlock * > Blocks ;
Blocks blocks ;
int32 width , height , msgCount , unreadCount ;
int32 inboxReadBefore , outboxReadBefore ;
HistoryItem * showFrom ;
2016-03-18 19:05:08 +00:00
HistoryItem * unreadBar ;
2015-09-19 09:13:21 +00:00
PeerData * peer ;
bool oldLoaded , newLoaded ;
HistoryItem * lastMsg ;
QDateTime lastMsgDate ;
typedef QList < HistoryItem * > NotifyQueue ;
NotifyQueue notifies ;
2016-02-25 10:32:31 +00: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 ;
}
2016-03-21 18:40:00 +00:00
// some fields below are a property of a currently displayed instance of this
// conversation history not a property of the conversation history itself
public :
// we save the last showAtMsgId to restore the state when switching
// between different conversation histories
MsgId showAtMsgId ;
// we save a pointer of the history item at the top of the displayed window
// together with an offset from the window top to the top of this message
// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
HistoryItem * scrollTopItem ;
int scrollTopOffset ;
void forgetScrollState ( ) {
scrollTopItem = nullptr ;
}
// find the correct scrollTopItem and scrollTopOffset using given top
// of the displayed window relative to the history start coord
void countScrollState ( int top ) ;
protected :
// when this item is destroyed scrollTopItem just points to the next one
// and scrollTopOffset remains the same
// if we are at the bottom of the window scrollTopItem == nullptr and
// scrollTopOffset is undefined
void getNextScrollTopItem ( HistoryBlock * block , int32 i ) ;
// helper method for countScrollState(int top)
void countScrollTopItem ( int top ) ;
public :
2014-05-30 08:53:19 +00:00
bool mute ;
2015-06-17 19:43:03 +00:00
bool lastKeyboardInited , lastKeyboardUsed ;
2015-11-23 15:34:38 +00:00
MsgId lastKeyboardId , lastKeyboardHiddenId ;
2015-06-15 17:19:24 +00:00
PeerId lastKeyboardFrom ;
2014-11-05 17:43:32 +00:00
mtpRequestId sendRequestId ;
2014-05-30 08:53:19 +00:00
mutable const HistoryItem * textCachedFor ; // cache
mutable Text lastItemTextCache ;
typedef QMap < UserData * , uint64 > TypingUsers ;
TypingUsers typing ;
2015-08-01 08:33:00 +00:00
typedef QMap < UserData * , SendAction > SendActionUsers ;
SendActionUsers sendActions ;
2014-05-30 08:53:19 +00:00
QString typingStr ;
Text typingText ;
2016-01-05 04:52:40 +00:00
uint32 typingDots ;
2015-08-01 08:33:00 +00:00
QMap < SendActionType , uint64 > mySendActions ;
2014-05-30 08:53:19 +00:00
2014-08-11 09:03:45 +00:00
typedef QList < MsgId > MediaOverview ;
2015-09-19 09:13:21 +00:00
MediaOverview overview [ OverviewCount ] ;
2015-11-18 13:11:56 +00:00
bool overviewCountLoaded ( int32 overviewIndex ) const {
return overviewCountData [ overviewIndex ] > = 0 ;
2015-11-16 16:04:37 +00:00
}
2015-11-18 13:11:56 +00: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 16:04:37 +00:00
}
2015-11-18 13:11:56 +00:00
void changeMsgId ( MsgId oldId , MsgId newId ) ;
2016-03-15 10:37:56 +00:00
protected :
void clearOnDestroy ( ) ;
2016-03-19 18:32:17 +00:00
HistoryItem * addNewToLastBlock ( const MTPMessage & msg , NewMessageType type ) ;
2016-03-15 10:37:56 +00:00
2016-03-31 10:37:58 +00:00
friend class HistoryBlock ;
// this method just removes a block from the blocks list
// when the last item from this block was detached and
// calls the required previousItemChanged()
void removeBlock ( HistoryBlock * block ) ;
void clearBlocks ( bool leaveItems ) ;
HistoryItem * createItem ( const MTPMessage & msg , bool applyServiceAction , bool detachExistingItem ) ;
HistoryItem * createItemForwarded ( MsgId id , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * msg ) ;
HistoryItem * createItemDocument ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ;
HistoryItem * createItemPhoto ( MsgId id , MTPDmessage : : Flags flags , int32 viaBotId , MsgId replyTo , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ;
HistoryItem * addNewItem ( HistoryItem * adding , bool newMsg ) ;
HistoryItem * addNewInTheMiddle ( HistoryItem * newItem , int32 blockIndex , int32 itemIndex ) ;
// All this methods add a new item to the first or last block
// depending on if we are in isBuildingFronBlock() state.
// The last block is created on the go if it is needed.
// If the previous item is a message group the new group is
// not created but is just united with the previous one.
// create(HistoryItem *previous) should return a new HistoryGroup*
// unite(HistoryGroup *existing) should unite a new group with an existing
template < typename CreateGroup , typename UniteGroup >
void addMessageGroup ( CreateGroup create , UniteGroup unite ) ;
void addMessageGroup ( const MTPDmessageGroup & group ) ;
// Adds the item to the back or front block, depending on
// isBuildingFrontBlock(), creating the block if necessary.
void addItemToBlock ( HistoryItem * item ) ;
// Usually all new items are added to the last block.
// Only when we scroll up and add a new slice to the
// front we want to create a new front block.
void startBuildingFrontBlock ( int expectedItemsCount = 1 ) ;
HistoryBlock * finishBuildingFrontBlock ( ) ; // Returns the built block or nullptr if nothing was added.
bool isBuildingFrontBlock ( ) const {
return ! _buildingFrontBlock . isNull ( ) ;
}
2015-09-19 09:13:21 +00:00
private :
2014-08-15 11:19:32 +00:00
2016-03-31 10:37:58 +00:00
enum class Flag {
2016-03-19 16:55:15 +00:00
f_has_pending_resized_items = ( 1 < < 0 ) ,
2016-03-31 10:37:58 +00:00
f_pending_resize = ( 1 < < 1 ) ,
2016-03-19 16:55:15 +00:00
} ;
Q_DECLARE_FLAGS ( Flags , Flag ) ;
2016-03-31 10:37:58 +00:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator | ( Flags : : enum_type f1 , Flags : : enum_type f2 ) noexcept {
2016-03-19 16:55:15 +00:00
return QFlags < Flags : : enum_type > ( f1 ) | f2 ;
}
2016-03-31 10:37:58 +00:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator | ( Flags : : enum_type f1 , QFlags < Flags : : enum_type > f2 ) noexcept {
2016-03-19 16:55:15 +00:00
return f2 | f1 ;
}
2016-03-31 10:37:58 +00:00
Q_DECL_CONSTEXPR friend inline QFlags < Flags : : enum_type > operator ~ ( Flags : : enum_type f ) noexcept {
return ~ QFlags < Flags : : enum_type > ( f ) ;
}
2016-03-19 16:55:15 +00:00
Flags _flags ;
2016-02-28 11:58:30 +00:00
ChatListLinksMap _chatListLinks ;
2016-03-24 13:27:34 +00:00
DialogRow * mainChatListLink ( ) const {
auto it = _chatListLinks . constFind ( 0 ) ;
t_assert ( it ! = _chatListLinks . cend ( ) ) ;
return it . value ( ) ;
}
2016-02-28 11:58:30 +00:00
uint64 _sortKeyInChatList ; // like ((unixtime) << 32) | (incremented counter)
2015-11-18 13:11:56 +00:00
typedef QMap < MsgId , NullType > MediaOverviewIds ;
MediaOverviewIds overviewIds [ OverviewCount ] ;
int32 overviewCountData [ OverviewCount ] ; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
2016-03-31 10:37:58 +00:00
// A pointer to the block that is currently being built.
// We hold this pointer so we can destroy it while building
// and then create a new one if it is necessary.
struct BuildingBlock {
int expectedItemsCount = 0 ; // optimization for block->items.reserve() call
HistoryBlock * block = nullptr ;
} ;
UniquePointer < BuildingBlock > _buildingFrontBlock ;
2015-09-19 09:13:21 +00:00
2016-03-31 10:37:58 +00:00
// Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock * prepareBlockForAddingItem ( ) ;
2016-03-22 09:51:20 +00:00
} ;
2015-09-19 09:13:21 +00:00
class HistoryGroup ;
class HistoryCollapse ;
2015-09-21 20:57:42 +00:00
class HistoryJoined ;
2015-09-19 09:13:21 +00: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 20:57:42 +00:00
void getRangeDifference ( ) ;
void getRangeDifferenceNext ( int32 pts ) ;
void addNewGroup ( const MTPMessageGroup & group ) ;
2015-09-19 09:13:21 +00:00
int32 unreadCountAll ;
bool onlyImportant ( ) const {
return _onlyImportant ;
}
HistoryCollapse * collapse ( ) const {
2015-09-21 20:57:42 +00:00
return _collapseMessage ;
2015-09-19 09:13:21 +00:00
}
2015-09-20 08:55:41 +00:00
void clearOther ( ) {
_otherNewLoaded = true ;
_otherOldLoaded = false ;
_otherList . clear ( ) ;
}
2015-09-21 20:57:42 +00:00
HistoryJoined * insertJoinedMessage ( bool unread ) ;
2015-09-25 07:47:32 +00:00
void checkJoinedMessage ( bool createUnread = false ) ;
2015-09-21 20:57:42 +00:00
const QDateTime & maxReadMessageDate ( ) ;
2016-03-15 10:37:56 +00:00
~ ChannelHistory ( ) ;
2015-09-19 09:13:21 +00:00
private :
2015-09-20 08:55:41 +00: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 20:57:42 +00:00
void checkMaxReadMessageDate ( ) ;
2015-09-19 09:13:21 +00:00
HistoryGroup * findGroup ( MsgId msgId ) const ;
HistoryBlock * findGroupBlock ( MsgId msgId ) const ;
HistoryGroup * findGroupInOther ( MsgId msgId ) const ;
HistoryItem * findPrevItem ( HistoryItem * item ) const ;
2015-09-21 20:57:42 +00:00
void switchMode ( ) ;
void cleared ( ) ;
2015-09-19 09:13:21 +00:00
bool _onlyImportant ;
2015-09-21 20:57:42 +00:00
QDateTime _maxReadMessageDate ;
2015-09-19 09:13:21 +00:00
typedef QList < HistoryItem * > OtherList ;
OtherList _otherList ;
bool _otherOldLoaded , _otherNewLoaded ;
2015-09-21 20:57:42 +00:00
HistoryCollapse * _collapseMessage ;
HistoryJoined * _joinedMessage ;
2015-09-19 09:13:21 +00:00
2015-09-21 20:57:42 +00:00
MsgId _rangeDifferenceFromId , _rangeDifferenceToId ;
int32 _rangeDifferencePts ;
mtpRequestId _rangeDifferenceRequestId ;
2015-07-03 08:47:16 +00:00
2014-05-30 08:53:19 +00:00
} ;
2015-06-15 17:19:24 +00:00
enum DialogsSortMode {
DialogsSortByDate ,
DialogsSortByName ,
DialogsSortByAdd
} ;
2014-05-30 08:53:19 +00:00
struct DialogsList {
2015-06-15 17:19:24 +00:00
DialogsList ( DialogsSortMode sortMode ) : begin ( & last ) , end ( & last ) , sortMode ( sortMode ) , count ( 0 ) , current ( & last ) {
2014-05-30 08:53:19 +00: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 13:24:39 +00:00
void paint ( Painter & p , int32 w , int32 hFrom , int32 hTo , PeerData * act , PeerData * sel , bool onlyBackground ) const {
2014-05-30 08:53:19 +00: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 13:11:56 +00: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 08:53:19 +00: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 10:17:09 +00:00
DialogRow * addToEnd ( History * history ) {
2014-05-30 08:53:19 +00: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 10:17:09 +00:00
end - > prev = result ;
if ( sortMode = = DialogsSortByDate ) {
adjustByPos ( result ) ;
2014-05-30 08:53:19 +00:00
}
2015-09-06 10:17:09 +00:00
return result ;
2014-05-30 08:53:19 +00: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 17:19:24 +00:00
if ( sortMode ! = DialogsSortByName ) return 0 ;
2014-05-30 08:53:19 +00: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 17:19:24 +00:00
if ( sortMode ! = DialogsSortByName ) return 0 ;
2014-05-30 08:53:19 +00:00
DialogRow * row = addToEnd ( history ) , * change = row ;
const QString & peerName ( history - > peer - > name ) ;
2015-08-07 12:11:50 +00:00
while ( change - > prev & & change - > prev - > history - > peer - > name . compare ( peerName , Qt : : CaseInsensitive ) > 0 ) {
2014-05-30 08:53:19 +00:00
change = change - > prev ;
}
if ( ! insertBefore ( row , change ) ) {
2015-08-07 12:11:50 +00:00
while ( change - > next ! = end & & change - > next - > history - > peer - > name . compare ( peerName , Qt : : CaseInsensitive ) < 0 ) {
2014-05-30 08:53:19 +00:00
change = change - > next ;
}
insertAfter ( row , change ) ;
}
return row ;
}
void adjustByPos ( DialogRow * row ) {
2015-06-15 17:19:24 +00:00
if ( sortMode ! = DialogsSortByDate ) return ;
2014-05-30 08:53:19 +00:00
DialogRow * change = row ;
2016-02-28 11:58:30 +00:00
if ( change ! = begin & & begin - > history - > sortKeyInChatList ( ) < row - > history - > sortKeyInChatList ( ) ) {
2015-09-06 10:17:09 +00:00
change = begin ;
2016-02-28 11:58:30 +00:00
} else while ( change - > prev & & change - > prev - > history - > sortKeyInChatList ( ) < row - > history - > sortKeyInChatList ( ) ) {
2014-05-30 08:53:19 +00:00
change = change - > prev ;
}
if ( ! insertBefore ( row , change ) ) {
2016-02-28 11:58:30 +00:00
if ( change - > next ! = end & & end - > prev - > history - > sortKeyInChatList ( ) > row - > history - > sortKeyInChatList ( ) ) {
2015-09-06 10:17:09 +00:00
change = end - > prev ;
2016-02-28 11:58:30 +00:00
} else while ( change - > next ! = end & & change - > next - > history - > sortKeyInChatList ( ) > row - > history - > sortKeyInChatList ( ) ) {
2014-05-30 08:53:19 +00: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 17:19:24 +00:00
DialogsSortMode sortMode ;
2014-05-30 08:53:19 +00:00
int32 count ;
typedef QHash < PeerId , DialogRow * > RowByPeer ;
RowByPeer rowByPeer ;
mutable DialogRow * current ; // cache
} ;
struct DialogsIndexed {
2015-06-15 17:19:24 +00:00
DialogsIndexed ( DialogsSortMode sortMode ) : sortMode ( sortMode ) , list ( sortMode ) {
2014-05-30 08:53:19 +00:00
}
2016-02-28 11:58:30 +00:00
History : : ChatListLinksMap addToEnd ( History * history ) {
History : : ChatListLinksMap result ;
2014-05-30 08:53:19 +00:00
DialogsList : : RowByPeer : : const_iterator i = list . rowByPeer . find ( history - > peer - > id ) ;
2016-02-28 11:58:30 +00:00
if ( i = = list . rowByPeer . cend ( ) ) {
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 ( ) ) {
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
}
result . insert ( * i , j . value ( ) - > addToEnd ( history ) ) ;
2014-05-30 08:53:19 +00:00
}
}
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 17:19:24 +00:00
j = index . insert ( * i , new DialogsList ( sortMode ) ) ;
2014-05-30 08:53:19 +00:00
}
j . value ( ) - > addByName ( history ) ;
}
return res ;
}
2016-02-28 11:58:30 +00:00
void adjustByPos ( const History : : ChatListLinksMap & links ) {
for ( History : : ChatListLinksMap : : const_iterator i = links . cbegin ( ) , e = links . cend ( ) ; i ! = e ; + + i ) {
2014-05-30 08:53:19 +00:00
if ( i . key ( ) = = QChar ( 0 ) ) {
2015-09-06 10:17:09 +00:00
list . adjustByPos ( i . value ( ) ) ;
2014-05-30 08:53:19 +00:00
} else {
DialogsIndex : : iterator j = index . find ( i . key ( ) ) ;
if ( j ! = index . cend ( ) ) {
2015-09-06 10:17:09 +00:00
j . value ( ) - > adjustByPos ( i . value ( ) ) ;
2014-05-30 08:53:19 +00: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 17:19:24 +00:00
DialogsSortMode sortMode ;
2014-05-30 08:53:19 +00:00
DialogsList list ;
typedef QMap < QChar , DialogsList * > DialogsIndex ;
DialogsIndex index ;
} ;
2015-09-19 09:13:21 +00:00
class HistoryBlock {
public :
2016-03-18 19:05:08 +00:00
HistoryBlock ( History * hist ) : y ( 0 ) , height ( 0 ) , history ( hist ) , _indexInHistory ( - 1 ) {
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
HistoryBlock ( const HistoryBlock & ) = delete ;
HistoryBlock & operator = ( const HistoryBlock & ) = delete ;
2015-09-19 09:13:21 +00:00
typedef QVector < HistoryItem * > Items ;
Items items ;
2014-07-04 11:12:54 +00:00
void clear ( bool leaveItems = false ) ;
2014-05-30 08:53:19 +00:00
~ HistoryBlock ( ) {
clear ( ) ;
}
void removeItem ( HistoryItem * item ) ;
2016-03-21 18:40:00 +00:00
int resizeGetHeight ( int newWidth , bool resizeAllItems ) ;
2014-05-30 08:53:19 +00:00
int32 y , height ;
History * history ;
2016-03-15 10:37:56 +00:00
2016-03-18 19:05:08 +00:00
HistoryBlock * previous ( ) const {
2016-03-21 18:40:00 +00:00
t_assert ( _indexInHistory > = 0 ) ;
2016-03-18 19:05:08 +00:00
return ( _indexInHistory > 0 ) ? history - > blocks . at ( _indexInHistory - 1 ) : nullptr ;
}
2016-03-19 18:32:17 +00:00
void setIndexInHistory ( int index ) {
_indexInHistory = index ;
}
2016-03-21 18:40:00 +00:00
int indexInHistory ( ) const {
t_assert ( _indexInHistory > = 0 ) ;
t_assert ( history - > blocks . at ( _indexInHistory ) = = this ) ;
return _indexInHistory ;
}
2016-03-18 19:05:08 +00:00
protected :
int _indexInHistory ;
2014-05-30 08:53:19 +00:00
} ;
class HistoryElem {
public :
2015-12-20 14:05:07 +00:00
HistoryElem ( ) : _maxw ( 0 ) , _minh ( 0 ) , _height ( 0 ) {
2014-05-30 08:53:19 +00:00
}
int32 maxWidth ( ) const {
return _maxw ;
}
2015-04-04 20:01:34 +00:00
int32 minHeight ( ) const {
return _minh ;
}
2015-12-20 14:05:07 +00:00
int32 height ( ) const {
return _height ;
}
2014-05-30 08:53:19 +00:00
virtual ~ HistoryElem ( ) {
}
protected :
2015-12-20 14:05:07 +00:00
mutable int32 _maxw , _minh , _height ;
2015-12-17 17:31:28 +00:00
HistoryElem & operator = ( const HistoryElem & ) ;
2014-05-30 08:53:19 +00:00
} ;
2015-04-13 08:58:13 +00:00
class HistoryMessage ; // dynamic_cast optimize
2015-03-19 09:18:19 +00:00
2015-06-27 13:02:00 +00:00
enum HistoryCursorState {
HistoryDefaultCursorState ,
HistoryInTextCursorState ,
2016-02-19 11:53:49 +00:00
HistoryInDateCursorState ,
HistoryInForwardedCursorState ,
2015-06-27 13:02:00 +00:00
} ;
2015-09-15 08:50:54 +00:00
enum InfoDisplayType {
InfoDisplayDefault ,
InfoDisplayOverImage ,
2016-03-31 14:06:40 +00:00
InfoDisplayOverBackground ,
2015-09-15 08:50:54 +00:00
} ;
2016-03-19 16:55:15 +00:00
inline bool isImportantChannelMessage ( MsgId id , MTPDmessage : : Flags flags ) { // client-side important msgs always has_views or has_from_id
return ( flags & MTPDmessage : : Flag : : f_out ) | | ( flags & MTPDmessage : : Flag : : f_mentioned ) | | ( flags & MTPDmessage : : Flag : : f_post ) ;
2015-09-19 09:13:21 +00:00
}
enum HistoryItemType {
HistoryItemMsg = 0 ,
HistoryItemGroup ,
2015-09-21 20:57:42 +00:00
HistoryItemCollapse ,
HistoryItemJoined
2015-09-19 09:13:21 +00:00
} ;
2016-03-25 11:29:45 +00:00
struct HistoryMessageVia : public BaseComponent < HistoryMessageVia > {
HistoryMessageVia ( Composer * ) {
}
2016-02-18 19:12:50 +00:00
void create ( int32 userId ) ;
void resize ( int32 availw ) const ;
2016-03-25 11:29:45 +00:00
UserData * _bot = nullptr ;
2016-02-18 19:12:50 +00:00
mutable QString _text ;
2016-03-25 11:29:45 +00:00
mutable int _width = 0 ;
mutable int _maxWidth = 0 ;
2016-02-18 19:12:50 +00:00
TextLinkPtr _lnk ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryMessageViews : public BaseComponent < HistoryMessageViews > {
HistoryMessageViews ( Composer * ) {
}
2016-02-18 19:12:50 +00:00
QString _viewsText ;
2016-03-25 11:29:45 +00:00
int _views = 0 ;
int _viewsWidth = 0 ;
2016-02-18 19:12:50 +00:00
} ;
2016-03-25 11:29:45 +00:00
struct HistoryMessageSigned : public BaseComponent < HistoryMessageSigned > {
HistoryMessageSigned ( Composer * ) {
}
2016-02-18 19:12:50 +00:00
void create ( UserData * from , const QDateTime & date ) ;
2016-03-25 11:29:45 +00:00
int maxWidth ( ) const ;
2016-02-18 19:12:50 +00:00
Text _signature ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryMessageForwarded : public BaseComponent < HistoryMessageForwarded > {
HistoryMessageForwarded ( Composer * ) {
}
2016-02-19 11:53:49 +00:00
void create ( const HistoryMessageVia * via ) const ;
2016-02-18 19:12:50 +00:00
2016-03-25 11:29:45 +00:00
PeerData * _authorOriginal = nullptr ;
PeerData * _fromOriginal = nullptr ;
MsgId _originalId = 0 ;
mutable Text _text = { 1 } ;
} ;
struct HistoryMessageReply : public BaseComponent < HistoryMessageReply > {
HistoryMessageReply ( Composer * ) {
}
HistoryMessageReply & operator = ( HistoryMessageReply & & other ) {
replyToMsgId = other . replyToMsgId ;
std : : swap ( replyToMsg , other . replyToMsg ) ;
2016-03-31 11:18:21 +00:00
replyToLnk = std_ : : move ( other . replyToLnk ) ;
replyToName = std_ : : move ( other . replyToName ) ;
replyToText = std_ : : move ( other . replyToText ) ;
2016-03-25 11:29:45 +00:00
replyToVersion = other . replyToVersion ;
_maxReplyWidth = other . _maxReplyWidth ;
std : : swap ( _replyToVia , other . _replyToVia ) ;
return * this ;
}
~ HistoryMessageReply ( ) {
// clearData() should be called by holder
t_assert ( replyToMsg = = nullptr ) ;
t_assert ( _replyToVia = = nullptr ) ;
}
bool updateData ( HistoryMessage * holder , bool force = false ) ;
void clearData ( HistoryMessage * holder ) ; // must be called before destructor
void checkNameUpdate ( ) const ;
void updateName ( ) const ;
void resize ( int width ) const ;
void itemRemoved ( HistoryMessage * holder , HistoryItem * removed ) ;
enum PaintFlag {
PaintInBubble = 0x01 ,
PaintSelected = 0x02 ,
} ;
Q_DECLARE_FLAGS ( PaintFlags , PaintFlag ) ;
void paint ( Painter & p , const HistoryItem * holder , int x , int y , int w , PaintFlags flags ) const ;
MsgId replyToId ( ) const {
return replyToMsgId ;
}
int replyToWidth ( ) const {
return _maxReplyWidth ;
}
TextLinkPtr replyToLink ( ) const {
return replyToLnk ;
}
MsgId replyToMsgId = 0 ;
HistoryItem * replyToMsg = nullptr ;
TextLinkPtr replyToLnk ;
mutable Text replyToName , replyToText ;
mutable int replyToVersion = 0 ;
mutable int _maxReplyWidth = 0 ;
HistoryMessageVia * _replyToVia = nullptr ;
int toWidth = 0 ;
2016-02-18 19:12:50 +00:00
} ;
2016-03-25 11:29:45 +00:00
Q_DECLARE_OPERATORS_FOR_FLAGS ( HistoryMessageReply : : PaintFlags ) ;
2016-02-18 19:12:50 +00:00
2016-03-10 10:15:21 +00:00
class HistoryDependentItemCallback : public SharedCallback2 < void , ChannelData * , MsgId > {
public :
HistoryDependentItemCallback ( FullMsgId dependent ) : _dependent ( dependent ) {
}
void call ( ChannelData * channel , MsgId msgId ) const override ;
private :
FullMsgId _dependent ;
} ;
2016-03-18 19:05:08 +00:00
// any HistoryItem can have this Interface for
// displaying the day mark above the message
2016-03-25 11:29:45 +00:00
struct HistoryMessageDate : public BaseComponent < HistoryMessageDate > {
HistoryMessageDate ( Composer * ) {
}
2016-03-18 19:05:08 +00:00
void init ( const QDateTime & date ) ;
2016-03-19 16:55:15 +00:00
int height ( ) const ;
void paint ( Painter & p , int y , int w ) const ;
2016-03-18 19:05:08 +00:00
QString _text ;
2016-03-25 11:29:45 +00:00
int _width = 0 ;
2016-03-18 19:05:08 +00:00
} ;
// any HistoryItem can have this Interface for
// displaying the unread messages bar above the message
2016-03-25 11:29:45 +00:00
struct HistoryMessageUnreadBar : public BaseComponent < HistoryMessageUnreadBar > {
HistoryMessageUnreadBar ( Composer * ) {
}
2016-03-18 19:05:08 +00:00
void init ( int count ) ;
2016-03-31 14:06:40 +00:00
static int height ( ) ;
static int marginTop ( ) ;
2016-03-19 16:55:15 +00:00
void paint ( Painter & p , int y , int w ) const ;
2016-03-18 19:05:08 +00:00
QString _text ;
2016-03-25 11:29:45 +00:00
int _width = 0 ;
2016-03-18 19:05:08 +00:00
// if unread bar is freezed the new messages do not
// increment the counter displayed by this bar
//
// it happens when we've opened the conversation and
// we've seen the bar and new messages are marked as read
// as soon as they are added to the chat history
2016-03-25 11:29:45 +00:00
bool _freezed = false ;
2016-03-18 19:05:08 +00:00
} ;
2014-08-11 09:03:45 +00:00
class HistoryMedia ;
2016-03-25 11:29:45 +00:00
class HistoryItem : public HistoryElem , public Composer {
2014-05-30 08:53:19 +00:00
public :
2016-03-18 19:05:08 +00:00
HistoryItem ( const HistoryItem & ) = delete ;
HistoryItem & operator = ( const HistoryItem & ) = delete ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:40:00 +00:00
int resizeGetHeight ( int width ) {
2016-03-19 16:55:15 +00:00
if ( _flags & MTPDmessage_ClientFlag : : f_pending_init_dimensions ) {
_flags & = ~ MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
initDimensions ( ) ;
}
if ( _flags & MTPDmessage_ClientFlag : : f_pending_resize ) {
_flags & = ~ MTPDmessage_ClientFlag : : f_pending_resize ;
}
2016-03-21 18:40:00 +00:00
return resizeGetHeight_ ( width ) ;
2016-03-19 16:55:15 +00:00
}
2015-12-11 18:11:38 +00:00
virtual void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const = 0 ;
2015-09-10 10:30:59 +00:00
2016-03-05 21:12:55 +00:00
virtual void dependencyItemRemoved ( HistoryItem * dependency ) {
}
virtual bool updateDependencyItem ( ) {
return true ;
}
virtual MsgId dependencyMsgId ( ) const {
return 0 ;
}
2016-03-11 12:20:58 +00:00
virtual bool notificationReady ( ) const {
return true ;
}
2016-03-05 21:12:55 +00:00
2016-03-25 11:29:45 +00:00
UserData * viaBot ( ) const {
if ( const HistoryMessageVia * via = Get < HistoryMessageVia > ( ) ) {
return via - > _bot ;
}
return nullptr ;
2015-12-31 15:27:21 +00:00
}
2015-12-22 08:01:02 +00:00
History * history ( ) const {
2014-05-30 08:53:19 +00:00
return _history ;
}
2015-09-04 13:01:31 +00:00
PeerData * from ( ) const {
2014-05-30 08:53:19 +00:00
return _from ;
}
HistoryBlock * block ( ) {
return _block ;
}
const HistoryBlock * block ( ) const {
return _block ;
}
2016-01-03 01:43:42 +00:00
virtual void destroy ( ) ;
2014-07-04 11:12:54 +00:00
void detach ( ) ;
void detachFast ( ) ;
bool detached ( ) const {
return ! _block ;
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
void attachToBlock ( HistoryBlock * block , int index ) {
2016-03-25 16:03:57 +00:00
t_assert ( _block = = nullptr ) ;
t_assert ( _indexInBlock < 0 ) ;
t_assert ( block ! = nullptr ) ;
t_assert ( index > = 0 ) ;
2016-03-19 16:55:15 +00:00
2015-04-30 23:05:19 +00:00
_block = block ;
2016-03-18 19:05:08 +00:00
_indexInBlock = index ;
2016-03-19 16:55:15 +00:00
if ( pendingResize ( ) ) {
_history - > setHasPendingResizedItems ( ) ;
}
2016-03-18 19:05:08 +00:00
}
void setIndexInBlock ( int index ) {
2016-03-25 16:03:57 +00:00
t_assert ( _block ! = nullptr ) ;
t_assert ( index > = 0 ) ;
2016-03-18 19:05:08 +00:00
_indexInBlock = index ;
2015-04-30 23:05:19 +00:00
}
2016-03-21 18:40:00 +00:00
int indexInBlock ( ) const {
if ( _indexInBlock > = 0 ) {
t_assert ( _block ! = nullptr ) ;
t_assert ( _block - > items . at ( _indexInBlock ) = = this ) ;
} else if ( _block ! = nullptr ) {
t_assert ( _indexInBlock > = 0 ) ;
t_assert ( _block - > items . at ( _indexInBlock ) = = this ) ;
}
return _indexInBlock ;
}
2014-05-30 08:53:19 +00:00
bool out ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_out ;
2014-05-30 08:53:19 +00:00
}
bool unread ( ) const {
2015-11-13 15:14:33 +00: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
2016-03-19 16:55:15 +00:00
return ( _flags & MTPDmessage : : Flag : : f_unread ) ;
2015-03-19 09:18:19 +00:00
}
2015-10-29 00:16:52 +00:00
bool mentionsMe ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_mentioned ;
2014-05-30 08:53:19 +00:00
}
2015-04-30 13:53:36 +00:00
bool isMediaUnread ( ) const {
2016-03-19 16:55:15 +00:00
return ( _flags & MTPDmessage : : Flag : : f_media_unread ) & & ( channelId ( ) = = NoChannel ) ;
2015-04-30 13:53:36 +00:00
}
void markMediaRead ( ) {
2016-03-19 16:55:15 +00:00
_flags & = ~ MTPDmessage : : Flag : : f_media_unread ;
2015-04-30 13:53:36 +00:00
}
2015-06-15 17:19:24 +00:00
bool hasReplyMarkup ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_reply_markup ;
2015-06-15 17:19:24 +00:00
}
2015-08-21 11:23:44 +00:00
bool hasTextLinks ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage_ClientFlag : : f_has_text_links ;
2015-08-21 11:23:44 +00:00
}
2015-11-13 15:14:33 +00:00
bool isGroupMigrate ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage_ClientFlag : : f_is_group_migrate ;
2015-11-13 15:14:33 +00:00
}
2015-09-21 20:57:42 +00:00
bool hasViews ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_views ;
2015-09-21 20:57:42 +00:00
}
2016-02-17 16:37:21 +00:00
bool isPost ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_post ;
2015-09-13 17:27:29 +00:00
}
2015-09-19 09:13:21 +00:00
bool isImportant ( ) const {
2015-09-21 20:57:42 +00:00
return _history - > isChannel ( ) & & isImportantChannelMessage ( id , _flags ) ;
2015-09-19 09:13:21 +00:00
}
2015-11-02 22:33:57 +00:00
bool indexInOverview ( ) const {
2016-02-17 16:37:21 +00:00
return ( id > 0 ) & & ( ! history ( ) - > isChannel ( ) | | history ( ) - > isMegagroup ( ) | | isPost ( ) ) ;
}
bool isSilent ( ) const {
2016-03-19 16:55:15 +00:00
return _flags & MTPDmessage : : Flag : : f_silent ;
2016-02-17 16:37:21 +00:00
}
2016-03-25 11:29:45 +00:00
bool hasOutLayout ( ) const {
return out ( ) & & ! isPost ( ) ;
}
2016-02-17 16:37:21 +00:00
virtual int32 viewsCount ( ) const {
return hasViews ( ) ? 1 : - 1 ;
2015-11-02 22:33:57 +00:00
}
2014-05-30 08:53:19 +00:00
virtual bool needCheck ( ) const {
2015-10-28 00:29:39 +00:00
return out ( ) | | ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) ;
2014-05-30 08:53:19 +00:00
}
virtual bool hasPoint ( int32 x , int32 y ) const {
return false ;
}
2015-06-27 13:02:00 +00:00
virtual void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const {
2014-05-30 08:53:19 +00:00
lnk = TextLinkPtr ( ) ;
2015-06-27 13:02:00 +00:00
state = HistoryDefaultCursorState ;
2014-05-30 08:53:19 +00: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 18:11:38 +00:00
virtual void linkOver ( const TextLinkPtr & lnk ) {
}
virtual void linkOut ( const TextLinkPtr & lnk ) {
}
2015-09-19 09:13:21 +00:00
virtual HistoryItemType type ( ) const {
return HistoryItemMsg ;
2014-05-30 08:53:19 +00:00
}
virtual bool serviceMsg ( ) const {
return false ;
}
2016-02-18 16:36:33 +00:00
virtual void updateMedia ( const MTPMessageMedia * media , bool edited = false ) {
2014-05-30 08:53:19 +00:00
}
2016-01-03 01:43:42 +00:00
virtual int32 addToOverview ( AddToOverviewMethod method ) {
return 0 ;
}
2015-12-09 18:06:20 +00:00
virtual bool hasBubble ( ) const {
return false ;
}
2016-03-18 19:05:08 +00:00
virtual void previousItemChanged ( ) ;
2014-05-30 08:53:19 +00:00
virtual QString selectedText ( uint32 selection ) const {
return qsl ( " [-] " ) ;
}
2015-03-19 09:18:19 +00:00
virtual QString inDialogsText ( ) const {
return qsl ( " - " ) ;
}
virtual QString inReplyText ( ) const {
return inDialogsText ( ) ;
}
2014-05-30 08:53:19 +00:00
2015-12-11 18:11:38 +00:00
virtual void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const {
2015-09-15 08:50:54 +00:00
}
2016-03-19 16:55:15 +00:00
virtual void setViewsCount ( int32 count ) {
2015-09-15 08:50:54 +00:00
}
2015-11-18 13:11:56 +00:00
virtual void setId ( MsgId newId ) ;
2015-09-15 08:50:54 +00:00
virtual void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const = 0 ;
2014-06-14 19:32:11 +00:00
virtual QString notificationHeader ( ) const {
return QString ( ) ;
}
virtual QString notificationText ( ) const = 0 ;
2014-05-30 08:53:19 +00:00
2015-09-21 20:57:42 +00:00
bool canDelete ( ) const {
ChannelData * channel = _history - > peer - > asChannel ( ) ;
2016-03-19 16:55:15 +00:00
if ( ! channel ) return ! ( _flags & MTPDmessage_ClientFlag : : f_is_group_migrate ) ;
2015-09-21 20:57:42 +00:00
if ( id = = 1 ) return false ;
if ( channel - > amCreator ( ) ) return true ;
2016-02-17 16:37:21 +00:00
if ( isPost ( ) ) {
2015-09-21 20:57:42 +00:00
if ( channel - > amEditor ( ) & & out ( ) ) return true ;
return false ;
}
return ( channel - > amEditor ( ) | | channel - > amModerator ( ) | | out ( ) ) ;
}
2016-03-10 10:15:21 +00:00
bool canPin ( ) const {
return id > 0 & & _history - > peer - > isMegagroup ( ) & & ( _history - > peer - > asChannel ( ) - > amEditor ( ) | | _history - > peer - > asChannel ( ) - > amCreator ( ) ) & & toHistoryMessage ( ) ;
}
2016-02-21 12:30:16 +00:00
bool canEdit ( const QDateTime & cur ) const ;
2016-03-10 10:15:21 +00:00
2016-03-13 15:45:00 +00:00
bool suggestBanReportDeleteAll ( ) const {
2016-03-14 16:59:18 +00:00
ChannelData * channel = history ( ) - > peer - > asChannel ( ) ;
2016-03-13 15:45:00 +00:00
if ( ! channel | | ( ! channel - > amEditor ( ) & & ! channel - > amCreator ( ) ) ) return false ;
return ! isPost ( ) & & ! out ( ) & & from ( ) - > isUser ( ) & & toHistoryMessage ( ) ;
}
2016-02-25 17:23:42 +00:00
bool hasDirectLink ( ) const {
2016-03-13 13:21:26 +00:00
return id > 0 & & _history - > peer - > isChannel ( ) & & _history - > peer - > asChannel ( ) - > isPublic ( ) & & ! _history - > peer - > isMegagroup ( ) ;
2016-02-25 17:23:42 +00:00
}
QString directLink ( ) const {
return hasDirectLink ( ) ? qsl ( " https://telegram.me/ " ) + _history - > peer - > asChannel ( ) - > username + ' / ' + QString : : number ( id ) : QString ( ) ;
}
2016-02-21 12:30:16 +00:00
2015-09-03 10:48:40 +00:00
int32 y ;
MsgId id ;
2014-05-30 08:53:19 +00:00
QDateTime date ;
2015-09-03 10:48:40 +00:00
ChannelId channelId ( ) const {
return _history - > channelId ( ) ;
}
FullMsgId fullId ( ) const {
return FullMsgId ( channelId ( ) , id ) ;
}
2014-08-11 09:03:45 +00:00
virtual HistoryMedia * getMedia ( bool inOverview = false ) const {
return 0 ;
}
2015-10-23 16:06:56 +00:00
virtual void setText ( const QString & text , const EntitiesInText & links ) {
2015-08-24 10:53:04 +00:00
}
2015-10-25 17:08:45 +00:00
virtual QString originalText ( ) const {
return QString ( ) ;
}
virtual EntitiesInText originalEntities ( ) const {
return EntitiesInText ( ) ;
2015-08-28 15:15:56 +00:00
}
2015-09-01 21:33:44 +00:00
virtual bool textHasLinks ( ) {
return false ;
}
2015-09-15 08:50:54 +00: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 15:50:11 +00:00
virtual HistoryMessage * toHistoryMessage ( ) { // dynamic_cast optimize
2015-03-19 09:18:19 +00:00
return 0 ;
}
2015-04-23 15:50:11 +00:00
virtual const HistoryMessage * toHistoryMessage ( ) const { // dynamic_cast optimize
2015-03-19 09:18:19 +00:00
return 0 ;
}
2016-03-25 11:29:45 +00:00
MsgId replyToId ( ) const {
if ( auto * reply = Get < HistoryMessageReply > ( ) ) {
return reply - > replyToId ( ) ;
}
2015-04-13 08:58:13 +00:00
return 0 ;
}
2015-03-19 09:18:19 +00:00
2015-12-09 19:09:29 +00:00
bool hasFromName ( ) const {
2016-02-17 16:37:21 +00:00
return ( ! out ( ) | | isPost ( ) ) & & ! history ( ) - > peer - > isUser ( ) ;
}
PeerData * author ( ) const {
return isPost ( ) ? history ( ) - > peer : _from ;
2015-09-13 17:27:29 +00:00
}
2015-09-03 10:48:40 +00:00
2016-02-18 19:12:50 +00:00
PeerData * fromOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _fromOriginal ;
}
2016-02-18 16:36:33 +00:00
return from ( ) ;
}
2016-02-18 19:12:50 +00:00
PeerData * authorOriginal ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
return fwd - > _authorOriginal ;
}
2016-02-18 16:36:33 +00:00
return author ( ) ;
}
2016-03-18 19:05:08 +00:00
// count > 0 - creates the unread bar if necessary and
// sets unread messages count if bar is not freezed yet
// count <= 0 - destroys the unread bar
void setUnreadBarCount ( int count ) ;
void destroyUnreadBar ( ) ;
// marks the unread bar as freezed so that unread
// messages count will not change for this bar
// when the new messages arrive in this chat history
void setUnreadBarFreezed ( ) ;
2016-03-19 16:55:15 +00:00
bool pendingResize ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_pending_resize ;
}
void setPendingResize ( ) {
_flags | = MTPDmessage_ClientFlag : : f_pending_resize ;
if ( ! detached ( ) ) {
_history - > setHasPendingResizedItems ( ) ;
}
}
bool pendingInitDimensions ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
}
void setPendingInitDimensions ( ) {
_flags | = MTPDmessage_ClientFlag : : f_pending_init_dimensions ;
setPendingResize ( ) ;
}
2016-03-21 18:40:00 +00:00
int displayedDateHeight ( ) const {
if ( auto * date = Get < HistoryMessageDate > ( ) ) {
return date - > height ( ) ;
}
return 0 ;
}
int marginTop ( ) const {
int result = 0 ;
if ( isAttachedToPrevious ( ) ) {
result + = st : : msgMarginTopAttached ;
} else {
result + = st : : msgMargin . top ( ) ;
}
result + = displayedDateHeight ( ) ;
if ( auto * unreadbar = Get < HistoryMessageUnreadBar > ( ) ) {
result + = unreadbar - > height ( ) ;
}
return result ;
}
int marginBottom ( ) const {
return st : : msgMargin . bottom ( ) ;
}
2016-03-22 19:43:47 +00:00
bool isAttachedToPrevious ( ) const {
return _flags & MTPDmessage_ClientFlag : : f_attach_to_previous ;
}
2016-03-21 18:40:00 +00:00
2015-12-28 21:20:04 +00:00
void clipCallback ( ClipReaderNotification notification ) ;
2014-05-30 08:53:19 +00:00
virtual ~ HistoryItem ( ) ;
protected :
2016-03-19 16:55:15 +00:00
HistoryItem ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime msgDate , int32 from ) ;
// to completely create history item we need to call
// a virtual method, it can not be done from constructor
virtual void finishCreate ( ) ;
2016-03-18 19:05:08 +00:00
2016-03-21 18:40:00 +00:00
// called from resizeGetHeight() when MTPDmessage_ClientFlag::f_pending_init_dimensions is set
2016-03-19 16:55:15 +00:00
virtual void initDimensions ( ) = 0 ;
2016-03-21 18:40:00 +00:00
virtual int resizeGetHeight_ ( int width ) = 0 ;
2016-03-18 19:05:08 +00:00
2015-09-04 13:01:31 +00:00
PeerData * _from ;
2014-05-30 08:53:19 +00:00
History * _history ;
2016-03-18 19:05:08 +00:00
HistoryBlock * _block = nullptr ;
int _indexInBlock = - 1 ;
2016-03-19 16:55:15 +00:00
MTPDmessage : : Flags _flags ;
2014-05-30 08:53:19 +00:00
2016-02-17 16:37:21 +00:00
mutable int32 _authorNameVersion ;
2016-03-18 19:05:08 +00:00
HistoryItem * previous ( ) const {
if ( _block & & _indexInBlock > = 0 ) {
2016-03-31 14:06:40 +00:00
if ( _indexInBlock > 0 ) {
return _block - > items . at ( _indexInBlock - 1 ) ;
}
2016-03-18 19:05:08 +00:00
if ( HistoryBlock * previousBlock = _block - > previous ( ) ) {
2016-03-31 14:06:40 +00:00
t_assert ( ! previousBlock - > items . isEmpty ( ) ) ;
2016-03-18 19:05:08 +00:00
return previousBlock - > items . back ( ) ;
}
}
return nullptr ;
}
2016-03-19 18:32:17 +00:00
// this should be used only in previousItemChanged()
2016-03-18 19:05:08 +00:00
// to add required bits to the Interfaces mask
2016-03-25 11:29:45 +00:00
// after that always use Has<HistoryMessageDate>()
2016-03-18 19:05:08 +00:00
bool displayDate ( ) const {
if ( HistoryItem * prev = previous ( ) ) {
return prev - > date . date ( ) . day ( ) ! = date . date ( ) . day ( ) ;
}
return true ;
}
2016-03-21 18:40:00 +00:00
// this should be used only in previousItemChanged() or when
// HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Interfaces mask
// then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous
void recountAttachToPrevious ( ) ;
2016-03-18 19:05:08 +00:00
} ;
// make all the constructors in HistoryItem children protected
// and wrapped with a static create() call with the same args
// so that history item can not be created directly, without
2016-03-19 16:55:15 +00:00
// calling a virtual finishCreate() method
2016-03-18 19:05:08 +00:00
template < typename T >
class HistoryItemInstantiated {
public :
template < typename . . . Args >
static T * _create ( Args . . . args ) {
T * result = new T ( args . . . ) ;
result - > finishCreate ( ) ;
return result ;
}
2014-05-30 08:53:19 +00:00
} ;
2015-03-19 09:18:19 +00:00
class MessageLink : public ITextLink {
2015-06-27 13:02:00 +00:00
TEXT_LINK_CLASS ( MessageLink )
2015-03-19 09:18:19 +00:00
public :
MessageLink ( PeerId peer , MsgId msgid ) : _peer ( peer ) , _msgid ( msgid ) {
}
2015-12-21 13:14:29 +00:00
MessageLink ( HistoryItem * item ) : _peer ( item - > history ( ) - > peer - > id ) , _msgid ( item - > id ) {
}
2015-03-19 09:18:19 +00: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 09:13:21 +00:00
class CommentsLink : public ITextLink {
TEXT_LINK_CLASS ( CommentsLink )
public :
CommentsLink ( HistoryItem * item ) : _item ( item ) {
}
void onClick ( Qt : : MouseButton button ) const ;
2015-12-31 15:27:21 +00:00
2015-09-19 09:13:21 +00:00
private :
HistoryItem * _item ;
} ;
2015-12-11 18:11:38 +00:00
class RadialAnimation {
public :
2015-12-28 21:20:04 +00:00
RadialAnimation ( AnimationCreator creator ) ;
2015-12-11 18:11:38 +00: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-12 22:29:33 +00:00
void step ( uint64 ms ) ;
void step ( ) {
step ( getms ( ) ) ;
}
2015-12-22 12:49:42 +00:00
void draw ( Painter & p , const QRect & inner , int32 thickness , const style : : color & color ) ;
2015-12-11 18:11:38 +00:00
private :
uint64 _firstStart , _lastStart , _lastTime ;
float64 _opacity ;
2015-12-12 22:29:33 +00:00
anim : : ivalue a_arcEnd , a_arcStart ;
2015-12-11 18:11:38 +00:00
Animation _animation ;
} ;
2014-05-30 08:53:19 +00:00
class HistoryMedia : public HistoryElem {
public :
2015-12-19 18:09:24 +00:00
HistoryMedia ( ) : _width ( 0 ) {
2014-11-18 12:41:33 +00:00
}
2015-12-19 18:09:24 +00:00
HistoryMedia ( const HistoryMedia & other ) : _width ( 0 ) {
2015-04-04 20:01:34 +00:00
}
2014-11-18 12:41:33 +00:00
2014-05-30 08:53:19 +00:00
virtual HistoryMediaType type ( ) const = 0 ;
virtual const QString inDialogsText ( ) const = 0 ;
2014-11-22 09:45:04 +00:00
virtual const QString inHistoryText ( ) const = 0 ;
2015-12-19 18:09:24 +00:00
bool hasPoint ( int32 x , int32 y , const HistoryItem * parent ) const {
return ( x > = 0 & & y > = 0 & & x < _width & & y < _height ) ;
}
2015-05-20 19:28:24 +00:00
virtual bool isDisplayed ( ) const {
return true ;
}
2015-09-10 10:30:59 +00:00
virtual void initDimensions ( const HistoryItem * parent ) = 0 ;
virtual int32 resize ( int32 width , const HistoryItem * parent ) { // return new height
2015-12-19 18:09:24 +00:00
_width = qMin ( width , _maxw ) ;
2014-11-18 12:41:33 +00:00
return _height ;
}
2015-12-19 18:09:24 +00: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 18:11:38 +00:00
virtual void linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) {
}
virtual void linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) {
}
2015-12-19 18:09:24 +00:00
2014-05-30 08:53:19 +00:00
virtual bool uploading ( ) const {
return false ;
}
virtual HistoryMedia * clone ( ) const = 0 ;
2015-12-18 21:36:16 +00:00
virtual DocumentData * getDocument ( ) {
return 0 ;
}
2015-12-28 21:20:04 +00:00
virtual ClipReader * getClipReader ( ) {
return 0 ;
}
2015-12-18 21:36:16 +00:00
2016-03-19 16:55:15 +00:00
bool playInline ( HistoryItem * item /*, bool autoplay = false*/ ) {
return playInline ( item , false ) ;
}
virtual bool playInline ( HistoryItem * item , bool autoplay ) {
2015-12-18 21:36:16 +00:00
return false ;
}
virtual void stopInline ( HistoryItem * item ) {
}
2016-03-18 19:05:08 +00:00
virtual void attachToItem ( HistoryItem * item ) {
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
virtual void detachFromItem ( HistoryItem * item ) {
2014-05-30 08:53:19 +00:00
}
2016-01-09 07:11:23 +00:00
virtual void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) {
2014-05-30 08:53:19 +00:00
}
2015-01-05 20:17:33 +00:00
2015-04-11 10:04:10 +00:00
virtual bool isImageLink ( ) const {
return false ;
}
2014-09-30 14:11:09 +00:00
virtual bool animating ( ) const {
return false ;
}
2014-05-30 08:53:19 +00:00
2015-03-19 09:18:19 +00:00
virtual bool hasReplyPreview ( ) const {
return false ;
}
virtual ImagePtr replyPreview ( ) {
return ImagePtr ( ) ;
}
2015-10-11 08:37:24 +00:00
virtual QString getCaption ( ) const {
return QString ( ) ;
}
2015-12-08 19:07:50 +00:00
virtual bool needsBubble ( const HistoryItem * parent ) const = 0 ;
2015-12-09 18:06:20 +00:00
virtual bool customInfoLayout ( ) const = 0 ;
2015-12-18 21:36:16 +00:00
virtual QMargins bubbleMargins ( ) const {
return QMargins ( ) ;
}
2015-12-09 19:09:29 +00:00
virtual bool hideFromName ( ) const {
return false ;
}
virtual bool hideForwardedFrom ( ) const {
return false ;
}
2015-03-19 09:18:19 +00:00
2014-11-18 12:41:33 +00:00
int32 currentWidth ( ) const {
2015-12-19 18:09:24 +00:00
return _width ;
2014-11-18 12:41:33 +00:00
}
protected :
2015-12-19 18:09:24 +00:00
int32 _width ;
2014-11-18 12:41:33 +00:00
2014-05-30 08:53:19 +00:00
} ;
2016-01-03 01:43:42 +00:00
inline MediaOverviewType mediaToOverviewType ( HistoryMedia * media ) {
switch ( media - > type ( ) ) {
case MediaTypePhoto : return OverviewPhotos ;
case MediaTypeVideo : return OverviewVideos ;
2016-02-12 16:35:06 +00: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 01:43:42 +00:00
}
return OverviewCount ;
}
2015-12-12 22:29:33 +00: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 17:05:32 +00:00
// duration = -1 - no duration, duration = -2 - "GIF" duration
2015-12-12 22:29:33 +00: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-27 21:37:48 +00:00
bool isThumbAnimation ( uint64 ms ) const {
if ( ! _animation | | ! _animation - > _a_thumbOver . animating ( ) ) return false ;
2015-12-31 15:27:21 +00:00
2015-12-27 21:37:48 +00:00
_animation - > _a_thumbOver . step ( ms ) ;
return _animation & & _animation - > _a_thumbOver . animating ( ) ;
}
2015-12-12 22:29:33 +00:00
virtual float64 dataProgress ( ) const = 0 ;
virtual bool dataFinished ( ) const = 0 ;
virtual bool dataLoaded ( ) const = 0 ;
struct AnimationData {
2015-12-28 21:20:04 +00:00
AnimationData ( AnimationCreator thumbOverCallbacks , AnimationCreator radialCallbacks ) : a_thumbOver ( 0 , 0 )
2015-12-12 22:29:33 +00:00
, _a_thumbOver ( thumbOverCallbacks )
2015-12-22 12:49:42 +00:00
, radial ( radialCallbacks ) {
2015-12-12 22:29:33 +00:00
}
anim : : fvalue a_thumbOver ;
Animation _a_thumbOver ;
RadialAnimation radial ;
} ;
mutable AnimationData * _animation ;
2015-12-17 17:31:28 +00:00
private :
HistoryFileMedia ( const HistoryFileMedia & other ) ;
2015-12-12 22:29:33 +00:00
} ;
2015-12-24 19:26:28 +00:00
class HistoryPhoto : public HistoryFileMedia {
public :
2015-12-31 05:34:43 +00:00
HistoryPhoto ( PhotoData * photo , const QString & caption , const HistoryItem * parent ) ;
2015-12-24 19:26:28 +00:00
HistoryPhoto ( PeerData * chat , const MTPDphoto & photo , int32 width = 0 ) ;
HistoryPhoto ( const HistoryPhoto & other ) ;
void init ( ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2015-12-24 19:26:28 +00:00
return MediaTypePhoto ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-24 19:26:28 +00:00
return new HistoryPhoto ( * this ) ;
}
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2015-12-24 19:26:28 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-24 19:26:28 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2015-12-24 19:26:28 +00:00
PhotoData * photo ( ) const {
return _data ;
}
2016-03-21 18:57:03 +00:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) override ;
2015-12-24 19:26:28 +00:00
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2015-12-25 13:09:14 +00:00
2016-03-21 18:57:03 +00:00
bool hasReplyPreview ( ) const override {
2015-12-24 19:26:28 +00:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 18:57:03 +00:00
ImagePtr replyPreview ( ) override ;
2015-12-24 19:26:28 +00:00
2016-03-21 18:57:03 +00:00
QString getCaption ( ) const override {
2015-12-24 19:26:28 +00:00
return _caption . original ( ) ;
}
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2016-03-25 11:29:45 +00:00
return ! _caption . isEmpty ( ) | | parent - > Has < HistoryMessageForwarded > ( ) | | parent - > Has < HistoryMessageReply > ( ) | | parent - > viaBot ( ) ;
2015-12-24 19:26:28 +00:00
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-24 19:26:28 +00:00
return _caption . isEmpty ( ) ;
}
2016-03-21 18:57:03 +00:00
bool hideFromName ( ) const override {
2015-12-24 19:26:28 +00:00
return true ;
}
protected :
2016-03-21 18:57:03 +00:00
float64 dataProgress ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > progress ( ) ;
}
2016-03-21 18:57:03 +00:00
bool dataFinished ( ) const override {
2015-12-24 19:26:28 +00:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
}
2016-03-21 18:57:03 +00:00
bool dataLoaded ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > loaded ( ) ;
}
private :
PhotoData * _data ;
int16 _pixw , _pixh ;
Text _caption ;
} ;
2015-12-13 15:21:20 +00:00
class HistoryVideo : public HistoryFileMedia {
public :
2016-03-14 05:31:33 +00:00
HistoryVideo ( DocumentData * document , const QString & caption , const HistoryItem * parent ) ;
2015-12-17 17:31:28 +00:00
HistoryVideo ( const HistoryVideo & other ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2015-12-19 18:09:24 +00:00
return MediaTypeVideo ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistoryVideo ( * this ) ;
}
2015-12-17 17:31:28 +00:00
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2015-12-13 15:21:20 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
DocumentData * getDocument ( ) override {
2015-12-19 18:09:24 +00:00
return _data ;
}
2016-03-21 18:57:03 +00:00
bool uploading ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > uploading ( ) ;
2015-12-13 15:21:20 +00:00
}
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2015-12-13 15:21:20 +00:00
2016-03-21 18:57:03 +00:00
bool hasReplyPreview ( ) const override {
2015-12-13 15:21:20 +00:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 18:57:03 +00:00
ImagePtr replyPreview ( ) override ;
2015-12-13 15:21:20 +00:00
2016-03-21 18:57:03 +00:00
QString getCaption ( ) const override {
2016-03-10 10:15:21 +00:00
return _caption . original ( ) ;
}
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2016-03-25 11:29:45 +00:00
return ! _caption . isEmpty ( ) | | parent - > Has < HistoryMessageForwarded > ( ) | | parent - > Has < HistoryMessageReply > ( ) | | parent - > viaBot ( ) ;
2015-12-13 15:21:20 +00:00
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-13 15:21:20 +00:00
return _caption . isEmpty ( ) ;
}
2016-03-21 18:57:03 +00:00
bool hideFromName ( ) const override {
2015-12-13 15:21:20 +00:00
return true ;
}
protected :
2016-03-21 18:57:03 +00:00
float64 dataProgress ( ) const override {
2015-12-13 15:21:20 +00:00
return _data - > progress ( ) ;
}
2016-03-21 18:57:03 +00:00
bool dataFinished ( ) const override {
2015-12-24 19:26:28 +00:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-13 15:21:20 +00:00
}
2016-03-21 18:57:03 +00:00
bool dataLoaded ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > loaded ( ) ;
2015-12-13 15:21:20 +00:00
}
private :
2016-02-12 18:18:32 +00:00
DocumentData * _data ;
int32 _thumbw ;
2015-12-13 15:21:20 +00:00
Text _caption ;
void setStatusSize ( int32 newSize ) const ;
void updateStatusText ( const HistoryItem * parent ) const ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryDocumentThumbed : public BaseComponent < HistoryDocumentThumbed > {
HistoryDocumentThumbed ( Composer * ) {
2015-05-29 18:52:43 +00:00
}
2016-02-12 16:35:06 +00:00
TextLinkPtr _linksavel , _linkcancell ;
2016-03-25 11:29:45 +00:00
int _thumbw = 0 ;
2015-05-29 18:52:43 +00:00
2016-03-25 11:29:45 +00:00
mutable int _linkw = 0 ;
2016-02-12 16:35:06 +00:00
mutable QString _link ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryDocumentCaptioned : public BaseComponent < HistoryDocumentCaptioned > {
HistoryDocumentCaptioned ( Composer * ) : _caption ( st : : msgFileMinWidth - st : : msgPadding . left ( ) - st : : msgPadding . right ( ) ) {
2015-12-08 19:07:50 +00:00
}
2016-02-12 16:35:06 +00:00
Text _caption ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryDocumentNamed : public BaseComponent < HistoryDocumentNamed > {
HistoryDocumentNamed ( Composer * ) {
2015-12-18 21:36:16 +00:00
}
2016-02-12 16:35:06 +00:00
QString _name ;
2016-03-25 11:29:45 +00:00
int _namew = 0 ;
2016-02-12 16:35:06 +00:00
} ;
class HistoryDocument ;
struct HistoryDocumentVoicePlayback {
HistoryDocumentVoicePlayback ( const HistoryDocument * that ) ;
2015-12-08 19:07:50 +00:00
2016-02-12 16:35:06 +00:00
int32 _position ;
anim : : fvalue a_progress ;
Animation _a_progress ;
} ;
2016-03-25 11:29:45 +00:00
struct HistoryDocumentVoice : public BaseComponent < HistoryDocumentVoice > {
HistoryDocumentVoice ( Composer * ) {
}
HistoryDocumentVoice & operator = ( HistoryDocumentVoice & & other ) {
std : : swap ( _playback , other . _playback ) ;
return * this ;
2015-12-12 22:29:33 +00:00
}
2016-02-12 16:35:06 +00:00
~ HistoryDocumentVoice ( ) {
deleteAndMark ( _playback ) ;
2015-12-12 22:29:33 +00:00
}
2016-02-12 16:35:06 +00:00
void ensurePlayback ( const HistoryDocument * interfaces ) const ;
void checkPlaybackFinished ( ) const ;
2016-03-25 11:29:45 +00:00
mutable HistoryDocumentVoicePlayback * _playback = nullptr ;
2014-05-30 08:53:19 +00:00
} ;
2016-03-25 11:29:45 +00:00
class HistoryDocument : public HistoryFileMedia , public Composer {
2014-05-30 08:53:19 +00:00
public :
2015-12-28 10:28:00 +00:00
HistoryDocument ( DocumentData * document , const QString & caption , const HistoryItem * parent ) ;
2015-12-17 17:31:28 +00:00
HistoryDocument ( const HistoryDocument & other ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2016-02-12 16:35:06 +00:00
return _data - > voice ( ) ? MediaTypeVoiceFile : ( _data - > song ( ) ? MediaTypeMusicFile : MediaTypeFile ) ;
2015-12-19 18:09:24 +00:00
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistoryDocument ( * this ) ;
}
2015-12-17 17:31:28 +00:00
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
bool uploading ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > uploading ( ) ;
2014-05-30 08:53:19 +00:00
}
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
DocumentData * getDocument ( ) override {
2015-12-08 19:07:50 +00:00
return _data ;
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) override ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
bool hasReplyPreview ( ) const override {
2015-12-08 19:07:50 +00:00
return ! _data - > thumb - > isNull ( ) ;
2015-03-19 09:18:19 +00:00
}
2016-03-21 18:57:03 +00:00
ImagePtr replyPreview ( ) override ;
2015-03-19 09:18:19 +00:00
2016-03-21 18:57:03 +00:00
QString getCaption ( ) const override {
2016-02-12 16:35:06 +00:00
if ( const HistoryDocumentCaptioned * captioned = Get < HistoryDocumentCaptioned > ( ) ) {
return captioned - > _caption . original ( ) ;
}
return QString ( ) ;
2015-12-28 10:28:00 +00:00
}
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2015-12-08 19:07:50 +00:00
return true ;
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-08 19:07:50 +00:00
return false ;
}
2016-03-21 18:57:03 +00:00
QMargins bubbleMargins ( ) const override {
2016-02-12 16:35:06 +00:00
return Get < HistoryDocumentThumbed > ( ) ? QMargins ( st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . top ( ) , st : : msgFileThumbPadding . left ( ) , st : : msgFileThumbPadding . bottom ( ) ) : st : : msgPadding ;
2015-12-18 21:36:16 +00:00
}
2016-03-21 18:57:03 +00:00
bool hideForwardedFrom ( ) const override {
2015-12-09 19:09:29 +00:00
return _data - > song ( ) ;
}
2015-12-08 19:07:50 +00:00
2016-02-12 16:35:06 +00:00
void step_voiceProgress ( float64 ms , bool timer ) ;
2015-12-12 22:29:33 +00:00
protected :
2016-03-21 18:57:03 +00:00
float64 dataProgress ( ) const override {
2015-12-12 22:29:33 +00:00
return _data - > progress ( ) ;
}
2016-03-21 18:57:03 +00:00
bool dataFinished ( ) const override {
2015-12-24 19:26:28 +00:00
return ! _data - > loading ( ) & & ! _data - > uploading ( ) ;
2015-12-12 22:29:33 +00:00
}
2016-03-21 18:57:03 +00:00
bool dataLoaded ( ) const override {
2015-12-23 16:48:44 +00:00
return _data - > loaded ( ) ;
2015-12-12 22:29:33 +00:00
}
2015-12-11 18:11:38 +00:00
2014-05-30 08:53:19 +00:00
private :
2016-03-18 19:05:08 +00:00
void createInterfaces ( bool caption ) ;
2016-02-12 16:35:06 +00:00
const HistoryItem * _parent ;
2015-12-08 19:07:50 +00:00
DocumentData * _data ;
2015-12-28 10:28:00 +00:00
2015-12-09 18:06:20 +00:00
void setStatusSize ( int32 newSize , qint64 realDuration = 0 ) const ;
bool updateStatusText ( const HistoryItem * parent ) const ; // returns showPause
2015-12-11 18:11:38 +00:00
2015-12-08 19:07:50 +00:00
} ;
2015-12-13 17:05:32 +00:00
class HistoryGif : public HistoryFileMedia {
2015-12-08 19:07:50 +00:00
public :
2015-12-28 10:28:00 +00:00
HistoryGif ( DocumentData * document , const QString & caption , const HistoryItem * parent ) ;
2015-12-17 17:31:28 +00:00
HistoryGif ( const HistoryGif & other ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2015-12-19 18:09:24 +00:00
return MediaTypeGif ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistoryGif ( * this ) ;
}
2015-12-17 17:31:28 +00:00
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2015-12-08 19:07:50 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
bool uploading ( ) const override {
2015-12-24 19:26:28 +00:00
return _data - > uploading ( ) ;
2015-12-08 19:07:50 +00:00
}
2016-03-21 18:57:03 +00:00
DocumentData * getDocument ( ) override {
2015-12-08 19:07:50 +00:00
return _data ;
}
2016-03-21 18:57:03 +00:00
ClipReader * getClipReader ( ) override {
2015-12-28 21:20:04 +00:00
return gif ( ) ;
}
2015-12-19 18:09:24 +00:00
2016-03-19 16:55:15 +00:00
bool playInline ( HistoryItem * item , bool autoplay ) override ;
void stopInline ( HistoryItem * item ) override ;
2015-12-08 19:07:50 +00:00
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2015-12-08 19:07:50 +00:00
2016-03-21 18:57:03 +00:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) override ;
2015-12-08 19:07:50 +00:00
2016-03-21 18:57:03 +00:00
bool hasReplyPreview ( ) const override {
2015-12-08 19:07:50 +00:00
return ! _data - > thumb - > isNull ( ) ;
}
2016-03-21 18:57:03 +00:00
ImagePtr replyPreview ( ) override ;
2015-12-08 19:07:50 +00:00
2016-03-21 18:57:03 +00:00
QString getCaption ( ) const override {
2015-12-28 10:28:00 +00:00
return _caption . original ( ) ;
}
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2016-03-25 11:29:45 +00:00
return ! _caption . isEmpty ( ) | | parent - > Has < HistoryMessageForwarded > ( ) | | parent - > Has < HistoryMessageReply > ( ) | | parent - > viaBot ( ) ;
2015-12-08 19:07:50 +00:00
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-28 10:28:00 +00:00
return _caption . isEmpty ( ) ;
2015-12-08 19:07:50 +00:00
}
2016-03-21 18:57:03 +00:00
bool hideFromName ( ) const override {
2015-12-13 17:05:32 +00:00
return true ;
}
2015-12-15 14:50:51 +00:00
~ HistoryGif ( ) ;
2015-12-13 17:05:32 +00:00
protected :
2016-03-21 18:57:03 +00:00
float64 dataProgress ( ) const override ;
bool dataFinished ( ) const override ;
bool dataLoaded ( ) const override ;
2015-12-08 19:07:50 +00:00
private :
2015-12-31 15:27:21 +00:00
const HistoryItem * _parent ;
2015-12-08 19:07:50 +00:00
DocumentData * _data ;
2015-12-13 17:05:32 +00:00
int32 _thumbw , _thumbh ;
2015-12-28 10:28:00 +00:00
Text _caption ;
2015-12-15 14:50:51 +00:00
ClipReader * _gif ;
2015-12-25 13:10:13 +00:00
ClipReader * gif ( ) {
2016-03-19 16:55:15 +00:00
return ( _gif = = BadClipReader ) ? nullptr : _gif ;
2015-12-25 13:10:13 +00:00
}
const ClipReader * gif ( ) const {
2016-03-19 16:55:15 +00:00
return ( _gif = = BadClipReader ) ? nullptr : _gif ;
2015-12-25 13:10:13 +00:00
}
2014-05-30 08:53:19 +00:00
2015-12-13 17:05:32 +00:00
void setStatusSize ( int32 newSize ) const ;
void updateStatusText ( const HistoryItem * parent ) const ;
2015-12-08 19:07:50 +00:00
2014-05-30 08:53:19 +00:00
} ;
2014-12-22 23:11:37 +00:00
class HistorySticker : public HistoryMedia {
public :
2015-04-04 20:01:34 +00:00
HistorySticker ( DocumentData * document ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2014-12-22 23:11:37 +00:00
return MediaTypeSticker ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistorySticker ( * this ) ;
}
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2014-12-22 23:11:37 +00:00
2016-03-21 18:57:03 +00:00
DocumentData * getDocument ( ) override {
2015-12-23 12:19:32 +00:00
return _data ;
2014-12-22 23:11:37 +00:00
}
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2014-12-22 23:11:37 +00:00
2016-03-21 18:57:03 +00:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) override ;
2014-12-22 23:11:37 +00:00
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2015-12-08 19:07:50 +00:00
return false ;
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-08 19:07:50 +00:00
return true ;
}
2014-12-22 23:11:37 +00:00
private :
2015-12-23 12:19:32 +00:00
int16 _pixw , _pixh ;
DocumentData * _data ;
2015-01-05 20:17:33 +00:00
QString _emoji ;
2014-12-22 23:11:37 +00:00
} ;
2015-12-12 22:29:33 +00: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 08:53:19 +00:00
class HistoryContact : public HistoryMedia {
public :
HistoryContact ( int32 userId , const QString & first , const QString & last , const QString & phone ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2014-05-30 08:53:19 +00:00
return MediaTypeContact ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistoryContact ( _userId , _fname , _lname , _phone ) ;
}
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2014-05-30 08:53:19 +00:00
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2015-12-12 22:29:33 +00:00
2016-03-21 18:57:03 +00:00
void updateFrom ( const MTPMessageMedia & media , HistoryItem * parent ) override ;
2014-08-22 14:55:23 +00:00
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2015-12-08 19:07:50 +00:00
return true ;
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-08 19:07:50 +00:00
return false ;
}
2015-12-12 22:29:33 +00:00
const QString & fname ( ) const {
return _fname ;
}
const QString & lname ( ) const {
return _lname ;
}
const QString & phone ( ) const {
return _phone ;
}
2014-05-30 08:53:19 +00:00
private :
2015-12-12 22:29:33 +00:00
int32 _userId ;
UserData * _contact ;
int32 _phonew ;
QString _fname , _lname , _phone ;
Text _name ;
TextLinkPtr _linkl ;
int32 _linkw ;
QString _link ;
2014-05-30 08:53:19 +00:00
} ;
2015-04-04 20:01:34 +00:00
class HistoryWebPage : public HistoryMedia {
public :
HistoryWebPage ( WebPageData * data ) ;
2015-12-18 21:36:16 +00:00
HistoryWebPage ( const HistoryWebPage & other ) ;
2016-03-21 18:57:03 +00:00
HistoryMediaType type ( ) const override {
2015-12-19 18:09:24 +00:00
return MediaTypeWebPage ;
}
2016-03-21 18:57:03 +00:00
HistoryMedia * clone ( ) const override {
2015-12-19 18:09:24 +00:00
return new HistoryWebPage ( * this ) ;
}
2016-03-21 18:57:03 +00:00
void initDimensions ( const HistoryItem * parent ) override ;
int32 resize ( int32 width , const HistoryItem * parent ) override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
void draw ( Painter & p , const HistoryItem * parent , const QRect & r , bool selected , uint64 ms ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y , const HistoryItem * parent ) const override ;
2015-12-19 18:09:24 +00:00
2016-03-21 18:57:03 +00:00
const QString inDialogsText ( ) const override ;
const QString inHistoryText ( ) const override ;
2015-04-04 20:01:34 +00:00
2016-03-21 18:57:03 +00:00
void linkOver ( HistoryItem * parent , const TextLinkPtr & lnk ) override ;
void linkOut ( HistoryItem * parent , const TextLinkPtr & lnk ) override ;
2015-12-18 21:36:16 +00:00
2016-03-21 18:57:03 +00:00
bool isDisplayed ( ) const override {
2015-12-18 21:36:16 +00:00
return ! _data - > pendingTill ;
2015-05-20 19:28:24 +00:00
}
2016-03-21 18:57:03 +00:00
DocumentData * getDocument ( ) override {
2015-12-18 21:36:16 +00:00
return _attach ? _attach - > getDocument ( ) : 0 ;
}
2016-03-21 18:57:03 +00:00
ClipReader * getClipReader ( ) override {
2016-01-01 01:56:21 +00:00
return _attach ? _attach - > getClipReader ( ) : 0 ;
}
2016-03-19 16:55:15 +00:00
bool playInline ( HistoryItem * item , bool autoplay ) override {
return _attach ? _attach - > playInline ( item , autoplay ) : false ;
2015-12-18 21:36:16 +00:00
}
2016-03-19 16:55:15 +00:00
void stopInline ( HistoryItem * item ) override {
2015-12-18 21:36:16 +00:00
if ( _attach ) _attach - > stopInline ( item ) ;
}
2016-03-18 19:05:08 +00:00
void attachToItem ( HistoryItem * item ) override ;
void detachFromItem ( HistoryItem * item ) override ;
2015-04-04 20:01:34 +00:00
2016-03-21 18:57:03 +00:00
bool hasReplyPreview ( ) const override {
2015-12-18 21:36:16 +00:00
return ( _data - > photo & & ! _data - > photo - > thumb - > isNull ( ) ) | | ( _data - > doc & & ! _data - > doc - > thumb - > isNull ( ) ) ;
2015-04-04 20:01:34 +00:00
}
2016-03-21 18:57:03 +00:00
ImagePtr replyPreview ( ) override ;
2015-04-04 20:01:34 +00:00
2015-08-28 15:15:56 +00:00
WebPageData * webpage ( ) {
2015-12-18 21:36:16 +00:00
return _data ;
2015-08-28 15:15:56 +00:00
}
2016-03-21 18:57:03 +00:00
bool needsBubble ( const HistoryItem * parent ) const override {
2015-12-08 19:07:50 +00:00
return true ;
}
2016-03-21 18:57:03 +00:00
bool customInfoLayout ( ) const override {
2015-12-08 19:07:50 +00:00
return false ;
}
2015-12-27 21:37:48 +00:00
HistoryMedia * attach ( ) const {
return _attach ;
}
2015-12-31 15:27:21 +00:00
2015-12-27 21:37:48 +00:00
~ HistoryWebPage ( ) ;
2015-04-04 20:01:34 +00:00
private :
2015-12-18 21:36:16 +00:00
WebPageData * _data ;
TextLinkPtr _openl ;
HistoryMedia * _attach ;
2015-04-04 20:01:34 +00:00
bool _asArticle ;
2015-12-18 21:36:16 +00:00
int32 _titleLines , _descriptionLines ;
2015-04-04 20:01:34 +00:00
Text _title , _description ;
int32 _siteNameWidth ;
2015-12-18 21:36:16 +00:00
QString _duration ;
int32 _durationWidth ;
2015-04-04 20:01:34 +00:00
int16 _pixw , _pixh ;
} ;
2015-12-31 15:28:54 +00:00
void initImageLinkManager ( ) ;
void reinitImageLinkManager ( ) ;
void deinitImageLinkManager ( ) ;
2016-02-28 13:54:04 +00:00
struct LocationData {
LocationData ( const LocationCoords & coords ) : coords ( coords ) , loading ( false ) {
2015-12-31 15:28:54 +00:00
}
2016-02-28 13:54:04 +00:00
LocationCoords coords ;
2015-12-31 15:28:54 +00:00
ImagePtr thumb ;
bool loading ;
void load ( ) ;
} ;
2016-02-28 13:54:04 +00:00
class LocationManager : public QObject {
2015-12-31 15:28:54 +00:00
Q_OBJECT
public :
2016-02-28 13:54:04 +00:00
LocationManager ( ) : manager ( 0 ) , black ( 0 ) {
2015-12-31 15:28:54 +00:00
}
void init ( ) ;
void reinit ( ) ;
void deinit ( ) ;
2016-02-28 13:54:04 +00:00
void getData ( LocationData * data ) ;
2015-12-31 15:28:54 +00:00
2016-02-28 13:54:04 +00:00
~ LocationManager ( ) {
2015-12-31 15:28:54 +00:00
deinit ( ) ;
}
2016-02-28 13:54:04 +00:00
public slots :
2015-12-31 15:28:54 +00:00
void onFinished ( QNetworkReply * reply ) ;
void onFailed ( QNetworkReply * reply ) ;
private :
2016-02-28 13:54:04 +00:00
void failed ( LocationData * data ) ;
2015-12-31 15:28:54 +00:00
QNetworkAccessManager * manager ;
2016-02-28 13:54:04 +00:00
QMap < QNetworkReply * , LocationData * > dataLoadings , imageLoadings ;
QMap < LocationData * , int32 > serverRedirects ;
2015-12-31 15:28:54 +00:00
ImagePtr * black ;
} ;
2016-02-28 13:54:04 +00:00
class HistoryLocation : public HistoryMedia {
2014-11-12 20:18:00 +00:00
public :
2016-02-28 13:54:04 +00:00
HistoryLocation ( const LocationCoords & coords , const QString & title = QString ( ) , const QString & description = QString ( ) ) ;
2014-11-12 20:18:00 +00:00
HistoryMediaType type ( ) const {
2016-02-28 13:54:04 +00:00
return MediaTypeLocation ;
2014-11-12 20:18:00 +00:00
}
2015-12-19 18:09:24 +00:00
HistoryMedia * clone ( ) const {
2016-02-28 13:54:04 +00:00
return new HistoryLocation ( * this ) ;
2015-12-19 18:09:24 +00:00
}
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 20:18:00 +00:00
const QString inDialogsText ( ) const ;
2014-11-22 09:45:04 +00:00
const QString inHistoryText ( ) const ;
2014-11-12 20:18:00 +00:00
2015-04-11 10:04:10 +00:00
bool isImageLink ( ) const {
return true ;
}
2015-12-08 19:07:50 +00:00
bool needsBubble ( const HistoryItem * parent ) const {
2016-03-25 11:29:45 +00:00
return ! _title . isEmpty ( ) | | ! _description . isEmpty ( ) | | parent - > Has < HistoryMessageForwarded > ( ) | | parent - > Has < HistoryMessageReply > ( ) | | parent - > viaBot ( ) ;
2015-12-08 19:07:50 +00:00
}
2015-12-09 18:06:20 +00:00
bool customInfoLayout ( ) const {
2015-12-08 19:07:50 +00:00
return true ;
}
2014-11-12 20:18:00 +00:00
private :
2016-02-28 13:54:04 +00:00
LocationData * _data ;
2015-04-30 13:53:36 +00:00
Text _title , _description ;
2015-12-19 12:27:03 +00:00
TextLinkPtr _link ;
2014-11-18 12:41:33 +00:00
2015-12-19 18:09:24 +00:00
int32 fullWidth ( ) const ;
int32 fullHeight ( ) const ;
2014-11-12 20:18:00 +00:00
} ;
2015-12-31 15:27:21 +00: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-03-18 19:05:08 +00:00
class HistoryMessage : public HistoryItem , private HistoryItemInstantiated < HistoryMessage > {
2014-05-30 08:53:19 +00:00
public :
2016-03-18 19:05:08 +00:00
static HistoryMessage * create ( History * history , const MTPDmessage & msg ) {
return _create ( history , msg ) ;
}
2016-03-19 16:55:15 +00:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * fwd ) {
2016-03-18 19:05:08 +00:00
return _create ( history , msgId , flags , date , from , fwd ) ;
}
2016-03-25 11:29:45 +00:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , const QString & msg , const EntitiesInText & entities ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , msg , entities ) ;
2016-03-18 19:05:08 +00:00
}
2016-03-25 11:29:45 +00:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , doc , caption ) ;
2016-03-18 19:05:08 +00:00
}
2016-03-25 11:29:45 +00:00
static HistoryMessage * create ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) {
return _create ( history , msgId , flags , replyTo , viaBotId , date , from , photo , caption ) ;
2016-03-18 19:05:08 +00:00
}
2014-05-30 08:53:19 +00:00
2015-04-30 13:53:36 +00:00
void initTime ( ) ;
2015-08-30 14:57:21 +00:00
void initMedia ( const MTPMessageMedia * media , QString & currentText ) ;
2015-12-28 10:28:00 +00:00
void initMediaFromDocument ( DocumentData * doc , const QString & caption ) ;
2016-01-09 07:11:23 +00:00
void fromNameUpdated ( int32 width ) const ;
2014-05-30 08:53:19 +00:00
2015-12-09 18:06:20 +00:00
int32 plainMaxWidth ( ) const ;
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2015-12-09 19:09:29 +00:00
bool emptyText ( ) const {
2015-12-08 19:07:50 +00:00
return _text . isEmpty ( ) ;
}
bool drawBubble ( ) const {
2015-12-09 19:09:29 +00:00
return _media ? ( ! emptyText ( ) | | _media - > needsBubble ( this ) ) : true ;
2015-04-04 20:01:34 +00:00
}
2016-03-21 18:57:03 +00:00
bool hasBubble ( ) const override {
2015-12-09 18:06:20 +00:00
return drawBubble ( ) ;
}
2015-12-09 19:09:29 +00:00
bool displayFromName ( ) const {
2016-03-21 18:40:00 +00:00
if ( ! hasFromName ( ) ) return false ;
if ( isAttachedToPrevious ( ) ) return false ;
2016-03-25 11:29:45 +00:00
return ( ! emptyText ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | Has < HistoryMessageReply > ( ) | | Has < HistoryMessageForwarded > ( ) | | viaBot ( ) | | ! _media - > hideFromName ( ) ) ;
2015-12-09 19:09:29 +00:00
}
2015-12-24 19:26:28 +00:00
bool uploading ( ) const {
return _media & & _media - > uploading ( ) ;
}
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
void drawInfo ( Painter & p , int32 right , int32 bottom , int32 width , bool selected , InfoDisplayType type ) const override ;
void setViewsCount ( int32 count ) override ;
void setId ( MsgId newId ) override ;
2016-03-18 19:05:08 +00:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const override ;
2015-12-11 18:11:38 +00:00
2016-03-25 11:29:45 +00:00
void dependencyItemRemoved ( HistoryItem * dependency ) override ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
void destroy ( ) override ;
2016-01-03 01:43:42 +00:00
2016-03-21 18:57:03 +00:00
bool hasPoint ( int32 x , int32 y ) const override ;
bool pointInTime ( int32 right , int32 bottom , int32 x , int32 y , InfoDisplayType type ) const override ;
2015-05-14 16:50:04 +00:00
2016-03-21 18:57:03 +00:00
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const override ;
2015-05-14 16:50:04 +00:00
2016-03-21 18:57:03 +00:00
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const override ;
uint32 adjustSelection ( uint16 from , uint16 to , TextSelectType type ) const override {
2014-05-30 08:53:19 +00:00
return _text . adjustSelection ( from , to , type ) ;
}
2016-03-21 18:57:03 +00:00
void linkOver ( const TextLinkPtr & lnk ) override {
2015-12-11 18:11:38 +00:00
if ( _media ) _media - > linkOver ( this , lnk ) ;
}
2016-03-21 18:57:03 +00:00
void linkOut ( const TextLinkPtr & lnk ) override {
2015-12-11 18:11:38 +00:00
if ( _media ) _media - > linkOut ( this , lnk ) ;
}
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const override ;
QString notificationHeader ( ) const override ;
QString notificationText ( ) const override ;
2015-12-31 15:27:21 +00:00
2016-03-19 16:55:15 +00:00
void updateMedia ( const MTPMessageMedia * media , bool edited = false ) override {
2016-02-18 16:36:33 +00:00
if ( ! edited & & media & & _media & & _media - > type ( ) ! = MediaTypeWebPage ) {
2016-01-09 07:11:23 +00:00
_media - > updateFrom ( * media , this ) ;
2015-10-01 17:15:23 +00:00
} else {
2016-01-09 07:11:23 +00:00
setMedia ( media ) ;
2015-05-20 19:28:24 +00:00
}
2016-03-19 16:55:15 +00:00
setPendingInitDimensions ( ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-21 18:57:03 +00:00
int32 addToOverview ( AddToOverviewMethod method ) override ;
2016-01-03 01:43:42 +00:00
void eraseFromOverview ( ) ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
QString selectedText ( uint32 selection ) const override ;
QString inDialogsText ( ) const override ;
HistoryMedia * getMedia ( bool inOverview = false ) const override ;
2016-01-09 07:11:23 +00:00
void setMedia ( const MTPMessageMedia * media ) ;
2016-03-21 18:57:03 +00:00
void setText ( const QString & text , const EntitiesInText & entities ) override ;
QString originalText ( ) const override ;
EntitiesInText originalEntities ( ) const override ;
bool textHasLinks ( ) override ;
2014-05-30 08:53:19 +00:00
2016-03-21 18:57:03 +00:00
int32 infoWidth ( ) const override {
2015-09-13 17:27:29 +00:00
int32 result = _timeWidth ;
2016-02-17 16:37:21 +00:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-28 00:29:39 +00:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 08:50:54 +00:00
}
2016-02-17 16:37:21 +00:00
if ( out ( ) & & ! isPost ( ) ) {
2015-09-15 08:50:54 +00:00
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-13 17:27:29 +00:00
}
return result ;
2014-08-15 11:19:32 +00:00
}
2016-03-21 18:57:03 +00:00
int32 timeLeft ( ) const override {
2015-09-15 08:50:54 +00:00
int32 result = 0 ;
2016-02-17 16:37:21 +00:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
result + = st : : msgDateViewsSpace + views - > _viewsWidth + st : : msgDateCheckSpace + st : : msgViewsImg . pxWidth ( ) ;
2015-10-28 00:29:39 +00:00
} else if ( id < 0 & & history ( ) - > peer - > isSelf ( ) ) {
result + = st : : msgDateCheckSpace + st : : msgCheckImg . pxWidth ( ) ;
2015-09-15 08:50:54 +00:00
}
return result ;
}
2016-03-21 18:57:03 +00:00
int32 timeWidth ( ) const override {
2015-09-15 08:50:54 +00:00
return _timeWidth ;
}
2016-02-17 16:37:21 +00:00
2016-03-21 18:57:03 +00:00
int32 viewsCount ( ) const override {
2016-02-17 16:37:21 +00:00
if ( const HistoryMessageViews * views = Get < HistoryMessageViews > ( ) ) {
return views - > _views ;
}
return HistoryItem : : viewsCount ( ) ;
2015-09-15 08:50:54 +00:00
}
2014-08-15 11:19:32 +00:00
2016-03-25 11:29:45 +00:00
bool updateDependencyItem ( ) override {
if ( auto * reply = Get < HistoryMessageReply > ( ) ) {
return reply - > updateData ( this , true ) ;
}
return true ;
}
MsgId dependencyMsgId ( ) const override {
return replyToId ( ) ;
}
2016-03-21 18:57:03 +00:00
HistoryMessage * toHistoryMessage ( ) override { // dynamic_cast optimize
2015-04-13 08:58:13 +00:00
return this ;
}
2016-03-21 18:57:03 +00:00
const HistoryMessage * toHistoryMessage ( ) const override { // dynamic_cast optimize
2015-04-13 08:58:13 +00:00
return this ;
}
2016-03-22 19:43:47 +00:00
// hasFromPhoto() returns true even if we don't display the photo
// but we need to skip a place at the left side for this photo
bool displayFromPhoto ( ) const ;
bool hasFromPhoto ( ) const ;
2014-05-30 08:53:19 +00:00
~ HistoryMessage ( ) ;
protected :
2016-03-18 19:05:08 +00:00
HistoryMessage ( History * history , const MTPDmessage & msg ) ;
2016-03-19 16:55:15 +00:00
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , QDateTime date , int32 from , HistoryMessage * fwd ) ; // local forwarded
2016-03-25 11:29:45 +00:00
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , const QString & msg , const EntitiesInText & entities ) ; // local message
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , DocumentData * doc , const QString & caption ) ; // local document
HistoryMessage ( History * history , MsgId msgId , MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId , QDateTime date , int32 from , PhotoData * photo , const QString & caption ) ; // local photo
2016-03-18 19:05:08 +00:00
friend class HistoryItemInstantiated < HistoryMessage > ;
2016-03-19 16:55:15 +00:00
void initDimensions ( ) override ;
2016-03-21 18:40:00 +00:00
int resizeGetHeight_ ( int width ) override ;
2016-03-19 16:55:15 +00:00
2016-02-18 19:12:50 +00:00
bool displayForwardedFrom ( ) const {
if ( const HistoryMessageForwarded * fwd = Get < HistoryMessageForwarded > ( ) ) {
2016-03-25 11:29:45 +00:00
return Has < HistoryMessageVia > ( ) | | ! _media | | ! _media - > isDisplayed ( ) | | fwd - > _authorOriginal - > isChannel ( ) | | ! _media - > hideForwardedFrom ( ) ;
2016-02-18 19:12:50 +00:00
}
return false ;
}
2016-03-25 11:29:45 +00:00
void paintForwardedInfo ( Painter & p , QRect & trect , bool selected ) const ;
void paintReplyInfo ( Painter & p , QRect & trect , bool selected ) const ;
// this method draws "via @bot" if it is not painted in forwarded info or in from name
void paintViaBotIdInfo ( Painter & p , QRect & trect , bool selected ) const ;
2016-02-17 16:37:21 +00:00
2016-03-22 19:50:14 +00:00
Text _text = { int ( st : : msgMinWidth ) } ;
2014-05-30 08:53:19 +00:00
2016-03-22 19:43:47 +00:00
int _textWidth = 0 ;
int _textHeight = 0 ;
2014-05-30 08:53:19 +00:00
2016-03-22 19:43:47 +00:00
HistoryMedia * _media = nullptr ;
2015-09-15 08:50:54 +00:00
QString _timeText ;
2016-03-22 19:43:47 +00:00
int _timeWidth = 0 ;
2015-12-31 15:27:21 +00:00
2016-03-25 11:29:45 +00:00
void createInterfacesHelper ( MTPDmessage : : Flags flags , MsgId replyTo , int32 viaBotId ) ;
void createInterfaces ( MsgId replyTo , int32 viaBotId , int32 viewsCount , const PeerId & authorIdOriginal = 0 , const PeerId & fromIdOriginal = 0 , MsgId originalId = 0 ) ;
2015-03-19 09:18:19 +00:00
} ;
2016-03-19 16:55:15 +00:00
inline MTPDmessage : : Flags newMessageFlags ( PeerData * p ) {
MTPDmessage : : Flags result = 0 ;
if ( ! p - > isSelf ( ) ) {
result | = MTPDmessage : : Flag : : f_out ;
if ( p - > isChat ( ) | | ( p - > isUser ( ) & & ! p - > asUser ( ) - > botInfo ) ) {
result | = MTPDmessage : : Flag : : f_unread ;
}
}
return result ;
2016-01-11 04:45:07 +00:00
}
2016-03-19 16:55:15 +00:00
inline MTPDmessage : : Flags newForwardedFlags ( PeerData * p , int32 from , HistoryMessage * fwd ) {
MTPDmessage : : Flags result = newMessageFlags ( p ) ;
if ( from ) {
result | = MTPDmessage : : Flag : : f_from_id ;
}
2016-03-25 11:29:45 +00:00
if ( fwd - > Has < HistoryMessageVia > ( ) ) {
2016-03-19 16:55:15 +00:00
result | = MTPDmessage : : Flag : : f_via_bot_id ;
2016-02-12 16:35:06 +00:00
}
if ( ! p - > isChannel ( ) ) {
2016-02-18 19:12:50 +00:00
if ( HistoryMedia * media = fwd - > getMedia ( ) ) {
2016-02-12 16:35:06 +00:00
if ( media - > type ( ) = = MediaTypeVoiceFile ) {
2016-03-19 16:55:15 +00:00
result | = MTPDmessage : : Flag : : f_media_unread ;
2016-02-12 16:35:06 +00:00
// } else if (media->type() == MediaTypeVideo) {
// result |= MTPDmessage::flag_media_unread;
}
}
}
return result ;
2016-01-11 04:45:07 +00:00
}
2016-03-25 11:29:45 +00:00
struct HistoryServicePinned : public BaseComponent < HistoryServicePinned > {
HistoryServicePinned ( Composer * ) {
}
2016-03-05 21:12:55 +00:00
2016-03-25 11:29:45 +00:00
MsgId msgId = 0 ;
HistoryItem * msg = nullptr ;
2016-03-05 21:12:55 +00:00
TextLinkPtr lnk ;
} ;
2016-03-25 11:29:45 +00:00
class HistoryService : public HistoryItem , private HistoryItemInstantiated < HistoryService > {
2014-05-30 08:53:19 +00:00
public :
2016-03-25 11:29:45 +00:00
static HistoryService * create ( History * history , const MTPDmessageService & msg ) {
2016-03-18 19:05:08 +00:00
return _create ( history , msg ) ;
}
2016-03-25 11:29:45 +00:00
static HistoryService * create ( History * history , MsgId msgId , QDateTime date , const QString & msg , MTPDmessage : : Flags flags = 0 , HistoryMedia * media = 0 , int32 from = 0 ) {
2016-03-18 19:05:08 +00:00
return _create ( history , msgId , date , msg , flags , media , from ) ;
}
2014-05-30 08:53:19 +00:00
2016-03-05 21:12:55 +00:00
bool updateDependencyItem ( ) override {
return updatePinned ( true ) ;
}
MsgId dependencyMsgId ( ) const override {
if ( const HistoryServicePinned * pinned = Get < HistoryServicePinned > ( ) ) {
return pinned - > msgId ;
}
return 0 ;
}
2016-03-11 12:20:58 +00:00
bool notificationReady ( ) const override {
if ( const HistoryServicePinned * pinned = Get < HistoryServicePinned > ( ) ) {
return ( pinned - > msg | | ! pinned - > msgId ) ;
}
return true ;
}
2016-03-05 21:12:55 +00:00
2016-02-09 16:05:08 +00:00
void countPositionAndSize ( int32 & left , int32 & width ) const ;
2016-03-11 15:28:32 +00:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const override ;
bool hasPoint ( int32 x , int32 y ) const override ;
void getState ( TextLinkPtr & lnk , HistoryCursorState & state , int32 x , int32 y ) const override ;
void getSymbol ( uint16 & symbol , bool & after , bool & upon , int32 x , int32 y ) const override ;
uint32 adjustSelection ( uint16 from , uint16 to , TextSelectType type ) const override {
2014-05-30 08:53:19 +00:00
return _text . adjustSelection ( from , to , type ) ;
}
2016-03-11 15:28:32 +00:00
void linkOver ( const TextLinkPtr & lnk ) override {
2015-12-27 21:37:48 +00:00
if ( _media ) _media - > linkOver ( this , lnk ) ;
}
2016-03-11 15:28:32 +00:00
void linkOut ( const TextLinkPtr & lnk ) override {
2015-12-27 21:37:48 +00:00
if ( _media ) _media - > linkOut ( this , lnk ) ;
}
2016-03-11 15:28:32 +00:00
void drawInDialog ( Painter & p , const QRect & r , bool act , const HistoryItem * & cacheFor , Text & cache ) const override ;
QString notificationText ( ) const override ;
2014-06-14 19:32:11 +00:00
2016-03-11 15:28:32 +00:00
bool needCheck ( ) const override {
2014-05-30 08:53:19 +00:00
return false ;
}
2016-03-11 15:28:32 +00:00
bool serviceMsg ( ) const override {
2014-05-30 08:53:19 +00:00
return true ;
}
2016-03-11 15:28:32 +00:00
QString selectedText ( uint32 selection ) const override ;
QString inDialogsText ( ) const override ;
QString inReplyText ( ) const override ;
2014-05-30 08:53:19 +00:00
2016-03-11 15:28:32 +00:00
HistoryMedia * getMedia ( bool inOverview = false ) const override ;
2014-08-11 09:03:45 +00:00
2015-09-22 10:19:57 +00:00
void setServiceText ( const QString & text ) ;
2015-09-19 09:13:21 +00:00
2016-03-25 11:29:45 +00:00
~ HistoryService ( ) ;
2014-05-30 08:53:19 +00:00
protected :
2016-03-25 11:29:45 +00:00
HistoryService ( History * history , const MTPDmessageService & msg ) ;
HistoryService ( History * history , MsgId msgId , QDateTime date , const QString & msg , MTPDmessage : : Flags flags = 0 , HistoryMedia * media = 0 , int32 from = 0 ) ;
friend class HistoryItemInstantiated < HistoryService > ;
2016-03-18 19:05:08 +00:00
2016-03-19 16:55:15 +00:00
void initDimensions ( ) override ;
2016-03-21 18:40:00 +00:00
int resizeGetHeight_ ( int width ) override ;
2016-03-19 16:55:15 +00:00
2014-12-18 18:40:49 +00:00
void setMessageByAction ( const MTPmessageAction & action ) ;
2016-03-05 21:12:55 +00:00
bool updatePinned ( bool force = false ) ;
bool updatePinnedText ( const QString * pfrom = nullptr , QString * ptext = nullptr ) ;
2014-05-30 08:53:19 +00:00
2016-03-23 11:47:32 +00:00
Text _text = { int ( st : : msgMinWidth ) } ;
HistoryMedia * _media = nullptr ;
2014-05-30 08:53:19 +00:00
int32 _textWidth , _textHeight ;
} ;
2016-03-25 11:29:45 +00:00
class HistoryGroup : public HistoryService , private HistoryItemInstantiated < HistoryGroup > {
2014-05-30 08:53:19 +00:00
public :
2016-03-18 19:05:08 +00:00
static HistoryGroup * create ( History * history , const MTPDmessageGroup & group , const QDateTime & date ) {
return _create ( history , group , date ) ;
2014-05-30 08:53:19 +00:00
}
2016-03-18 19:05:08 +00:00
static HistoryGroup * create ( History * history , HistoryItem * newItem , const QDateTime & date ) {
return _create ( history , newItem , date ) ;
2015-09-19 09:13:21 +00: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 08:53:19 +00:00
}
2015-09-19 09:13:21 +00:00
QString selectedText ( uint32 selection ) const {
return QString ( ) ;
}
HistoryItemType type ( ) const {
return HistoryItemGroup ;
}
void uniteWith ( MsgId minId , MsgId maxId , int32 count ) ;
2015-09-20 08:55:41 +00:00
void uniteWith ( HistoryItem * item ) {
uniteWith ( item - > id - 1 , item - > id + 1 , 1 ) ;
}
void uniteWith ( HistoryGroup * other ) {
2015-09-19 09:13:21 +00: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 ;
}
2016-03-18 19:05:08 +00:00
protected :
HistoryGroup ( History * history , const MTPDmessageGroup & group , const QDateTime & date ) ;
HistoryGroup ( History * history , HistoryItem * newItem , const QDateTime & date ) ;
using HistoryItemInstantiated < HistoryGroup > : : _create ;
friend class HistoryItemInstantiated < HistoryGroup > ;
2015-09-19 09:13:21 +00:00
private :
MsgId _minId , _maxId ;
int32 _count ;
TextLinkPtr _lnk ;
void updateText ( ) ;
} ;
2016-03-25 11:29:45 +00:00
class HistoryCollapse : public HistoryService , private HistoryItemInstantiated < HistoryCollapse > {
2015-09-19 09:13:21 +00:00
public :
2016-03-18 19:05:08 +00:00
static HistoryCollapse * create ( History * history , MsgId wasMinId , const QDateTime & date ) {
return _create ( history , wasMinId , date ) ;
}
2015-12-11 18:11:38 +00:00
void draw ( Painter & p , const QRect & r , uint32 selection , uint64 ms ) const ;
2015-09-19 09:13:21 +00: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 ;
}
2016-03-18 19:05:08 +00:00
protected :
HistoryCollapse ( History * history , MsgId wasMinId , const QDateTime & date ) ;
using HistoryItemInstantiated < HistoryCollapse > : : _create ;
friend class HistoryItemInstantiated < HistoryCollapse > ;
2015-09-19 09:13:21 +00:00
private :
MsgId _wasMinId ;
2014-05-30 08:53:19 +00:00
} ;
2016-03-25 11:29:45 +00:00
class HistoryJoined : public HistoryService , private HistoryItemInstantiated < HistoryJoined > {
2015-09-21 20:57:42 +00:00
public :
2016-03-19 16:55:15 +00:00
static HistoryJoined * create ( History * history , const QDateTime & date , UserData * from , MTPDmessage : : Flags flags ) {
2016-03-18 19:05:08 +00:00
return _create ( history , date , from , flags ) ;
2015-09-21 20:57:42 +00:00
}
2014-05-30 08:53:19 +00:00
2015-09-19 09:13:21 +00:00
HistoryItemType type ( ) const {
2016-03-18 19:05:08 +00:00
return HistoryItemJoined ;
2014-05-30 08:53:19 +00:00
}
protected :
2016-03-19 16:55:15 +00:00
HistoryJoined ( History * history , const QDateTime & date , UserData * from , MTPDmessage : : Flags flags ) ;
2016-03-18 19:05:08 +00:00
using HistoryItemInstantiated < HistoryJoined > : : _create ;
friend class HistoryItemInstantiated < HistoryJoined > ;
2014-05-30 08:53:19 +00:00
} ;