diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index bf77067227..ba272f67f1 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -34,6 +34,7 @@ #include "llfolderview.h" #include "llfolderviewmodel.h" #include "llpanel.h" +#include "llcallbacklist.h" #include "llcriticaldamp.h" #include "llclipboard.h" #include "llfocusmgr.h" // gFocusMgr @@ -1959,7 +1960,12 @@ void LLFolderViewFolder::setOpen(BOOL openitem) { if(mSingleFolderMode) { - getViewModelItem()->navigateToFolder(); + // navigateToFolder can destroy this view + // delay it in case setOpen was called from click or key processing + doOnIdleOneTime([this]() + { + getViewModelItem()->navigateToFolder(); + }); } else { @@ -2189,7 +2195,19 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) if(mSingleFolderMode) { static LLUICachedControl double_click_new_window("SingleModeDoubleClickOpenWindow", false); - getViewModelItem()->navigateToFolder(double_click_new_window); + if (double_click_new_window) + { + getViewModelItem()->navigateToFolder(true); + } + else + { + // navigating is going to destroy views and change children + // delay it untill handleDoubleClick processing is complete + doOnIdleOneTime([this]() + { + getViewModelItem()->navigateToFolder(false); + }); + } return TRUE; } diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 22b93d4cda..a4ae039c76 100644 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -708,8 +708,12 @@ void AISAPI::FetchCOF(completion_t callback) // _6 -> httpHeaders (&LLCoreHttpUtil::HttpCoroutineAdapter::getAndSuspend), _1, _2, _3, _5, _6); + LLSD body; + // Only cof folder will be full, but cof can contain an outfit + // link with embedded outfit folder for request to parse + body["depth"] = 0; LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro, - _1, getFn, url, LLUUID::null, LLSD(), callback, FETCHCOF)); + _1, getFn, url, LLUUID::null, body, callback, FETCHCOF)); EnqueueAISCommand("FetchCOF", proc); } @@ -1268,7 +1272,6 @@ void AISUpdate::parseItem(const LLSD& item_map) if (mFetch) { mItemsCreated[item_id] = new_item; - mCatDescendentDeltas[new_item->getParentUUID()]; new_item->setComplete(true); if (new_item->getParentUUID().isNull()) @@ -1322,7 +1325,6 @@ void AISUpdate::parseLink(const LLSD& link_map, S32 depth) new_link->setSaleInfo(default_sale_info); //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; mItemsCreated[item_id] = new_link; - mCatDescendentDeltas[parent_id]; new_link->setComplete(true); if (new_link->getParentUUID().isNull()) @@ -1379,6 +1381,7 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) if (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN + && curr_cat->getDescendentCount() != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN && version > LLViewerInventoryCategory::VERSION_UNKNOWN && version < curr_cat->getVersion()) { @@ -1418,17 +1421,6 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) { if (mFetch) { - // set version only if previous one was already known - // or if we are sure this update has full data and embeded items (depth 0+) - // since bulk fetch uses this to decide what still needs fetching - if (version > LLViewerInventoryCategory::VERSION_UNKNOWN - && (depth >= 0 || (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN))) - { - // Set version/descendents for newly fetched categories. - LL_DEBUGS("Inventory") << "Setting version to " << version - << " for category " << category_id << LL_ENDL; - new_cat->setVersion(version); - } uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); if (mCatDescendentsKnown.end() != lookup_it) { @@ -1436,9 +1428,28 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count << " for category " << category_id << LL_ENDL; new_cat->setDescendentCount(descendent_count); + + // set version only if we are sure this update has full data and embeded items + // since viewer uses version to decide if folder and content still need fetching + if (version > LLViewerInventoryCategory::VERSION_UNKNOWN + && (depth >= 0 || (curr_cat && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN))) + { + LL_DEBUGS("Inventory") << "Setting version to " << version + << " for category " << category_id << LL_ENDL; + new_cat->setVersion(version); + } + } + else if (curr_cat + && curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN + && version > curr_cat->getVersion()) + { + // Potentially should new_cat->setVersion(unknown) here, + // but might be waiting for a callback that would increment + LL_DEBUGS("Inventory") << "Category " << category_id + << " is stale. Known version: " << curr_cat->getVersion() + << " server version: " << version << LL_ENDL; } mCategoriesCreated[category_id] = new_cat; - mCatDescendentDeltas[new_cat->getParentUUID()]; } else if (curr_cat) { @@ -1453,20 +1464,22 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) else { // Set version/descendents for newly created categories. - if (category_map.has("version")) - { - S32 version = category_map["version"].asInteger(); - LL_DEBUGS("Inventory") << "Setting version to " << version - << " for new category " << category_id << LL_ENDL; - new_cat->setVersion(version); - } - uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); - if (mCatDescendentsKnown.end() != lookup_it) - { - S32 descendent_count = lookup_it->second; - LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count - << " for new category " << category_id << LL_ENDL; - new_cat->setDescendentCount(descendent_count); + uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); + if (mCatDescendentsKnown.end() != lookup_it) + { + S32 descendent_count = lookup_it->second; + LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count + << " for new category " << category_id << LL_ENDL; + new_cat->setDescendentCount(descendent_count); + + // Don't set version unles correct children count is present + if (category_map.has("version")) + { + S32 version = category_map["version"].asInteger(); + LL_DEBUGS("Inventory") << "Setting version to " << version + << " for new category " << category_id << LL_ENDL; + new_cat->setVersion(version); + } } mCategoriesCreated[category_id] = new_cat; mCatDescendentDeltas[new_cat->getParentUUID()]++; @@ -1487,15 +1500,26 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth) void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded) { - // We can only determine true descendent count if this contains all descendent types. - if (embedded.has("categories") && - embedded.has("links") && - embedded.has("items")) - { - mCatDescendentsKnown[category_id] = embedded["categories"].size(); - mCatDescendentsKnown[category_id] += embedded["links"].size(); - mCatDescendentsKnown[category_id] += embedded["items"].size(); - } + if (mType == AISAPI::FETCHCOF) + { + // contains only links + if (embedded.has("links")) + { + mCatDescendentsKnown[category_id] = embedded["links"].size(); + } + } + else + { + // We can only determine true descendent count if this contains all descendent types. + if (embedded.has("categories") && + embedded.has("links") && + embedded.has("items")) + { + mCatDescendentsKnown[category_id] = embedded["categories"].size(); + mCatDescendentsKnown[category_id] += embedded["links"].size(); + mCatDescendentsKnown[category_id] += embedded["items"].size(); + } + } } void AISUpdate::parseEmbedded(const LLSD& embedded, S32 depth) diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index bc689ab050..8323d7a2c2 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -4239,7 +4239,7 @@ void LLAppearanceMgr::serverAppearanceUpdateCoro(LLCoreHttpUtil::HttpCoroutineAd if (cofVersion == LLViewerInventoryCategory::VERSION_UNKNOWN) { - LL_WARNS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL; + LL_INFOS("AVatar") << "COF version is unknown... not requesting until COF version is known." << LL_ENDL; return; } else diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index e80bc3fe7a..f54315ac5e 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -304,6 +304,12 @@ void LLAttachmentsMgr::linkRecentlyArrivedAttachments() return; } + if (LLAppearanceMgr::instance().getCOFVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // Wait for cof to load + return; + } + LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size() << " recently arrived items" << LL_ENDL; diff --git a/indra/newview/llfloaterchangeitemthumbnail.cpp b/indra/newview/llfloaterchangeitemthumbnail.cpp index 66a12113bb..f22cb5d084 100644 --- a/indra/newview/llfloaterchangeitemthumbnail.cpp +++ b/indra/newview/llfloaterchangeitemthumbnail.cpp @@ -547,12 +547,21 @@ struct ImageLoadedData LLUUID mThumbnailId; LLUUID mObjectId; LLHandle mFloaterHandle; + bool mSilent; }; void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id, bool silent) { LLPointer texturep = LLViewerTextureManager::getFetchedTexture(asset_id); - if (texturep->getFullWidth() == 0 && !texturep->isFullyLoaded() && !texturep->isMissingAsset()) + if (texturep->isMissingAsset()) + { + LL_WARNS() << "Attempted to assign missing asset " << asset_id << LL_ENDL; + if (!silent) + { + LLNotificationsUtil::add("ThumbnailDimentionsLimit"); + } + } + else if (texturep->getFullWidth() == 0) { if (silent) { @@ -567,9 +576,10 @@ void LLFloaterChangeItemThumbnail::assignAndValidateAsset(const LLUUID &asset_id data->mObjectId = mItemId; data->mThumbnailId = asset_id; data->mFloaterHandle = getHandle(); + data->mSilent = silent; texturep->setLoadedCallback(onImageLoaded, - MAX_DISCARD_LEVEL, // don't actually need max one, 3 or 4 should be enough + MAX_DISCARD_LEVEL, // Don't need full image, just size data FALSE, FALSE, (void*)data, @@ -649,16 +659,20 @@ void LLFloaterChangeItemThumbnail::onImageLoaded( { setThumbnailId(data->mThumbnailId, data->mObjectId); } - - // Update floater - if (!data->mFloaterHandle.isDead()) + else if (!data->mSilent) { - LLFloaterChangeItemThumbnail* self = static_cast(data->mFloaterHandle.get()); - if (self && self->mExpectingAssetId == data->mThumbnailId) - { - LLNotificationsUtil::add("ThumbnailDimentionsLimit"); - self->mExpectingAssetId = LLUUID::null; - } + // Should this only appear if floater is alive? + LLNotificationsUtil::add("ThumbnailDimentionsLimit"); + } + } + + // Update floater + if (!data->mSilent && !data->mFloaterHandle.isDead()) + { + LLFloaterChangeItemThumbnail* self = static_cast(data->mFloaterHandle.get()); + if (self && self->mExpectingAssetId == data->mThumbnailId) + { + self->mExpectingAssetId = LLUUID::null; } } diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index d88f325a38..55e2b7a2cf 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2382,6 +2382,9 @@ void LLInventoryGalleryItem::setSelected(bool value) BOOL LLInventoryGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask) { + // call changeItemSelection directly, before setFocus + // to avoid autoscroll from LLInventoryGallery::onFocusReceived() + mGallery->changeItemSelection(mUUID, false); setFocus(TRUE); mGallery->claimEditHandler(); @@ -2452,7 +2455,19 @@ BOOL LLInventoryGalleryItem::handleDoubleClick(S32 x, S32 y, MASK mask) { if (mIsFolder && mGallery) { - mGallery->setRootFolder(mUUID); + // setRootFolder can destroy this item. + // Delay it until handleDoubleClick processing is complete + // or make gallery handle doubleclicks. + LLHandle handle = mGallery->getHandle(); + LLUUID navigate_to = mUUID; + doOnIdleOneTime([handle, navigate_to]() + { + LLInventoryGallery* gallery = (LLInventoryGallery*)handle.get(); + if (gallery) + { + gallery->setRootFolder(navigate_to); + } + }); } else { diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c1c24397b2..efcff2e58e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -4083,29 +4083,36 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); if(folderp) { - if(tfolder->getParentUUID() == folderp->getParentUUID()) - { + if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + if (tfolder->getParentUUID() == folderp->getParentUUID()) + { // [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Added: RLVa-1.2.0e - // NOTE-RLVa: not sure if this is a hack or a bug-fix :o - // -> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain - // the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the - // viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server - // -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues - // -> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem - // to be any way to accomplish that either *sighs* - if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) && - ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) ) - { - tfolder->rename(folderp->getName()); - } + // NOTE-RLVa: not sure if this is a hack or a bug-fix :o + // -> if we rename the folder on the first BulkUpdateInventory message subsequent messages will still contain + // the old folder name and gInventory.updateCategory() below will "undo" the folder name change but on the + // viewer-side *only* so the folder name actually becomes out of sync with what's on the inventory server + // -> so instead we keep the name of the existing folder and only do it for #RLV/~ in case this causes issues + // -> a better solution would be to only do the rename *after* the transaction completes but there doesn't seem + // to be any way to accomplish that either *sighs* + if ( (rlv_handler_t::isEnabled()) && (!folderp->getName().empty()) && (tfolder->getName() != folderp->getName()) && + ((tfolder->getName().find(RLV_PUTINV_PREFIX) == 0)) ) + { + tfolder->rename(folderp->getName()); + } // [/RLVa:KB] - update[tfolder->getParentUUID()]; - } - else - { - ++update[tfolder->getParentUUID()]; - --update[folderp->getParentUUID()]; - } + update[tfolder->getParentUUID()]; + } + else + { + ++update[tfolder->getParentUUID()]; + --update[folderp->getParentUUID()]; + } + } + else + { + folderp->fetch(); + } } else { @@ -4115,7 +4122,14 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) folderp = gInventory.getCategory(tfolder->getParentUUID()); if(folderp) { - ++update[tfolder->getParentUUID()]; + if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + ++update[tfolder->getParentUUID()]; + } + else + { + folderp->fetch(); + } } } } @@ -4161,7 +4175,14 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID()); if(folderp) { - ++update[titem->getParentUUID()]; + if (folderp->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + ++update[titem->getParentUUID()]; + } + else + { + folderp->fetch(); + } } } } diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index f6e5b96d73..29144698f8 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -485,7 +485,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item) } // Not yet supported for task inventories - mChangeThumbnailBtn->setEnabled(mObjectID.isNull()); + mChangeThumbnailBtn->setEnabled(mObjectID.isNull() && ALEXANDRIA_LINDEN_ID != perm.getOwner()); //////////// // ORIGIN // diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 84470fe8ba..4970fe4c01 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -300,7 +300,7 @@ static bool mLoginStatePastUI = false; static bool mBenefitsSuccessfullyInit = false; const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds -const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN = 3; // Give region 3 chances +const S32 MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT = 4; // Give region 4 chances std::unique_ptr LLStartUp::sStateWatcher(new LLEventStream("StartupState")); std::unique_ptr LLStartUp::sListener(new LLStartupListener()); @@ -2074,11 +2074,18 @@ bool idle_startup() else { U32 num_retries = regionp->getNumSeedCapRetries(); - if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN) + if (num_retries > MAX_SEED_CAP_ATTEMPTS_BEFORE_ABORT) { - // Region will keep trying to get capabilities, - // but for now continue as if caps were granted - LLStartUp::setStartupState(STATE_SEED_CAP_GRANTED); + LL_WARNS("AppInit") << "Failed to get capabilities. Backing up to login screen!" << LL_ENDL; + if (gRememberPassword) + { + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + } + else + { + LLNotificationsUtil::add("LoginPacketNeverReceivedNoTP", LLSD(), LLSD(), login_alert_status); + } + reset_login(); } else if (num_retries > 0) { diff --git a/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml index 533b4f5593..c984dbe5f7 100644 --- a/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml +++ b/indra/newview/skins/default/xui/en/floater_change_item_thumbnail.xml @@ -54,7 +54,6 @@