diff options
Diffstat (limited to 'indra/newview')
22 files changed, 579 insertions, 106 deletions
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 097a9ac7b9..f0a91fd407 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1619,6 +1619,17 @@ <key>Value</key> <string>default</string> </map> + <key>ChatAutocompleteGestures</key> + <map> + <key>Comment</key> + <string>Auto-complete gestures in nearby chat</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>ChatBarStealsFocus</key> <map> <key>Comment</key> @@ -10168,6 +10179,17 @@ <key>Value</key> <integer>10</integer> </map> + <key>MaxAttachmentComplexity</key> + <map> + <key>Comment</key> + <string>Attachment's render weight limit</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>1.0E6</real> + </map> <key>ComplexityChangesPopUpDelay</key> <map> <key>Comment</key> @@ -10734,6 +10756,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>ScriptDialogLimitations</key> + <map> + <key>Comment</key> + <string>Limits amount of dialogs per script (0 - per object, 1 - per channel, 2 - per channel for attachments, 3 - per channel for HUDs, 4 -unconstrained for HUDs)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> <key>SecondLifeEnterprise</key> <map> <key>Comment</key> diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index feb981217d..c928cf0601 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2917,11 +2917,32 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar() removeItemsFromAvatar(ids_to_remove); } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) +class LLUpdateOnCOFLinkRemove : public LLInventoryCallback { - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); +public: + LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer<LLInventoryCallback> cb = NULL): + mItemID(remove_item_id), + mCB(cb) + { + } - LLInventoryModel::cat_array_t cat_array; + /* virtual */ void fire(const LLUUID& item_id) + { + // just removed cof link, "(wear)" suffix depends on presence of link, so update label + gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID); + if (mCB.notNull()) + { + mCB->fire(item_id); + } + } + +private: + LLUUID mItemID; + LLPointer<LLInventoryCallback> mCB; +}; + +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb) +{ LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; gInventory.collectDescendents(LLAppearanceMgr::getCOF(), cat_array, @@ -2932,12 +2953,20 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInve const LLInventoryItem* item = item_array.at(i).get(); if (item->getIsLinkType() && item->getLinkedUUID() == item_id) { - bool immediate_delete = false; if (item->getType() == LLAssetType::AT_OBJECT) { - immediate_delete = true; + // Immediate delete + remove_inventory_item(item->getUUID(), cb, true); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + } + else + { + // Delayed delete + // Pointless to update item_id label here since link still exists and first notifyObservers + // call will restore (wear) suffix, mark for update after deletion + LLPointer<LLUpdateOnCOFLinkRemove> cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb); + remove_inventory_item(item->getUUID(), cb_label, false); } - remove_inventory_item(item->getUUID(), cb, immediate_delete); } } } diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 314b859cea..711a87dc99 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -44,7 +44,7 @@ public: mExpanderLabel(more_text) {} - /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { // more label always spans width of text box if (num_chars == 0) diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 40ae22bb4e..7895a5ff48 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -485,7 +485,8 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke() KEY key = gKeyboard->currentKey(); // Ignore "special" keys, like backspace, arrows, etc. - if (length > 1 + if (gSavedSettings.getBOOL("ChatAutocompleteGestures") + && length > 1 && raw_text[0] == '/' && key < KEY_SPECIAL) { diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c654817849..b3885bf36c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1262,6 +1262,10 @@ LLModelPreview::~LLModelPreview() // glod.dll!glodShutdown() + 0x77 bytes // //glodShutdown(); + if(mModelLoader) + { + mModelLoader->shutdown(); + } } U32 LLModelPreview::calcResourceCost() diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ff8b8b0403..bcda9baa9a 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -2677,49 +2677,57 @@ void LLIMMgr::addMessage( LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg); LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id); - skip_message &= !session->isGroupSessionType(); // Do not skip group chats... - if(skip_message) + if (session) { - gIMMgr->leaveSession(new_session_id); - } - // When we get a new IM, and if you are a god, display a bit - // of information about the source. This is to help liaisons - // when answering questions. - if(gAgent.isGodlike()) - { - // *TODO:translate (low priority, god ability) - std::ostringstream bonus_info; - bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " " - << parent_estate_id - << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") - << ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : ""); - - // once we have web-services (or something) which returns - // information about a region id, we can print this out - // and even have it link to map-teleport or something. - //<< "*** region_id: " << region_id << std::endl - //<< "*** position: " << position << std::endl; + skip_message &= !session->isGroupSessionType(); // Do not skip group chats... + if (skip_message) + { + gIMMgr->leaveSession(new_session_id); + } + // When we get a new IM, and if you are a god, display a bit + // of information about the source. This is to help liaisons + // when answering questions. + if (gAgent.isGodlike()) + { + // *TODO:translate (low priority, god ability) + std::ostringstream bonus_info; + bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " " + << parent_estate_id + << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") + << ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : ""); + + // once we have web-services (or something) which returns + // information about a region id, we can print this out + // and even have it link to map-teleport or something. + //<< "*** region_id: " << region_id << std::endl + //<< "*** position: " << position << std::endl; + + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); + } - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); - } + // Logically it would make more sense to reject the session sooner, in another area of the + // code, but the session has to be established inside the server before it can be left. + if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) + { + LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; + if (!gIMMgr->leaveSession(new_session_id)) + { + LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL; + } + return; + } - // Logically it would make more sense to reject the session sooner, in another area of the - // code, but the session has to be established inside the server before it can be left. - if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden) - { - LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL; - if(!gIMMgr->leaveSession(new_session_id)) + //Play sound for new conversations + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) { - LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL; + make_ui_sound("UISndNewIncomingIMSession"); } - return; } - - //Play sound for new conversations - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE)) - { - make_ui_sound("UISndNewIncomingIMSession"); - } + else + { + // Failed to create a session, most likely due to empty name (name cache failed?) + LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL; + } } if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message) @@ -3022,7 +3030,7 @@ void LLIMMgr::inviteToSession( LLIncomingCallDialog::processCallResponse(1, payload); return; } - else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat)) + else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite) { LL_INFOS() << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL; return; diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index a8919db828..406c8b89d0 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -76,13 +76,6 @@ // * Review the download rate throttling. Slow then fast? // Detect bandwidth usage and speed up when it drops? // -// * A lot of calls to notifyObservers(). It looks like -// these could be collapsed by maintaining a 'dirty' -// bit and there appears to be an attempt to do this. -// But it isn't used or is used in a limited fashion. -// Are there semanic issues requiring a call after certain -// updateItem() calls? -// // * An error on a fetch could be due to one item in the batch. // If the batch were broken up, perhaps more of the inventory // would download. (Handwave here, not certain this is an @@ -393,6 +386,12 @@ void LLInventoryModelBackgroundFetch::bulkFetch() { // Process completed background HTTP requests gInventory.handleResponses(false); + // Just processed a bunch of items. + // Note: do we really need notifyObservers() here? + // OnIdle it will be called anyway due to Add flag for processed item. + // It seems like in some cases we are updaiting on fail (no flag), + // but is there anything to update? + gInventory.notifyObservers(); } if ((mFetchCount > max_concurrent_fetches) || @@ -711,7 +710,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res titem->setParent(lost_uuid); titem->updateParentOnServer(FALSE); gInventory.updateItem(titem); - gInventory.notifyObservers(); } } } @@ -784,8 +782,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res { fetcher->setAllFoldersFetched(); } - - gInventory.notifyObservers(); } @@ -828,7 +824,6 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http fetcher->setAllFoldersFetched(); } } - gInventory.notifyObservers(); } @@ -866,7 +861,6 @@ void BGFolderHttpHandler::processFailure(const char * const reason, LLCore::Http fetcher->setAllFoldersFetched(); } } - gInventory.notifyObservers(); } diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index b9194c6c67..5abd99d36f 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -67,7 +67,8 @@ const std::string LL_IM_FROM("from"); const std::string LL_IM_FROM_ID("from_id"); const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt"); -const static std::string IM_SEPARATOR(": "); +const static char IM_SYMBOL_SEPARATOR(':'); +const static std::string IM_SEPARATOR(std::string() + IM_SYMBOL_SEPARATOR + " "); const static std::string NEW_LINE("\n"); const static std::string NEW_LINE_SPACE_PREFIX("\n "); const static std::string TWO_SPACES(" "); @@ -838,7 +839,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const } if (im[LL_IM_TIME].isDefined()) -{ + { std::string timestamp = im[LL_IM_TIME].asString(); boost::trim(timestamp); ostr << '[' << timestamp << ']' << TWO_SPACES; @@ -851,9 +852,29 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const { std::string from = im[LL_IM_FROM].asString(); boost::trim(from); - if (from.size()) + + std::size_t found = from.find(IM_SYMBOL_SEPARATOR); + std::size_t len = from.size(); + std::size_t start = 0; + while (found != std::string::npos) { - ostr << from << IM_SEPARATOR; + std::size_t sub_len = found - start; + if (sub_len > 0) + { + ostr << from.substr(start, sub_len); + } + LLURI::encodeCharacter(ostr, IM_SYMBOL_SEPARATOR); + start = found + 1; + found = from.find(IM_SYMBOL_SEPARATOR, start); + } + if (start < len) + { + std::string str_end = from.substr(start, len - start); + ostr << str_end; + } + if (len > 0) + { + ostr << IM_SEPARATOR; } } @@ -865,7 +886,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX); ostr << im_text; } - } +} bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params) { @@ -912,7 +933,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params if (!boost::regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false; bool has_name = name_and_text[IDX_NAME].matched; - std::string name = name_and_text[IDX_NAME]; + std::string name = LLURI::unescape(name_and_text[IDX_NAME]); //we don't need a name/text separator if (has_name && name.length() && name[name.length()-1] == ':') @@ -933,7 +954,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params U32 divider_pos = stuff.find(NAME_TEXT_DIVIDER); if (divider_pos != std::string::npos && divider_pos < (stuff.length() - NAME_TEXT_DIVIDER.length())) { - im[LL_IM_FROM] = stuff.substr(0, divider_pos); + im[LL_IM_FROM] = LLURI::unescape(stuff.substr(0, divider_pos)); im[LL_IM_TEXT] = stuff.substr(divider_pos + NAME_TEXT_DIVIDER.length()); return true; } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 1a533dace7..f7e0e32256 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3626,7 +3626,15 @@ void LLMeshRepository::notifyLoadedMeshes() //popup queued error messages from background threads while (!mUploadErrorQ.empty()) { - LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front()); + LLSD substitutions(mUploadErrorQ.front()); + if (substitutions.has("DETAILS")) + { + LLNotificationsUtil::add("MeshUploadErrorDetails", substitutions); + } + else + { + LLNotificationsUtil::add("MeshUploadError", substitutions); + } mUploadErrorQ.pop(); } diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 203c57b732..cf38090798 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -56,15 +56,20 @@ #include "llfloatergroups.h" #include "llfloaterreg.h" #include "llavataractions.h" +#include "llavatariconctrl.h" #include "llnamebox.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" #include "llspinctrl.h" #include "roles_constants.h" #include "llgroupactions.h" +#include "llgroupiconctrl.h" #include "lltrans.h" #include "llinventorymodel.h" +#include "llavatarnamecache.h" +#include "llcachename.h" + U8 string_value_to_click_action(std::string p_value); std::string click_action_to_string_value( U8 action); @@ -186,10 +191,13 @@ void LLPanelPermissions::disableAll() getChild<LLUICtrl>("pathfinding_attributes_value")->setValue(LLStringUtil::null); getChildView("Creator:")->setEnabled(FALSE); + getChild<LLUICtrl>("Creator Icon")->setVisible(FALSE); getChild<LLUICtrl>("Creator Name")->setValue(LLStringUtil::null); getChildView("Creator Name")->setEnabled(FALSE); getChildView("Owner:")->setEnabled(FALSE); + getChild<LLUICtrl>("Owner Icon")->setVisible(FALSE); + getChild<LLUICtrl>("Owner Group Icon")->setVisible(FALSE); getChild<LLUICtrl>("Owner Name")->setValue(LLStringUtil::null); getChildView("Owner Name")->setEnabled(FALSE); @@ -366,39 +374,84 @@ void LLPanelPermissions::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); - std::string creator_name; - LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); - - getChild<LLUICtrl>("Creator Name")->setValue(creator_name); + std::string creator_app_link; + LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_app_link); + + // Style for creator and owner links (both group and agent) + LLStyle::Params style_params; + LLColor4 link_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + style_params.color = link_color; + style_params.readonly_color = link_color; + style_params.is_link = true; // link will be added later + style_params.font.style = "UNDERLINE"; + + LLAvatarName av_name; + if (LLAvatarNameCache::get(mCreatorID, &av_name)) + { + // If name isn't present, this will 'request' it and trigger refresh() again + LLTextBox* text_box = getChild<LLTextBox>("Creator Name"); + style_params.link_href = creator_app_link; + text_box->setText(av_name.getCompleteName(), style_params); + } + getChild<LLAvatarIconCtrl>("Creator Icon")->setValue(mCreatorID); + getChild<LLAvatarIconCtrl>("Creator Icon")->setVisible(TRUE); getChildView("Creator Name")->setEnabled(TRUE); // Update owner text field getChildView("Owner:")->setEnabled(TRUE); - std::string owner_name; - const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name); - if (mOwnerID.isNull()) + std::string owner_app_link; + const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); + + + if (LLSelectMgr::getInstance()->selectIsGroupOwned()) { - if (LLSelectMgr::getInstance()->selectIsGroupOwned()) + // Group owned already displayed by selectGetOwner + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mOwnerID); + if (group_data && group_data->isGroupPropertiesDataComplete()) { - // Group owned already displayed by selectGetOwner + LLTextBox* text_box = getChild<LLTextBox>("Owner Name"); + style_params.link_href = owner_app_link; + text_box->setText(group_data->mName, style_params); + getChild<LLGroupIconCtrl>("Owner Group Icon")->setIconId(group_data->mInsigniaID); + getChild<LLGroupIconCtrl>("Owner Group Icon")->setVisible(TRUE); + getChild<LLUICtrl>("Owner Icon")->setVisible(FALSE); } else { + // Triggers refresh + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mOwnerID); + } + } + else + { + LLUUID owner_id = mOwnerID; + if (owner_id.isNull()) + { // Display last owner if public - std::string last_owner_name; - LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, last_owner_name); + std::string last_owner_app_link; + LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, last_owner_app_link); // It should never happen that the last owner is null and the owner // is null, but it seems to be a bug in the simulator right now. JC - if (!mLastOwnerID.isNull() && !last_owner_name.empty()) + if (!mLastOwnerID.isNull() && !last_owner_app_link.empty()) { - owner_name.append(", last "); - owner_name.append(last_owner_name); + owner_app_link.append(", last "); + owner_app_link.append(last_owner_app_link); } + owner_id = mLastOwnerID; + } + if (LLAvatarNameCache::get(owner_id, &av_name)) + { + // If name isn't present, this will 'request' it and trigger refresh() again + LLTextBox* text_box = getChild<LLTextBox>("Owner Name"); + style_params.link_href = owner_app_link; + text_box->setText(av_name.getCompleteName(), style_params); } + getChild<LLAvatarIconCtrl>("Owner Icon")->setValue(owner_id); + getChild<LLAvatarIconCtrl>("Owner Icon")->setVisible(TRUE); + getChild<LLUICtrl>("Owner Group Icon")->setVisible(FALSE); } - getChild<LLUICtrl>("Owner Name")->setValue(owner_name); getChildView("Owner Name")->setEnabled(TRUE); // update group text field diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index 1d021ec28f..b2c450aa0c 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -40,6 +40,7 @@ #include "lltoastnotifypanel.h" #include "lltoastscripttextbox.h" #include "lltrans.h" +#include "llviewerobjectlist.h" #include "llviewerwindow.h" #include "llfloaterimsession.h" @@ -61,6 +62,7 @@ LLUUID notification_id_to_object_id(const LLUUID& notification_id) ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// + LLScriptFloater::LLScriptFloater(const LLSD& key) : LLDockableFloater(NULL, true, key) , mScriptForm(NULL) @@ -346,6 +348,11 @@ void LLScriptFloater::hideToastsIfNeeded() ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +LLScriptFloaterManager::LLScriptFloaterManager() +{ + gSavedSettings.getControl("ScriptDialogLimitations")->getCommitSignal()->connect(boost::bind(&clearScriptNotifications)); +} + void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id) { if(notification_id.isNull()) @@ -365,16 +372,86 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id) // LLDialog can spawn only one instance, LLLoadURL and LLGiveInventory can spawn unlimited number of instances if(OBJ_SCRIPT == obj_type) { - // If an Object spawns more-than-one floater, only the newest one is shown. - // The previous is automatically closed. - script_notification_map_t::const_iterator it = findUsingObjectId(object_id); + static LLCachedControl<U32> script_dialog_limitations(gSavedSettings, "ScriptDialogLimitations", 0); + script_notification_map_t::const_iterator it = mNotifications.end(); + switch (script_dialog_limitations) + { + case SCRIPT_PER_CHANNEL: + { + // If an Object spawns more-than-one floater per channel, only the newest one is shown. + // The previous is automatically closed. + LLNotificationPtr notification = LLNotifications::instance().find(notification_id); + if (notification) + { + it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger()); + } + break; + } + case SCRIPT_ATTACHMENT_PER_CHANNEL: + { + LLViewerObject* objectp = gObjectList.findObject(object_id); + if (objectp && objectp->getAttachmentItemID().notNull()) //in user inventory + { + LLNotificationPtr notification = LLNotifications::instance().find(notification_id); + if (notification) + { + it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger()); + } + } + else + { + it = findUsingObjectId(object_id); + } + break; + } + case SCRIPT_HUD_PER_CHANNEL: + { + LLViewerObject* objectp = gObjectList.findObject(object_id); + if (objectp && objectp->isHUDAttachment()) + { + LLNotificationPtr notification = LLNotifications::instance().find(notification_id); + if (notification) + { + it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger()); + } + } + else + { + it = findUsingObjectId(object_id); + } + break; + } + case SCRIPT_HUD_UNCONSTRAINED: + { + LLViewerObject* objectp = gObjectList.findObject(object_id); + if (objectp && objectp->isHUDAttachment()) + { + // don't remove existing floaters + break; + } + else + { + it = findUsingObjectId(object_id); + } + break; + } + case SCRIPT_PER_OBJECT: + default: + { + // If an Object spawns more-than-one floater, only the newest one is shown. + // The previous is automatically closed. + it = findUsingObjectId(object_id); + break; + } + } + if(it != mNotifications.end()) { LLChicletPanel * chiclet_panelp = LLChicletBar::getInstance()->getChicletPanel(); if (NULL != chiclet_panelp) { LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(it->first); - if(NULL != chicletp) + if (NULL != chicletp) { // Pass the new_message icon state further. set_new_message = chicletp->getShowNewMessagesIcon(); @@ -383,7 +460,7 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id) } LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", it->first); - if(floater) + if (floater) { // Generate chiclet with a "new message" indicator if a docked window was opened but not in focus. See EXT-3142. set_new_message |= !floater->hasFocus(); @@ -579,6 +656,23 @@ LLScriptFloaterManager::script_notification_map_t::const_iterator LLScriptFloate return mNotifications.end(); } +LLScriptFloaterManager::script_notification_map_t::const_iterator LLScriptFloaterManager::findUsingObjectIdAndChannel(const LLUUID& object_id, S32 im_channel) +{ + script_notification_map_t::const_iterator it = mNotifications.begin(); + for (; mNotifications.end() != it; ++it) + { + if (object_id == it->second) + { + LLNotificationPtr notification = LLNotifications::instance().find(it->first); + if (notification && (im_channel == notification->getPayload()["chat_channel"].asInteger())) + { + return it; + } + } + } + return mNotifications.end(); +} + void LLScriptFloaterManager::saveFloaterPosition(const LLUUID& object_id, const FloaterPositionInfo& fpi) { if(object_id.notNull()) @@ -612,6 +706,33 @@ void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bo } } +//static +void LLScriptFloaterManager::clearScriptNotifications() +{ + LLScriptFloaterManager* inst = LLScriptFloaterManager::getInstance(); + static const object_type_map TYPE_MAP = initObjectTypeMap(); + + script_notification_map_t::const_iterator ntf_it = inst->mNotifications.begin(); + while (inst->mNotifications.end() != ntf_it) + { + LLUUID notification_id = ntf_it->first; + ntf_it++; // onRemoveNotification() erases notification + LLNotificationPtr notification = LLNotifications::instance().find(notification_id); + if (notification) + { + object_type_map::const_iterator map_it = TYPE_MAP.find(notification->getName()); + if (map_it != TYPE_MAP.end() && map_it->second == OBJ_SCRIPT) + { + if (notification != NULL && !notification->isCancelled()) + { + LLNotificationsUtil::cancel(notification); + } + inst->onRemoveNotification(notification_id); + } + } + } +} + ////////////////////////////////////////////////////////////////// bool LLScriptFloater::isScriptTextbox(LLNotificationPtr notification) diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h index c0b84abdcb..0192a8893e 100644 --- a/indra/newview/llscriptfloater.h +++ b/indra/newview/llscriptfloater.h @@ -41,7 +41,7 @@ class LLScriptFloaterManager : public LLSingleton<LLScriptFloaterManager> // *TODO // LLScriptFloaterManager and LLScriptFloater will need some refactoring after we // know how script notifications should look like. - LLSINGLETON_EMPTY_CTOR(LLScriptFloaterManager); + LLSINGLETON(LLScriptFloaterManager); public: typedef enum e_object_type @@ -53,6 +53,15 @@ public: OBJ_UNKNOWN }EObjectType; + typedef enum e_limitation_type + { + SCRIPT_PER_OBJECT = 0, + SCRIPT_PER_CHANNEL = 1, + SCRIPT_ATTACHMENT_PER_CHANNEL, + SCRIPT_HUD_PER_CHANNEL, + SCRIPT_HUD_UNCONSTRAINED + }ELimitationType; + /** * Handles new notifications. * Saves notification and object ids, removes old notification if needed, creates script chiclet @@ -104,6 +113,11 @@ public: protected: + /** + * Removes all script-dialog notifications + */ + static void clearScriptNotifications(); + typedef std::map<std::string, EObjectType> object_type_map; static object_type_map initObjectTypeMap(); @@ -112,6 +126,7 @@ protected: typedef std::map<LLUUID, LLUUID> script_notification_map_t; script_notification_map_t::const_iterator findUsingObjectId(const LLUUID& object_id); + script_notification_map_t::const_iterator findUsingObjectIdAndChannel(const LLUUID& object_id, S32 im_channel); private: diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index 3c58dd7194..43e7e57814 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -815,40 +815,49 @@ void LLSidepanelItemInfo::onCommitPermissions() //LL_INFOS() << "LLSidepanelItemInfo::onCommitPermissions()" << LL_ENDL; LLViewerInventoryItem* item = findItem(); if(!item) return; + + BOOL is_group_owned; + LLUUID owner_id; + LLUUID group_id; LLPermissions perm(item->getPermissions()); + perm.getOwnership(owner_id, is_group_owned); + if (is_group_owned && gAgent.hasPowerInGroup(owner_id, GP_OBJECT_MANIPULATE)) + { + group_id = owner_id; + } LLCheckBoxCtrl* CheckShareWithGroup = getChild<LLCheckBoxCtrl>("CheckShareWithGroup"); if(CheckShareWithGroup) { - perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(), + perm.setGroupBits(gAgent.getID(), group_id, CheckShareWithGroup->get(), PERM_MODIFY | PERM_MOVE | PERM_COPY); } LLCheckBoxCtrl* CheckEveryoneCopy = getChild<LLCheckBoxCtrl>("CheckEveryoneCopy"); if(CheckEveryoneCopy) { - perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), + perm.setEveryoneBits(gAgent.getID(), group_id, CheckEveryoneCopy->get(), PERM_COPY); } LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify"); if(CheckNextOwnerModify) { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + perm.setNextOwnerBits(gAgent.getID(), group_id, CheckNextOwnerModify->get(), PERM_MODIFY); } LLCheckBoxCtrl* CheckNextOwnerCopy = getChild<LLCheckBoxCtrl>("CheckNextOwnerCopy"); if(CheckNextOwnerCopy) { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + perm.setNextOwnerBits(gAgent.getID(), group_id, CheckNextOwnerCopy->get(), PERM_COPY); } LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild<LLCheckBoxCtrl>("CheckNextOwnerTransfer"); if(CheckNextOwnerTransfer) { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + perm.setNextOwnerBits(gAgent.getID(), group_id, CheckNextOwnerTransfer->get(), PERM_TRANSFER); } if(perm != item->getPermissions() diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 45dbd95bea..1d6daed9cc 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -6274,6 +6274,24 @@ BOOL LLViewerObject::isTempAttachment() const return (mID.notNull() && (mID == mAttachmentItemID)); } +BOOL LLViewerObject::isHiglightedOrBeacon() const +{ + if (LLFloaterReg::instanceVisible("beacons") && (gPipeline.getRenderBeacons(NULL) || gPipeline.getRenderHighlights(NULL))) + { + BOOL has_media = (getMediaType() == LLViewerObject::MEDIA_SET); + BOOL is_scripted = !isAvatar() && !getParent() && flagScripted(); + BOOL is_physical = !isAvatar() && flagUsePhysics(); + + return (isParticleSource() && gPipeline.getRenderParticleBeacons(NULL)) + || (isAudioSource() && gPipeline.getRenderSoundBeacons(NULL)) + || (has_media && gPipeline.getRenderMOAPBeacons(NULL)) + || (is_scripted && gPipeline.getRenderScriptedBeacons(NULL)) + || (is_scripted && flagHandleTouch() && gPipeline.getRenderScriptedTouchBeacons(NULL)) + || (is_physical && gPipeline.getRenderPhysicalBeacons(NULL)); + } + return FALSE; +} + const LLUUID &LLViewerObject::getAttachmentItemID() const { diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 1e8f3f4ec2..24fcf0517e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -178,6 +178,8 @@ public: virtual BOOL isHUDAttachment() const { return FALSE; } virtual BOOL isTempAttachment() const; + virtual BOOL isHiglightedOrBeacon() const; + virtual void updateRadius() {}; virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() @@ -388,7 +390,7 @@ public: // Create if necessary LLAudioSource *getAudioSource(const LLUUID& owner_id); - bool isAudioSource() {return mAudioSourcep != NULL;} + BOOL isAudioSource() const {return mAudioSourcep != NULL;} U8 getMediaType() const; void setMediaType(U8 media_type); diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 9e09971ced..7d2d6e25c7 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -176,7 +176,7 @@ public: mToolTip = inv_item->getName() + '\n' + inv_item->getDescription(); } - /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const + /*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { if (num_chars == 0) { @@ -185,7 +185,7 @@ public: } else { - width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str()); + width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidthF32(mLabel.c_str()); height = llmax(mImage->getHeight(), mStyle->getFont()->getLineHeight()); } return false; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f6a16f7da1..3968266c27 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -119,7 +119,7 @@ const F32 MAX_HOVER_Z = 2.0; const F32 MIN_HOVER_Z = -2.0; const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f; -const F32 MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; +const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; using namespace LLAvatarAppearanceDefines; @@ -9018,6 +9018,9 @@ void LLVOAvatar::calculateUpdateRenderComplexity() * the official viewer for consideration. *****************************************************************/ static const U32 COMPLEXITY_BODY_PART_COST = 200; + static LLCachedControl<F32> max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity"); + F32 max_attachment_complexity = max_complexity_setting; + max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY); // Diagnostic list of all textures on our avatar static std::set<LLUUID> all_textures; @@ -9099,7 +9102,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() << " children: " << attachment_children_cost << LL_ENDL; // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI - cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, MAX_ATTACHMENT_COMPLEXITY); + cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); } } } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 657babd92c..90ba814a15 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3977,7 +3977,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& start_face = face; end_face = face+1; } - + pick_transparent |= isHiglightedOrBeacon(); bool special_cursor = specialHoverCursor(); for (S32 i = start_face; i < end_face; ++i) { diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 91e4c1b603..c3a5a0dce8 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -946,18 +946,28 @@ width="90"> Creator: </text> + <avatar_icon + default_icon_name="Generic_Person" + height="18" + follows="left|top" + layout="topleft" + left_pad="1" + name="Creator Icon" + visible="false" + top_delta="0" + width="18" /> <!-- *NOTE: Intentionally wide for long names --> <text type="string" length="1" follows="left|top" - left_pad="0" + left_pad="1" height="29" layout="topleft" name="Creator Name" - top_delta="0" + top_delta="-1" translate="false" - width="190" + width="170" word_wrap="true" use_ellipses="true"> TestString PleaseIgnore (please.ignore) @@ -974,6 +984,26 @@ width="90"> Owner: </text> + <avatar_icon + default_icon_name="Generic_Person" + height="18" + follows="left|top" + layout="topleft" + left_pad="1" + name="Owner Icon" + visible="false" + top_delta="0" + width="18" /> + <group_icon + default_icon_name="Generic_Group" + height="18" + follows="left|top" + layout="topleft" + left_pad="-18" + name="Owner Group Icon" + visible="false" + top_delta="0" + width="18" /> <!-- *NOTE: Intentionally wide for long names --> <text type="string" @@ -982,10 +1012,10 @@ height="29" layout="topleft" name="Owner Name" - left_pad="0" - top_delta="0" + left_pad="1" + top_delta="-1" translate="false" - width="190" + width="170" word_wrap="true" use_ellipses="true"> TestString PleaseIgnore (please.ignore) diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 4f5f0ac02c..ebe1fdc4c7 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -909,6 +909,108 @@ Please invite members within 48 hours. <notification icon="alertmodal.tga" + name="JoinGroupInaccessible" + type="alertmodal"> +This group is not accessible to you. + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupError" + type="alertmodal"> +Error processing your group membership request. + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupError" + type="alertmodal"> +Unable to join group: [reason] + <tag>group_id</tag> + <tag>success</tag> + <tag>reason</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupTrialUser" + type="alertmodal"> +Sorry, trial users can't join groups. + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupMaxGroups" + type="alertmodal"> +You cannot join '[group_name]': +You are already a member of [group_count] groups, the maximum number allowed is [max_groups] + <tag>success</tag> + <tag>group_id</tag> + <tag>group_name</tag> + <tag>group_count</tag> + <tag>max_groups</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupClosedEnrollment" + type="alertmodal"> +You cannot join '[group_name]': +The group no longer has open enrollment. + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupSuccess" + type="alertmodal"> +You have been added to the group + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="JoinGroupInsufficientFunds" + type="alertmodal"> +Unable to transfer the required L$ [membership_fee] membership fee. + <tag>group_id</tag> + <tag>success</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="LandBuyPass" type="alertmodal"> <tag>fail</tag> @@ -8501,12 +8603,22 @@ Select residents to share with. </notification> <notification - name="MeshUploadError" + name="MeshUploadErrorDetails" icon="alert.tga" type="alert"> [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] [DETAILS]See SecondLife.log for details </notification> + + <notification + name="MeshUploadError" + icon="alert.tga" + type="alert"> + [LABEL] failed to upload: [MESSAGE] +[IDENTIFIER] + +See SecondLife.log for details + </notification> <notification name="MeshUploadPermError" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 440c6613d5..78f771cd51 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -9,6 +9,18 @@ name="chat" top="1" width="517"> + + <check_box + control_name="ChatAutocompleteGestures" + height="16" + initial_value="true" + label="Auto-complete gestures in nearby chat" + layout="topleft" + top="17" + left="13" + name="auto_complete_gestures" + width="330"> + </check_box> <panel border="false" diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 2dae1025ec..b7b67147eb 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -586,7 +586,7 @@ label_width="205" left="10" max_val="100" - min_val="0.1" + min_val="-100" name="rptctrl" width="265" /> <spinner |