SL-14270 Crash on participant's updateName
Session was deleted before viewer had a chance to create view for listener, so listener ended up not deleted and avaiting an uptade, then tryed to call for deleted session.master
parent
db161b6f85
commit
f86014ef15
|
|
@ -349,6 +349,20 @@ void LLConversationItemSession::clearParticipants()
|
|||
mNeedsRefresh = true;
|
||||
}
|
||||
|
||||
|
||||
void LLConversationItemSession::deleteParticipantModels()
|
||||
{
|
||||
// Make sure that no views exist before use and that view-owned items were removed!
|
||||
//
|
||||
// Normally we are not supposed to delete models directly, they should be
|
||||
// owned by views and this action will result in crashes, but LLParticipantList
|
||||
// creates models separately from views (it probably shouldn't) and then those
|
||||
// models wait for idle cycles to be assigned to view.
|
||||
// this code is meant to delete 'waiting' models
|
||||
std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id)
|
||||
{
|
||||
// This is *not* a general tree parsing algorithm. It assumes that a session contains only
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ public:
|
|||
void removeParticipant(LLConversationItemParticipant* participant);
|
||||
void removeParticipant(const LLUUID& participant_id);
|
||||
void clearParticipants();
|
||||
void deleteParticipantModels(); // do not use while there are existing participant views
|
||||
LLConversationItemParticipant* findParticipant(const LLUUID& participant_id);
|
||||
|
||||
void setParticipantIsMuted(const LLUUID& participant_id, bool is_muted);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,57 @@ LLConversationViewSession::~LLConversationViewSession()
|
|||
mFlashTimer->unset();
|
||||
}
|
||||
|
||||
void LLConversationViewSession::destroyView()
|
||||
{
|
||||
// Chat can create and parent models(listeners) to session's model before creating
|
||||
// coresponding views, such participant's models normally will wait for idle cycles
|
||||
// but since we are deleting session and won't be processing any more events, make
|
||||
// sure unowned models are removed as well.
|
||||
// Might be good idea to just have an LLPointer list somewhere in LLConversationItemSession
|
||||
|
||||
LLConversationItemSession* vmi = dynamic_cast<LLConversationItemSession*>(getViewModelItem());
|
||||
|
||||
// CONV_SESSION_1_ON_1 stores participants as two models that belong to views independent
|
||||
// from session (nasty! These views are widgets in LLFloaterIMSessionTab, see buildConversationViewParticipant)
|
||||
if (vmi && vmi->getType() != LLConversationItem::CONV_SESSION_1_ON_1)
|
||||
{
|
||||
// Destroy existing views
|
||||
while (!mItems.empty())
|
||||
{
|
||||
LLFolderViewItem *itemp = mItems.back();
|
||||
mItems.pop_back();
|
||||
|
||||
LLFolderViewModelItem* item_vmi = itemp->getViewModelItem();
|
||||
if (item_vmi) // supposed to exist
|
||||
{
|
||||
// unparent to remove from child list
|
||||
vmi->removeChild(item_vmi);
|
||||
}
|
||||
itemp->destroyView();
|
||||
}
|
||||
|
||||
// Not needed in scope of sessions, but just in case
|
||||
while (!mFolders.empty())
|
||||
{
|
||||
LLFolderViewFolder *folderp = mFolders.back();
|
||||
mFolders.pop_back();
|
||||
|
||||
LLFolderViewModelItem* folder_vmi = folderp->getViewModelItem();
|
||||
if (folder_vmi)
|
||||
{
|
||||
vmi->removeChild(folder_vmi);
|
||||
}
|
||||
folderp->destroyView();
|
||||
}
|
||||
|
||||
// Now everything that is left in model(listener) is unowned,
|
||||
// it is safe to remove
|
||||
vmi->deleteParticipantModels();
|
||||
}
|
||||
|
||||
LLFolderViewFolder::destroyView();
|
||||
}
|
||||
|
||||
void LLConversationViewSession::setFlashState(bool flash_state)
|
||||
{
|
||||
if (flash_state && !mFlashStateOn)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ protected:
|
|||
public:
|
||||
virtual ~LLConversationViewSession();
|
||||
|
||||
/*virtual*/ void destroyView();
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void draw();
|
||||
/*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask );
|
||||
|
|
|
|||
|
|
@ -1822,6 +1822,8 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
|
|||
{
|
||||
new_selection = mConversationsRoot->getPreviousFromChild(widget, FALSE);
|
||||
}
|
||||
|
||||
// Will destroy views and delete models that are not assigned to any views
|
||||
widget->destroyView();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -534,8 +534,7 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
|
|||
LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
|
||||
if (widget)
|
||||
{
|
||||
mConversationsRoot->extractItem(widget);
|
||||
delete widget;
|
||||
widget->destroyView();
|
||||
}
|
||||
mConversationsWidgets.erase(participant_id);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue