From d4f5b71434ba8a6fea622d63a0f224a663181eea Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 16 Jun 2016 13:56:12 +0300 Subject: [PATCH 01/13] MAINT-6495 Problem with saving notecard embedded in object --- indra/newview/llpreviewnotecard.cpp | 19 ++++++++++++++++++- indra/newview/llpreviewnotecard.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index ba9845ef04..510d91839d 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -437,6 +437,23 @@ void LLPreviewNotecard::finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, } } +void LLPreviewNotecard::finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId) +{ + + LLSD floater_key; + floater_key["taskid"] = taskId; + floater_key["itemid"] = itemId; + LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance("preview_notecard", floater_key); + if (nc) + { + if (nc->hasEmbeddedInventory()) + { + gVFS->removeFile(newAssetId, LLAssetType::AT_NOTECARD); + } + nc->setAssetId(newAssetId); + nc->refreshFromInventory(); + } +} bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) { @@ -485,7 +502,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) else if (!mObjectUUID.isNull() && !task_url.empty()) { uploadInfo = LLResourceUploadInfo::ptr_t(new LLBufferedAssetUploadInfo(mObjectUUID, mItemUUID, LLAssetType::AT_NOTECARD, buffer, - boost::bind(&LLPreviewNotecard::finishInventoryUpload, _1, _3, LLUUID::null))); + boost::bind(&LLPreviewNotecard::finishTaskUpload, _1, _3, mObjectUUID))); url = task_url; } diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index ba571995f6..017c4485ba 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -96,6 +96,7 @@ protected: bool handleConfirmDeleteDialog(const LLSD& notification, const LLSD& response); static void finishInventoryUpload(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId); + static void finishTaskUpload(LLUUID itemId, LLUUID newAssetId, LLUUID taskId); protected: LLViewerTextEditor* mEditor; From aff8dcea758b4f31e320fb02369df97498e10c8b Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 16 Jun 2016 20:46:53 +0300 Subject: [PATCH 02/13] MAINT-85 Using mouse scroll while renaming item moves it out of My Inventory tab --- indra/llui/llfolderview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 89fef2a7c3..f9664e0658 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -684,9 +684,10 @@ void LLFolderView::draw() } } - if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().contains(mRenamer->getRect())) + if (mRenameItem && mRenamer && mRenamer->getVisible() && !getVisibleRect().overlaps(mRenamer->getRect())) { // renamer is not connected to the item we are renaming in any form so manage it manually + // TODO: consider stopping on any scroll action instead of when out of visible area finishRenamingItem(); } From 2b287b6bf7313100c78cc7c6186654e832c1887f Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine Date: Thu, 16 Jun 2016 23:27:39 +0300 Subject: [PATCH 03/13] MAINT-6511 Added a null check in LLFloaterView::restoreAll --- indra/llui/llfloater.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 5ea9f5b6cc..69038a8627 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -2321,7 +2321,10 @@ void LLFloaterView::restoreAll() for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { LLFloater* floaterp = (LLFloater*)*child_it; - floaterp->setMinimized(FALSE); + if (floaterp) + { + floaterp->setMinimized(FALSE); + } } // *FIX: make sure dependents are restored From 373947aba36e45f2496975d2cc7c4c9f4b2c205e Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 17 Jun 2016 12:07:16 +0300 Subject: [PATCH 04/13] MAINT-6509 Viewer still allows you to create a group with leading spaces in the group name --- indra/llui/lltextvalidate.cpp | 9 +++++++++ indra/llui/lltextvalidate.h | 1 + indra/newview/llpanelgroupgeneral.cpp | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp index 324ceb7fba..bfe0a5bb5d 100644 --- a/indra/llui/lltextvalidate.cpp +++ b/indra/llui/lltextvalidate.cpp @@ -328,6 +328,15 @@ namespace LLTextValidate return rv; } + bool validateASCIINoLeadingSpace(const LLWString &str) + { + if (LLStringOps::isSpace(str[0])) + { + return FALSE; + } + return validateASCII(str); + } + // Used for multiline text stored on the server. // Example is landmark description in Places SP. bool validateASCIIWithNewLine(const LLWString &str) diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h index 5c830d7db3..e2b6c313d6 100644 --- a/indra/llui/lltextvalidate.h +++ b/indra/llui/lltextvalidate.h @@ -52,6 +52,7 @@ namespace LLTextValidate bool validateASCIIPrintableNoPipe(const LLWString &str); bool validateASCIIPrintableNoSpace(const LLWString &str); bool validateASCII(const LLWString &str); + bool validateASCIINoLeadingSpace(const LLWString &str); bool validateASCIIWithNewLine(const LLWString &str); } diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index b2164c1f21..d17f5494a0 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -199,7 +199,7 @@ void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group) mGroupNameEditor = panel_group->getChild("group_name_editor"); - mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCII ); + mGroupNameEditor->setPrevalidate( LLTextValidate::validateASCIINoLeadingSpace ); } From 27bcc5f06e74257bd21ba207777f8fff45224e18 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 21 Jun 2016 13:13:10 +0300 Subject: [PATCH 05/13] MAINT-6497 FIXED land buy disqualification missing warning icon --- indra/newview/llfloatersellland.cpp | 3 +-- indra/newview/llviewchildren.cpp | 5 +++-- indra/newview/skins/default/textures/textures.xml | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 0cb37dabe7..b139e5daf5 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -257,7 +257,6 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge) static std::string badgeOK("badge_ok.j2c"); static std::string badgeNote("badge_note.j2c"); static std::string badgeWarn("badge_warn.j2c"); - static std::string badgeError("badge_error.j2c"); std::string badgeName; switch (badge) @@ -266,7 +265,7 @@ void LLFloaterSellLandUI::setBadge(const char* id, Badge badge) case BADGE_OK: badgeName = badgeOK; break; case BADGE_NOTE: badgeName = badgeNote; break; case BADGE_WARN: badgeName = badgeWarn; break; - case BADGE_ERROR: badgeName = badgeError; break; + case BADGE_ERROR: badgeName = badgeWarn; break; } getChild(id)->setValue(badgeName); diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 5c5bbdc8f5..32b2f7e9f5 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -79,8 +79,9 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible) default: case BADGE_OK: child->setValue(std::string("badge_ok.j2c")); break; case BADGE_NOTE: child->setValue(std::string("badge_note.j2c")); break; - case BADGE_WARN: child->setValue(std::string("badge_warn.j2c")); break; - case BADGE_ERROR: child->setValue(std::string("badge_error.j2c")); break; + case BADGE_WARN: + case BADGE_ERROR: + child->setValue(std::string("badge_warn.j2c")); break; } } } diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 72037a84b3..85f4ae587a 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -774,6 +774,9 @@ with the same filename but different name + + + From 0070a5f964a01c4595a8daa5ab485b447f183152 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Fri, 17 Jun 2016 19:04:10 +0300 Subject: [PATCH 06/13] MAINT-6490 Newly created inventory reports version mismatch --- indra/newview/llagentwearables.cpp | 41 ++++++++++++++++++----------- indra/newview/llinventorymodel.cpp | 4 +-- indra/newview/llviewerinventory.cpp | 38 +++++++++++++------------- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index b76a66ab39..8a65aa6a89 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -62,23 +62,37 @@ using namespace LLAvatarAppearanceDefines; /////////////////////////////////////////////////////////////////////////////// +void set_default_permissions(LLViewerInventoryItem* item) +{ + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskNextOwner() != LLFloaterPerms::getNextOwnerPerms("Wearables") + || perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Wearables") + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Wearables")) + { + perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); + + item->setPermissions(perm); + + item->updateServer(FALSE); + } +} + // Callback to wear and start editing an item that has just been created. void wear_and_edit_cb(const LLUUID& inv_item) { if (inv_item.isNull()) return; - LLViewerInventoryItem* item = gInventory.getItem(inv_item); - if (!item) return; + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) return; - LLPermissions perm = item->getPermissions(); - perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); - item->setPermissions(perm); + set_default_permissions(item); - item->updateServer(FALSE); - gInventory.updateItem(item); - gInventory.notifyObservers(); + // item was just created, update even if permissions did not changed + gInventory.updateItem(item); + gInventory.notifyObservers(); // Request editing the item after it gets worn. gAgentWearables.requestEditingWearable(inv_item); @@ -94,13 +108,8 @@ void wear_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); - item->setPermissions(perm); + set_default_permissions(item); - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index cada2d7cf2..dfaad5e525 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -582,7 +582,7 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, // Add the category to the internal representation LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLCategoryUpdate update(cat->getParentUUID(), 1); accountForUpdate(update); @@ -640,7 +640,7 @@ void LLInventoryModel::createNewCategoryCoro(std::string url, LLSD postData, inv result["parent_id"].asUUID(), (LLFolderType::EType)result["type"].asInteger(), result["name"].asString(), gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 0ee873d7a1..80a13bbb71 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -1036,6 +1036,22 @@ void activate_gesture_cb(const LLUUID& inv_item) LLGestureMgr::instance().activateGesture(inv_item); } +void set_default_permissions(LLViewerInventoryItem* item, std::string perm_type) +{ + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms(perm_type) + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms(perm_type)) + { + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms(perm_type)); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms(perm_type)); + + item->setPermissions(perm); + + item->updateServer(FALSE); + } +} + void create_script_cb(const LLUUID& inv_item) { if (!inv_item.isNull()) @@ -1043,13 +1059,9 @@ void create_script_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Scripts")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Scripts")); + set_default_permissions(item, "Scripts"); - item->setPermissions(perm); - - item->updateServer(FALSE); + // item was just created, update even if permissions did not changed gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -1065,13 +1077,8 @@ void create_gesture_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures")); + set_default_permissions(item, "Gestures"); - item->setPermissions(perm); - - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); @@ -1090,13 +1097,8 @@ void create_notecard_cb(const LLUUID& inv_item) LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (item) { - LLPermissions perm = item->getPermissions(); - perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Notecards")); - perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Notecards")); + set_default_permissions(item, "Notecards"); - item->setPermissions(perm); - - item->updateServer(FALSE); gInventory.updateItem(item); gInventory.notifyObservers(); } From 84396f4e279e63d536af37784e50e063185c161d Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Tue, 21 Jun 2016 16:25:18 +0300 Subject: [PATCH 07/13] MAINT-6513 Math rounding errors --- doc/contributions.txt | 3 ++- indra/newview/llfloaterpreference.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 2dbd3783f2..30465d8cfb 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -192,7 +192,8 @@ Ansariel Hiller MAINT-4677 MAINT-6300 MAINT-6397 - MAINT-6432 + MAINT-6432 + MAINT-6513 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 36bdcf4d89..20d8119606 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1411,7 +1411,7 @@ void LLAvatarComplexityControls::setIndirectMaxArc() else { // This is the inverse of the calculation in updateMaxComplexity - indirect_max_arc = (U32)((log(max_arc) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE) + MIN_INDIRECT_ARC_LIMIT; + indirect_max_arc = (U32)ll_round(((log(F32(max_arc)) - MIN_ARC_LOG) / ARC_LIMIT_MAP_SCALE)) + MIN_INDIRECT_ARC_LIMIT; } gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } @@ -1930,7 +1930,7 @@ void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* valu { // if this is changed, the inverse calculation in setIndirectMaxArc // must be changed to match - max_arc = (U32)exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT))); + max_arc = (U32)ll_round(exp(MIN_ARC_LOG + (ARC_LIMIT_MAP_SCALE * (indirect_value - MIN_INDIRECT_ARC_LIMIT)))); } gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); From ba36b366dbdb2a0b228bc88c7e03cc93a65f48d4 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Wed, 22 Jun 2016 12:55:30 +0300 Subject: [PATCH 08/13] MAINT-6514 Appearance Mode Body Parts Select shows wrong type --- doc/contributions.txt | 1 + indra/newview/llpaneloutfitedit.cpp | 3 --- indra/newview/llpaneloutfitedit.h | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/contributions.txt b/doc/contributions.txt index 30465d8cfb..f1bafba32c 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -194,6 +194,7 @@ Ansariel Hiller MAINT-6397 MAINT-6432 MAINT-6513 + MAINT-6514 Aralara Rajal Arare Chantilly CHUIBUG-191 diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index 8331c152e2..8b9941c0ca 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -1059,9 +1059,6 @@ void LLPanelOutfitEdit::filterWearablesBySelectedItem(void) case LLAssetType::AT_BODYPART: applyListViewFilter(LVIT_BODYPART); break; - case LLAssetType::AT_GESTURE: - applyListViewFilter(LVIT_GESTURES); - break; case LLAssetType::AT_CLOTHING: default: applyListViewFilter(LVIT_CLOTHING); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index 841bb4337a..30870daf40 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -80,7 +80,6 @@ public: { LVIT_ALL = 0, LVIT_CLOTHING, - LVIT_GESTURES, LVIT_BODYPART, LVIT_ATTACHMENT, LVIT_SHAPE, From a183385b2c475cf8096ad26b80f1a6a3dd7e0860 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 22 Jun 2016 17:53:47 +0300 Subject: [PATCH 09/13] MAINT-1768 Allow sharing objects from trash folder --- indra/newview/llgiveinventory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index a9bf8a9a50..97cc7684e4 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -248,7 +248,7 @@ bool LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, gInventory.collectDescendentsIf (cat->getUUID(), cats, items, - LLInventoryModel::EXCLUDE_TRASH, + LLInventoryModel::INCLUDE_TRASH, giveable); S32 count = cats.size(); bool complete = true; @@ -499,7 +499,7 @@ bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, gInventory.collectDescendentsIf (cat->getUUID(), cats, items, - LLInventoryModel::EXCLUDE_TRASH, + LLInventoryModel::INCLUDE_TRASH, giveable); bool give_successful = true; From 84b01805736c8927ef9fea8ec13f9f14ecdc4ce1 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Wed, 22 Jun 2016 18:59:46 +0300 Subject: [PATCH 10/13] MAINT-6515 Viewer doesn't store scripted null string settext updates for Metadata close refreshing. --- indra/newview/llviewerobject.cpp | 34 +++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 5edc3c9745..13cdcd6954 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1434,10 +1434,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, setChanged(MOVED | SILHOUETTE); } - else if (mText.notNull()) + else { - mText->markDead(); - mText = NULL; + if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + mHudText.clear(); } std::string media_url; @@ -1812,10 +1816,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, setChanged(TEXTURE); } - else if(mText.notNull()) + else { - mText->markDead(); - mText = NULL; + if (mText.notNull()) + { + mText->markDead(); + mText = NULL; + } + mHudText.clear(); } std::string media_url; @@ -4990,8 +4998,20 @@ void LLViewerObject::initHudText() void LLViewerObject::restoreHudText() { - if(mText) + if (mHudText.empty()) { + if (mText) + { + mText->markDead(); + mText = NULL; + } + } + else + { + if (!mText) + { + initHudText(); + } mText->setColor(mHudTextColor); mText->setString(mHudText); } From 0a9f25bcfbc977cf894e83fda95d7ff693039923 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 22 Jun 2016 13:35:13 -0700 Subject: [PATCH 11/13] MAINT-6385: Ensure that VMM initialization only happens once after login and that it will only happen after the region caps have been received. --- indra/newview/llagent.cpp | 24 +++++++++++++++++++----- indra/newview/llagent.h | 2 ++ indra/newview/llmarketplacefunctions.cpp | 4 +++- indra/newview/llviewermenu.cpp | 10 ++++++---- indra/newview/llviewermenu.h | 2 +- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d933537d2e..d8b0787852 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3895,11 +3895,17 @@ void LLAgent::handleTeleportFinished() mIsMaturityRatingChangingDuringTeleport = false; } - // Init SLM Marketplace connection so we know which UI should be used for the user as a merchant - // Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all. - // Note: Some regions will not support the SLM cap for a while so we need to do that check for each teleport. - // *TODO : Suppress that line from here once the whole grid migrated to SLM and move it to idle_startup() (llstartup.cpp) - check_merchant_status(); + if (mRegionp) + { + if (mRegionp->capabilitiesReceived()) + { + onCapabilitiesReceivedAfterTeleport(); + } + else + { + mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::onCapabilitiesReceivedAfterTeleport)); + } + } } void LLAgent::handleTeleportFailed() @@ -3931,6 +3937,14 @@ void LLAgent::handleTeleportFailed() } } +/*static*/ +void LLAgent::onCapabilitiesReceivedAfterTeleport() +{ + + check_merchant_status(); +} + + void LLAgent::teleportRequest( const U64& region_handle, const LLVector3& pos_local, diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 3a533c2cba..d82ff7a67f 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -676,6 +676,8 @@ private: void handleTeleportFinished(); void handleTeleportFailed(); + static void onCapabilitiesReceivedAfterTeleport(); + //-------------------------------------------------------------------- // Teleport State //-------------------------------------------------------------------- diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 6cc7a0fc99..54f95520db 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -773,7 +773,9 @@ void LLMarketplaceData::getMerchantStatusCoro() std::string url = getSLMConnectURL("/merchant"); if (url.empty()) { - LL_INFOS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + LL_WARNS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + return; } LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 99a9ed1d75..5790fa4c46 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -397,13 +397,15 @@ void set_merchant_SLM_menu() gToolBarView->enableCommand(command->id(), true); } -void check_merchant_status() +void check_merchant_status(bool force) { if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) { - // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() - LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); - + if (force) + { + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); + } // Hide SLM related menu item gMenuHolder->getChild("MarketplaceListings")->setVisible(FALSE); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index b7bdf00157..2f9bf7f714 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -83,7 +83,7 @@ BOOL enable_god_full(void* user_data); BOOL enable_god_liaison(void* user_data); BOOL enable_god_basic(void* user_data); void set_underclothes_menu_options(); -void check_merchant_status(); +void check_merchant_status(bool force = false); void exchange_callingcard(const LLUUID& dest_id); From 1b9c4e259974c93e781038e1cbc8c0428b265600 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 23 Jun 2016 12:48:06 +0300 Subject: [PATCH 12/13] MAINT-6516 FIXED Crash in updateEditFieldValues() while in Pathfinding -> Linksets floater --- indra/newview/llpathfindinglinksetlist.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/llpathfindinglinksetlist.cpp b/indra/newview/llpathfindinglinksetlist.cpp index b886e46765..eb7b95552e 100644 --- a/indra/newview/llpathfindinglinksetlist.cpp +++ b/indra/newview/llpathfindinglinksetlist.cpp @@ -204,7 +204,10 @@ void LLPathfindingLinksetList::parseLinksetListData(const LLSD& pLinksetListData { const std::string& uuid(linksetDataIter->first); const LLSD& linksetData = linksetDataIter->second; - LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); - objectMap.insert(std::pair(uuid, linksetPtr)); + if(linksetData.size() != 0) + { + LLPathfindingObjectPtr linksetPtr(new LLPathfindingLinkset(uuid, linksetData)); + objectMap.insert(std::pair(uuid, linksetPtr)); + } } } From d161651cdb2ea8c3e73055cbf4a85510b8da56db Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Thu, 23 Jun 2016 15:03:39 -0700 Subject: [PATCH 13/13] MAINT-6521: Allow anonymous connections to bypass the dependency and order tracking. --- indra/llcommon/llevents.cpp | 279 +++++++++++++++-------------- indra/llcommon/llevents.h | 8 + indra/llmessage/llcorehttputil.cpp | 2 +- indra/newview/llxmlrpclistener.cpp | 2 +- 4 files changed, 159 insertions(+), 132 deletions(-) diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 645c29d770..0e36741616 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -275,6 +275,8 @@ LLEventPumps::~LLEventPumps() #pragma warning (push) #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally #endif +const std::string LLEventPump::ANONYMOUS = std::string(); + LLEventPump::LLEventPump(const std::string& name, bool tweak): // Register every new instance with LLEventPumps @@ -313,145 +315,162 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL const NameList& after, const NameList& before) { - // Check for duplicate name before connecting listener to mSignal - ConnectionMap::const_iterator found = mConnections.find(name); - // In some cases the user might disconnect a connection explicitly -- or - // might use LLEventTrackable to disconnect implicitly. Either way, we can - // end up retaining in mConnections a zombie connection object that's - // already been disconnected. Such a connection object can't be - // reconnected -- nor, in the case of LLEventTrackable, would we want to - // try, since disconnection happens with the destruction of the listener - // object. That means it's safe to overwrite a disconnected connection - // object with the new one we're attempting. The case we want to prevent - // is only when the existing connection object is still connected. - if (found != mConnections.end() && found->second.connected()) + float nodePosition = 1.0; + + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new + // listener. We'll just tack it on to the end. + if (name != ANONYMOUS) { - throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name + - "' on " + typeid(*this).name() + " '" + getName() + "'"); - } - // Okay, name is unique, try to reconcile its dependencies. Specify a new - // "node" value that we never use for an mSignal placement; we'll fix it - // later. - DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); - // What if this listener has been added, removed and re-added? In that - // case newNode already has a non-negative value because we never remove a - // listener from mDeps. But keep processing uniformly anyway in case the - // listener was added back with different dependencies. Then mDeps.sort() - // would put it in a different position, and the old newNode placement - // value would be wrong, so we'd have to reassign it anyway. Trust that - // re-adding a listener with the same dependencies is the trivial case for - // mDeps.sort(): it can just replay its cache. - DependencyMap::sorted_range sorted_range; - try - { - // Can we pick an order that works including this new entry? - sorted_range = mDeps.sort(); - } - catch (const DependencyMap::Cycle& e) - { - // No: the new node's after/before dependencies have made mDeps - // unsortable. If we leave the new node in mDeps, it will continue - // to screw up all future attempts to sort()! Pull it out. - mDeps.remove(name); - throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() + - " '" + getName() + "' would cause cycle: " + e.what()); - } - // Walk the list to verify that we haven't changed the order. - float previous = 0.0, myprev = 0.0; - DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop - for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); - dmi != sorted_range.end(); ++dmi) - { - // Since we've added the new entry with an invalid placement, - // recognize it and skip it. - if (dmi->first == name) + // Check for duplicate name before connecting listener to mSignal + ConnectionMap::const_iterator found = mConnections.find(name); + // In some cases the user might disconnect a connection explicitly -- or + // might use LLEventTrackable to disconnect implicitly. Either way, we can + // end up retaining in mConnections a zombie connection object that's + // already been disconnected. Such a connection object can't be + // reconnected -- nor, in the case of LLEventTrackable, would we want to + // try, since disconnection happens with the destruction of the listener + // object. That means it's safe to overwrite a disconnected connection + // object with the new one we're attempting. The case we want to prevent + // is only when the existing connection object is still connected. + if (found != mConnections.end() && found->second.connected()) { - // Remember the iterator belonging to our new node, and which - // placement value was 'previous' at that point. - mydmi = dmi; - myprev = previous; - continue; + throw DupListenerName(std::string("Attempt to register duplicate listener name '") + name + + "' on " + typeid(*this).name() + " '" + getName() + "'"); } - // If the new node has rearranged the existing nodes, we'll find - // that their placement values are no longer in increasing order. - if (dmi->second < previous) + // Okay, name is unique, try to reconcile its dependencies. Specify a new + // "node" value that we never use for an mSignal placement; we'll fix it + // later. + DependencyMap::node_type& newNode = mDeps.add(name, -1.0, after, before); + // What if this listener has been added, removed and re-added? In that + // case newNode already has a non-negative value because we never remove a + // listener from mDeps. But keep processing uniformly anyway in case the + // listener was added back with different dependencies. Then mDeps.sort() + // would put it in a different position, and the old newNode placement + // value would be wrong, so we'd have to reassign it anyway. Trust that + // re-adding a listener with the same dependencies is the trivial case for + // mDeps.sort(): it can just replay its cache. + DependencyMap::sorted_range sorted_range; + try { - // This is another scenario in which we'd better back out the - // newly-added node from mDeps -- but don't do it yet, we want to - // traverse the existing mDeps to report on it! - // Describe the change to the order of our listeners. Copy - // everything but the newest listener to a vector we can sort to - // obtain the old order. - typedef std::vector< std::pair > SortNameList; - SortNameList sortnames; - for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); - cdmi != cdmend; ++cdmi) - { - if (cdmi->first != name) - { - sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); - } - } - std::sort(sortnames.begin(), sortnames.end()); - std::ostringstream out; - out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() - << "' would move previous listener '" << dmi->first << "'\nwas: "; - SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); - if (sni != snend) - { - out << sni->second; - while (++sni != snend) - { - out << ", " << sni->second; - } - } - out << "\nnow: "; - DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); - if (ddmi != ddmend) - { - out << ddmi->first; - while (++ddmi != ddmend) - { - out << ", " << ddmi->first; - } - } - // NOW remove the offending listener node. + // Can we pick an order that works including this new entry? + sorted_range = mDeps.sort(); + } + catch (const DependencyMap::Cycle& e) + { + // No: the new node's after/before dependencies have made mDeps + // unsortable. If we leave the new node in mDeps, it will continue + // to screw up all future attempts to sort()! Pull it out. mDeps.remove(name); - // Having constructed a description of the order change, inform caller. - throw OrderChange(out.str()); + throw Cycle(std::string("New listener '") + name + "' on " + typeid(*this).name() + + " '" + getName() + "' would cause cycle: " + e.what()); } - // This node becomes the previous one. - previous = dmi->second; - } - // We just got done with a successful mDeps.add(name, ...) call. We'd - // better have found 'name' somewhere in that sorted list! - assert(mydmi != sorted_range.end()); - // Four cases: - // 0. name is the only entry: placement 1.0 - // 1. name is the first of several entries: placement (next placement)/2 - // 2. name is between two other entries: placement (myprev + (next placement))/2 - // 3. name is the last entry: placement ceil(myprev) + 1.0 - // Since we've cleverly arranged for myprev to be 0.0 if name is the - // first entry, this folds down to two cases. Case 1 is subsumed by - // case 2, and case 0 is subsumed by case 3. So we need only handle - // cases 2 and 3, which means we need only detect whether name is the - // last entry. Increment mydmi to see if there's anything beyond. - if (++mydmi != sorted_range.end()) - { - // The new node isn't last. Place it between the previous node and - // the successor. - newNode = (myprev + mydmi->second)/2.f; - } - else - { - // The new node is last. Bump myprev up to the next integer, add - // 1.0 and use that. - newNode = std::ceil(myprev) + 1.f; + // Walk the list to verify that we haven't changed the order. + float previous = 0.0, myprev = 0.0; + DependencyMap::sorted_iterator mydmi = sorted_range.end(); // need this visible after loop + for (DependencyMap::sorted_iterator dmi = sorted_range.begin(); + dmi != sorted_range.end(); ++dmi) + { + // Since we've added the new entry with an invalid placement, + // recognize it and skip it. + if (dmi->first == name) + { + // Remember the iterator belonging to our new node, and which + // placement value was 'previous' at that point. + mydmi = dmi; + myprev = previous; + continue; + } + // If the new node has rearranged the existing nodes, we'll find + // that their placement values are no longer in increasing order. + if (dmi->second < previous) + { + // This is another scenario in which we'd better back out the + // newly-added node from mDeps -- but don't do it yet, we want to + // traverse the existing mDeps to report on it! + // Describe the change to the order of our listeners. Copy + // everything but the newest listener to a vector we can sort to + // obtain the old order. + typedef std::vector< std::pair > SortNameList; + SortNameList sortnames; + for (DependencyMap::sorted_iterator cdmi(sorted_range.begin()), cdmend(sorted_range.end()); + cdmi != cdmend; ++cdmi) + { + if (cdmi->first != name) + { + sortnames.push_back(SortNameList::value_type(cdmi->second, cdmi->first)); + } + } + std::sort(sortnames.begin(), sortnames.end()); + std::ostringstream out; + out << "New listener '" << name << "' on " << typeid(*this).name() << " '" << getName() + << "' would move previous listener '" << dmi->first << "'\nwas: "; + SortNameList::const_iterator sni(sortnames.begin()), snend(sortnames.end()); + if (sni != snend) + { + out << sni->second; + while (++sni != snend) + { + out << ", " << sni->second; + } + } + out << "\nnow: "; + DependencyMap::sorted_iterator ddmi(sorted_range.begin()), ddmend(sorted_range.end()); + if (ddmi != ddmend) + { + out << ddmi->first; + while (++ddmi != ddmend) + { + out << ", " << ddmi->first; + } + } + // NOW remove the offending listener node. + mDeps.remove(name); + // Having constructed a description of the order change, inform caller. + throw OrderChange(out.str()); + } + // This node becomes the previous one. + previous = dmi->second; + } + // We just got done with a successful mDeps.add(name, ...) call. We'd + // better have found 'name' somewhere in that sorted list! + assert(mydmi != sorted_range.end()); + // Four cases: + // 0. name is the only entry: placement 1.0 + // 1. name is the first of several entries: placement (next placement)/2 + // 2. name is between two other entries: placement (myprev + (next placement))/2 + // 3. name is the last entry: placement ceil(myprev) + 1.0 + // Since we've cleverly arranged for myprev to be 0.0 if name is the + // first entry, this folds down to two cases. Case 1 is subsumed by + // case 2, and case 0 is subsumed by case 3. So we need only handle + // cases 2 and 3, which means we need only detect whether name is the + // last entry. Increment mydmi to see if there's anything beyond. + if (++mydmi != sorted_range.end()) + { + // The new node isn't last. Place it between the previous node and + // the successor. + newNode = (myprev + mydmi->second) / 2.f; + } + else + { + // The new node is last. Bump myprev up to the next integer, add + // 1.0 and use that. + newNode = std::ceil(myprev) + 1.f; + } + + nodePosition = newNode; } // Now that newNode has a value that places it appropriately in mSignal, // connect it. - LLBoundListener bound = mSignal->connect(newNode, listener); - mConnections[name] = bound; + LLBoundListener bound = mSignal->connect(nodePosition, listener); + + if (name != ANONYMOUS) + { // note that we are not tracking anonymous listeners here either. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. + mConnections[name] = bound; + } return bound; } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index ba4fcd766e..694951e699 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -365,6 +365,8 @@ typedef boost::signals2::trackable LLEventTrackable; class LL_COMMON_API LLEventPump: public LLEventTrackable { public: + static const std::string ANONYMOUS; // constant for anonymous listeners. + /** * Exception thrown by LLEventPump(). You are trying to instantiate an * LLEventPump (subclass) using the same name as some other instance, and @@ -476,6 +478,12 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is + * manually disconnected when no longer needed since there will be no + * way to later find and disconnect this listener manually. * * If (as is typical) you pass a boost::bind() expression as @a * listener, listen() will inspect the components of that expression. If a diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 7742cbc182..9bf38fb336 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -642,7 +642,7 @@ HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request) mHttpRequest(request) { mBoundListener = LLEventPumps::instance().obtain("mainloop"). - listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1)); + listen(LLEventPump::ANONYMOUS, boost::bind(&HttpRequestPumper::pollRequest, this, _1)); } HttpRequestPumper::~HttpRequestPumper() diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 97a9eb7f5f..cc3645131d 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -322,7 +322,7 @@ public: mBoundListener = LLEventPumps::instance(). obtain("mainloop"). - listen(LLEventPump::inventName(), boost::bind(&Poller::poll, this, _1)); + listen(LLEventPump::ANONYMOUS, boost::bind(&Poller::poll, this, _1)); LL_INFOS("LLXMLRPCListener") << mMethod << " request sent to " << mUri << LL_ENDL; }