summaryrefslogtreecommitdiff
path: root/indra/newview/llinventorypanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llinventorypanel.cpp')
-rw-r--r--indra/newview/llinventorypanel.cpp182
1 files changed, 162 insertions, 20 deletions
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 74d9e895c2..09a94c1c09 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -282,17 +282,18 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
mInventory->addObserver(mCompletionObserver);
- if (mBuildViewsOnInit)
+ if (mBuildViewsOnInit && mViewsInitialized == VIEWS_UNINITIALIZED)
{
// Build view of inventory if we need default full hierarchy and inventory is ready, otherwise do in onIdle.
// Initializing views takes a while so always do it onIdle if viewer already loaded.
- if (mInventory->isInventoryUsable()
- && mViewsInitialized == VIEWS_UNINITIALIZED
+ if (mInventory->isInventoryUsable()
&& LLStartUp::getStartupState() <= STATE_WEARABLES_WAIT)
{
- initializeViews();
+ // Usually this happens on login, so we have less time constraits, but too long and we can cause a disconnect
+ const F64 max_time = 20.f;
+ initializeViews(max_time);
}
- else if (mViewsInitialized != VIEWS_INITIALIZING)
+ else
{
mViewsInitialized = VIEWS_INITIALIZING;
gIdleCallbacks.addFunction(onIdle, (void*)this);
@@ -497,6 +498,23 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
}
+ // if folder is not fully initialized (likely due to delayed load on idle)
+ // and we are not rebuilding, try updating children
+ if (view_folder
+ && !view_folder->areChildrenInited()
+ && ( (mask & LLInventoryObserver::REBUILD) == 0))
+ {
+ LLInventoryObject const* objectp = mInventory->getObject(item_id);
+ if (objectp)
+ {
+ // Time is low since we only need the item itself and children views.
+ // Any value bigger than zero will do to init children, everything else
+ // will be processed on idle.
+ const F64 max_time = 0.0001f;
+ view_item = buildNewViewsWithTimeLimit(item_id, objectp, view_item, max_time);
+ }
+ }
+
//////////////////////////////
// LABEL Operation
// Empty out the display name for relabel.
@@ -536,8 +554,13 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
LLInventoryObject const* objectp = mInventory->getObject(item_id);
if (objectp)
{
+ // Time is low since we only need the item itself and children views.
+ // Any value bigger than zero will do to init children, everything else
+ // will be processed on idle.
+ const F64 max_time = 0.0001f;
+
// providing NULL directly avoids unnessesary getItemByID calls
- view_item = buildNewViews(item_id, objectp, NULL);
+ view_item = buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time);
}
else
{
@@ -589,8 +612,13 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve
LLInventoryObject const* objectp = mInventory->getObject(item_id);
if (objectp)
{
+ // Time is low since we only need the item itself and children views.
+ // Any value bigger than zero will do to init children, everything else
+ // will be processed on idle.
+ const F64 max_time = 0.0001f;
+
// providing NULL directly avoids unnessesary getItemByID calls
- buildNewViews(item_id, objectp, NULL);
+ buildNewViewsWithTimeLimit(item_id, objectp, NULL, max_time);
}
// Select any newly created object that has the auto rename at top of folder root set.
@@ -742,12 +770,12 @@ void LLInventoryPanel::onIdle(void *userdata)
return;
LLInventoryPanel *self = (LLInventoryPanel*)userdata;
- // Inventory just initialized, do complete build
- if (self->mViewsInitialized != VIEWS_INITIALIZED)
+ if (self->mViewsInitialized <= VIEWS_INITIALIZING)
{
- self->initializeViews();
+ const F64 max_time = 0.001f; // 1 ms, in this case we need only root folders
+ self->initializeViews(max_time); // Shedules LLInventoryPanel::idle()
}
- if (self->mViewsInitialized == VIEWS_INITIALIZED)
+ if (self->mViewsInitialized >= VIEWS_BUILDING)
{
gIdleCallbacks.deleteFunction(onIdle, (void*)self);
}
@@ -782,6 +810,49 @@ void LLInventoryPanel::idle(void* user_data)
}
+ bool in_visible_chain = panel->isInVisibleChain();
+
+ if (!panel->mBuildViewsQueue.empty())
+ {
+ const F64 max_time = in_visible_chain ? 0.006f : 0.001f; // 6 ms
+ F64 curent_time = LLTimer::getTotalSeconds();
+ panel->mBuildViewsEndTime = curent_time + max_time;
+
+ // things added last are closer to root thus of higher priority
+ std::deque<LLUUID> priority_list;
+ priority_list.swap(panel->mBuildViewsQueue);
+
+ while (curent_time < panel->mBuildViewsEndTime
+ && !priority_list.empty())
+ {
+ LLUUID item_id = priority_list.back();
+ priority_list.pop_back();
+
+ LLInventoryObject const* objectp = panel->mInventory->getObject(item_id);
+ if (objectp && panel->typedViewsFilter(item_id, objectp))
+ {
+ LLFolderViewItem* folder_view_item = panel->getItemByID(item_id);
+ if (!folder_view_item || !folder_view_item->areChildrenInited())
+ {
+ const LLUUID &parent_id = objectp->getParentUUID();
+ LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)panel->getItemByID(parent_id);
+ panel->buildViewsTree(item_id, parent_id, objectp, folder_view_item, parent_folder);
+ }
+ }
+ curent_time = LLTimer::getTotalSeconds();
+ }
+ while (!priority_list.empty())
+ {
+ // items in priority_list are of higher priority
+ panel->mBuildViewsQueue.push_back(priority_list.front());
+ priority_list.pop_front();
+ }
+ if (panel->mBuildViewsQueue.empty())
+ {
+ panel->mViewsInitialized = VIEWS_INITIALIZED;
+ }
+ }
+
// Take into account the fact that the root folder might be invalidated
if (panel->mFolderRoot.get())
{
@@ -812,10 +883,16 @@ void LLInventoryPanel::idle(void* user_data)
}
-void LLInventoryPanel::initializeViews()
+void LLInventoryPanel::initializeViews(F64 max_time)
{
if (!gInventory.isInventoryUsable()) return;
+ mViewsInitialized = VIEWS_BUILDING;
+
+ F64 curent_time = LLTimer::getTotalSeconds();
+ mBuildViewsEndTime = curent_time + max_time;
+
+ // init everything
LLUUID root_id = getRootFolderID();
if (root_id.notNull())
{
@@ -823,14 +900,18 @@ void LLInventoryPanel::initializeViews()
}
else
{
- // Default case: always add "My Inventory" first, "Library" second
+ // Default case: always add "My Inventory" root first, "Library" root second
+ // If we run out of time, this still should create root folders
buildNewViews(gInventory.getRootFolderID()); // My Inventory
buildNewViews(gInventory.getLibraryRootFolderID()); // Library
}
- gIdleCallbacks.addFunction(idle, this);
+ if (mBuildViewsQueue.empty())
+ {
+ mViewsInitialized = VIEWS_INITIALIZED;
+ }
- mViewsInitialized = VIEWS_INITIALIZED;
+ gIdleCallbacks.addFunction(idle, this);
openStartFolderOrMyInventory();
@@ -930,6 +1011,12 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id, LLInventoryO
return buildViewsTree(id, parent_id, objectp, folder_view_item, parent_folder);
}
+LLFolderViewItem* LLInventoryPanel::buildNewViewsWithTimeLimit(const LLUUID& id, LLInventoryObject const* objectp, LLFolderViewItem *folder_view_item, F64 max_time)
+{
+ mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time;
+ return buildNewViews(id, objectp, folder_view_item);
+}
+
LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
const LLUUID& parent_id,
LLInventoryObject const* objectp,
@@ -1035,9 +1122,33 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
}
}
+ bool create_children = folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY;
+
+ if (create_children)
+ {
+ F64 curent_time = LLTimer::getTotalSeconds();
+ // If function is out of time, we want to shedule it into mBuildViewsQueue
+ // If we have time, no matter how little, create views for all children
+ //
+ // This creates children in 'bulk' to make sure folder has either
+ // 'empty and incomplete' or 'complete' states with nothing in between.
+ // Folders are marked as mIsFolderComplete == false by default,
+ // later arrange() will update mIsFolderComplete by child count
+ if (mBuildViewsEndTime < curent_time)
+ {
+ create_children = false;
+ // run it again for the sake of creating children
+ mBuildViewsQueue.push_back(id);
+ }
+ else if (folder_view_item)
+ {
+ folder_view_item->setChildrenInited(true);
+ }
+ }
+
// If this is a folder, add the children of the folder and recursively add any
// child folders.
- if (folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY)
+ if (create_children)
{
LLViewerInventoryCategory::cat_array_t* categories;
LLViewerInventoryItem::item_array_t* items;
@@ -1053,7 +1164,7 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
++cat_iter)
{
const LLViewerInventoryCategory* cat = (*cat_iter);
- if (typedViewsFilter(cat->getUUID(), cat))
+ if (typedViewsFilter(cat->getUUID(), cat))
{
if (has_folders)
{
@@ -1077,17 +1188,16 @@ LLFolderViewItem* LLInventoryPanel::buildViewsTree(const LLUUID& id,
item_iter != items->end();
++item_iter)
{
+ // At the moment we have to build folder's items in bulk and ignore mBuildViewsEndTime
const LLViewerInventoryItem* item = (*item_iter);
if (typedViewsFilter(item->getUUID(), item))
{
-
// This can be optimized: we don't need to call getItemByID()
// each time, especially since content is growing, we can just
// iter over copy of mItemMap in some way
LLFolderViewItem* view_itemp = getItemByID(item->getUUID());
buildViewsTree(item->getUUID(), id, item, view_itemp, parentp);
}
-
}
}
mInventory->unlockDirectDescendentArrays(id);
@@ -1200,6 +1310,18 @@ void LLInventoryPanel::onFocusReceived()
LLPanel::onFocusReceived();
}
+void LLInventoryPanel::onFolderOpening(const LLUUID &id)
+{
+ LLFolderViewItem* folder = getItemByID(id);
+ if (folder && !folder->areChildrenInited())
+ {
+ // Last item in list will be processed first.
+ // This might result in dupplicates in list, but it
+ // isn't critical, views won't be created twice
+ mBuildViewsQueue.push_back(id);
+ }
+}
+
bool LLInventoryPanel::addBadge(LLBadge * badge)
{
bool badge_added = false;
@@ -1221,7 +1343,7 @@ void LLInventoryPanel::openAllFolders()
void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus)
{
// Don't select objects in COF (e.g. to prevent refocus when items are worn).
- const LLInventoryObject *obj = gInventory.getObject(obj_id);
+ const LLInventoryObject *obj = mInventory->getObject(obj_id);
if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())
{
return;
@@ -1257,6 +1379,12 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it
if (view_model)
{
LLUUID id = view_model->getUUID();
+ if (!(*it)->areChildrenInited())
+ {
+ const F64 max_time = 0.0001f;
+ mBuildViewsEndTime = LLTimer::getTotalSeconds() + max_time;
+ buildNewViews(id);
+ }
LLViewerInventoryItem* inv_item = mInventory->getItem(id);
if (inv_item && !inv_item->isFinished())
@@ -1714,6 +1842,20 @@ LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id)
void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus )
{
LLFolderViewItem* itemp = getItemByID(obj_id);
+
+ if (itemp && !itemp->areChildrenInited())
+ {
+ LLInventoryObject const* objectp = mInventory->getObject(obj_id);
+ if (objectp)
+ {
+ // Time is low since we only need the item itself and children views.
+ // Any value bigger than zero will do to init children, everything else
+ // will be processed on idle.
+ const F64 max_time = 0.0001f;
+ buildNewViewsWithTimeLimit(obj_id, objectp, itemp, max_time);
+ }
+ }
+
if(itemp && itemp->getViewModelItem())
{
itemp->arrangeAndSet(TRUE, take_keyboard_focus);