diff options
-rw-r--r-- | indra/llmessage/llinstantmessage.cpp | 1 | ||||
-rw-r--r-- | indra/llmessage/llinstantmessage.h | 1 | ||||
-rw-r--r-- | indra/llui/llnotifications.cpp | 25 | ||||
-rw-r--r-- | indra/llui/llnotifications.h | 10 | ||||
-rw-r--r-- | indra/newview/llchathistory.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llimfloater.cpp | 35 | ||||
-rw-r--r-- | indra/newview/llimview.cpp | 15 | ||||
-rw-r--r-- | indra/newview/llnotificationhandler.h | 22 | ||||
-rw-r--r-- | indra/newview/llnotificationhandlerutil.cpp | 127 | ||||
-rw-r--r-- | indra/newview/llnotificationofferhandler.cpp | 57 | ||||
-rw-r--r-- | indra/newview/llnotificationtiphandler.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llscreenchannel.cpp | 4 | ||||
-rw-r--r-- | indra/newview/lltoastnotifypanel.cpp | 94 | ||||
-rw-r--r-- | indra/newview/lltoastnotifypanel.h | 10 | ||||
-rw-r--r-- | indra/newview/lltooldraganddrop.cpp | 38 | ||||
-rw-r--r-- | indra/newview/lltooldraganddrop.h | 4 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 20 | ||||
-rw-r--r-- | indra/newview/llviewermessage.h | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 1 |
19 files changed, 421 insertions, 55 deletions
diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index a9e1ee77ef..57e8a22546 100644 --- a/indra/llmessage/llinstantmessage.cpp +++ b/indra/llmessage/llinstantmessage.cpp @@ -61,6 +61,7 @@ const char EMPTY_BINARY_BUCKET[] = ""; const S32 EMPTY_BINARY_BUCKET_SIZE = 1; const U32 NO_TIMESTAMP = 0; const std::string SYSTEM_FROM("Second Life"); +const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B"); const S32 IM_TTL = 1; diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index 272e753f3c..f11b649f78 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -226,6 +226,7 @@ extern const S32 EMPTY_BINARY_BUCKET_SIZE; extern const U32 NO_TIMESTAMP; extern const std::string SYSTEM_FROM; +extern const std::string INTERACTIVE_SYSTEM_FROM; // Number of retry attempts on sending the im. extern const S32 IM_TTL; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 5816cef6af..7b8970a153 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -402,7 +402,8 @@ LLNotification::LLNotification(const LLNotification::Params& p) : mRespondedTo(false), mPriority(p.priority), mCancelled(false), - mIgnored(false) + mIgnored(false), + mResponderObj(NULL) { if (p.functor.name.isChosen()) { @@ -416,6 +417,11 @@ LLNotification::LLNotification(const LLNotification::Params& p) : mTemporaryResponder = true; } + if(p.responder.isProvided()) + { + mResponderObj = p.responder; + } + mId.generate(); init(p.name, p.form_elements); } @@ -425,7 +431,8 @@ LLNotification::LLNotification(const LLSD& sd) : mTemporaryResponder(false), mRespondedTo(false), mCancelled(false), - mIgnored(false) + mIgnored(false), + mResponderObj(NULL) { mId.generate(); mSubstitutions = sd["substitutions"]; @@ -563,7 +570,9 @@ void LLNotification::respond(const LLSD& response) // and then call it functor(asLLSD(), response); - if (mTemporaryResponder) + bool is_resusable = getPayload()["reusable"].asBoolean(); + + if (mTemporaryResponder && !is_resusable) { LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); mResponseFunctorName = ""; @@ -597,6 +606,16 @@ void LLNotification::setResponseFunctor(std::string const &responseFunctorName) mTemporaryResponder = false; } +void LLNotification::setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb) +{ + if(mTemporaryResponder) + { + LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName); + } + + LLNotificationFunctorRegistry::instance().registerFunctor(mResponseFunctorName, cb); +} + bool LLNotification::payloadContainsAll(const std::vector<std::string>& required_fields) const { for(std::vector<std::string>::const_iterator required_fields_it = required_fields.begin(); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 8d993b71d7..262633206b 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -296,6 +296,7 @@ public: Optional<LLSD> form_elements; Optional<LLDate> time_stamp; Optional<LLNotificationContext*> context; + Optional<void*> responder; struct Functor : public LLInitParam::Choice<Functor> { @@ -317,6 +318,7 @@ public: form_elements("form_elements") { time_stamp = LLDate::now(); + responder = NULL; } Params(const std::string& _name) @@ -329,6 +331,7 @@ public: functor.name = _name; name = _name; time_stamp = LLDate::now(); + responder = NULL; } }; @@ -344,6 +347,7 @@ private: bool mIgnored; ENotificationPriority mPriority; LLNotificationFormPtr mForm; + void* mResponderObj; // a reference to the template LLNotificationTemplatePtr mTemplatep; @@ -384,6 +388,8 @@ public: void setResponseFunctor(std::string const &responseFunctorName); + void setResponseFunctor(const LLNotificationFunctorRegistry::ResponseFunctor& cb); + typedef enum e_response_template_type { WITHOUT_DEFAULT_BUTTON, @@ -423,6 +429,10 @@ public: void respond(const LLSD& sd); + void* getResponder() { return mResponderObj; } + + void setResponder(void* responder) { mResponderObj = responder; } + void setIgnored(bool ignore); bool isCancelled() const diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index e1c96d4a16..911ac9c485 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -743,7 +743,9 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL ctrl_list_t ctrls = notify_box->getControlPanel()->getCtrlList(); S32 offset = 0; - for (ctrl_list_t::iterator it = ctrls.begin(); it != ctrls.end(); it++) + // Children were added by addChild() which uses push_front to insert them into list, + // so to get buttons in correct order reverse iterator is used (EXT-5906) + for (ctrl_list_t::reverse_iterator it = ctrls.rbegin(); it != ctrls.rend(); it++) { LLButton * button = dynamic_cast<LLButton*> (*it); if (button != NULL) diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 77eaebb0bc..f0e195c37a 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -454,7 +454,7 @@ void LLIMFloater::getAllowedRect(LLRect& rect) void LLIMFloater::setDocked(bool docked, bool pop_on_undock) { // update notification channel state - LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*> + LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); @@ -473,7 +473,7 @@ void LLIMFloater::setDocked(bool docked, bool pop_on_undock) void LLIMFloater::setVisible(BOOL visible) { - LLNotificationsUI::LLScreenChannel* channel = dynamic_cast<LLNotificationsUI::LLScreenChannel*> + LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> (LLNotificationsUI::LLChannelManager::getInstance()-> findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); LLTransientDockableFloater::setVisible(visible); @@ -642,6 +642,24 @@ void LLIMFloater::updateMessages() if (msg.has("notification_id")) { chat.mNotifId = msg["notification_id"].asUUID(); + // if notification exists - embed it + if (LLNotificationsUtil::find(chat.mNotifId) != NULL) + { + // remove embedded notification from channel + LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*> + (LLNotificationsUI::LLChannelManager::getInstance()-> + findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID")))); + if (getVisible()) + { + // toast will be automatically closed since it is not storable toast + channel->hideToast(chat.mNotifId); + } + } + // if notification doesn't exist - try to use next message which should be log entry + else + { + continue; + } } //process text message else @@ -651,6 +669,19 @@ void LLIMFloater::updateMessages() mChatHistory->appendMessage(chat, chat_args); mLastMessageIndex = msg["index"].asInteger(); + + // if it is a notification - next message is a notification history log, so skip it + if (chat.mNotifId.notNull() && LLNotificationsUtil::find(chat.mNotifId) != NULL) + { + if (++iter == iter_end) + { + break; + } + else + { + mLastMessageIndex++; + } + } } } } diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index b3f085ef6d..6ce06adc80 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -717,13 +717,22 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, return NULL; } - addToHistory(session_id, from, from_id, utf8_text); - if (log2file) logToFile(session_id, from, from_id, utf8_text); + // replace interactive system message marker with correct from string value + std::string from_name = from; + if (INTERACTIVE_SYSTEM_FROM == from) + { + from_name = SYSTEM_FROM; + } + + addToHistory(session_id, from_name, from_id, utf8_text); + if (log2file) logToFile(session_id, from_name, from_id, utf8_text); session->mNumUnread++; //update count of unread messages from real participant - if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from)) + if (!(from_id.isNull() || from_id == gAgentID || SYSTEM_FROM == from) + // we should increment counter for interactive system messages() + || INTERACTIVE_SYSTEM_FROM == from) { ++(session->mParticipantUnreadMessageCount); } diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index a163b6fd62..62daf5f105 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -298,6 +298,18 @@ public: static bool canSpawnSessionAndLogToIM(const LLNotificationPtr& notification); /** + * Checks if passed notification can create toast. + * + * It returns false only for inventory accepted/declined notifications if respective IM window is open (EXT-5909) + */ + static bool canSpawnToast(const LLNotificationPtr& notification); + + /** + * Determines whether IM floater is opened. + */ + static bool isIMFloaterOpened(const LLNotificationPtr& notification); + + /** * Writes notification message to IM session. */ static void logToIM(const EInstantMessage& session_type, @@ -343,6 +355,16 @@ public: * Adds notification panel to the IM floater. */ static void addNotifPanelToIM(const LLNotificationPtr& notification); + + /** + * Updates messages of visible IM floater. + */ + static void updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification); + + /** + * Decrements counter of IM messages. + */ + static void decIMMesageCounter(const LLNotificationPtr& notification); }; } diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 88bb769109..cb3d52fe13 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -127,7 +127,9 @@ const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), FRIENDSHIP_DECLINED_BYME("FriendshipDeclinedByMe"), FRIEND_ONLINE("FriendOnline"), FRIEND_OFFLINE("FriendOffline"), SERVER_OBJECT_MESSAGE("ServerObjectMessage"), - TELEPORT_OFFERED("TeleportOffered"); + TELEPORT_OFFERED("TeleportOffered"), + TELEPORT_OFFER_SENT("TeleportOfferSent"); + // static bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) @@ -137,11 +139,15 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) || PAYMENT_RECIVED == notification->getName() || OFFER_FRIENDSHIP == notification->getName() || FRIENDSHIP_OFFERED == notification->getName() + || FRIENDSHIP_ACCEPTED == notification->getName() || FRIENDSHIP_ACCEPTED_BYME == notification->getName() || FRIENDSHIP_DECLINED_BYME == notification->getName() || SERVER_OBJECT_MESSAGE == notification->getName() || INVENTORY_ACCEPTED == notification->getName() - || INVENTORY_DECLINED == notification->getName(); + || INVENTORY_DECLINED == notification->getName() + || USER_GIVE_ITEM == notification->getName() + || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFER_SENT == notification->getName(); } // static @@ -158,20 +164,18 @@ bool LLHandlerUtil::canLogToNearbyChat(const LLNotificationPtr& notification) bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() - || FRIENDSHIP_ACCEPTED == notification->getName() || USER_GIVE_ITEM == notification->getName() - || INVENTORY_ACCEPTED == notification->getName() - || INVENTORY_DECLINED == notification->getName(); + || TELEPORT_OFFERED == notification->getName(); } // static bool LLHandlerUtil::canAddNotifPanelToIM(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() - || USER_GIVE_ITEM == notification->getName(); + || USER_GIVE_ITEM == notification->getName() + || TELEPORT_OFFERED == notification->getName(); } - // static bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notification) { @@ -179,18 +183,57 @@ bool LLHandlerUtil::canSpawnSessionAndLogToIM(const LLNotificationPtr& notificat } // static +bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification) +{ + bool cannot_spawn = isIMFloaterOpened(notification) && (INVENTORY_DECLINED == notification->getName() + || INVENTORY_ACCEPTED == notification->getName()); + + return !cannot_spawn; +} + +// static +bool LLHandlerUtil::isIMFloaterOpened(const LLNotificationPtr& notification) +{ + bool res = false; + + LLUUID from_id = notification->getPayload()["from_id"]; + LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, + from_id); + + LLIMFloater* im_floater = LLFloaterReg::findTypedInstance<LLIMFloater>( + "impanel", session_id); + if (im_floater != NULL) + { + res = im_floater->getVisible() == TRUE; + } + + return res; +} + +// static void LLHandlerUtil::logToIM(const EInstantMessage& session_type, const std::string& session_name, const std::string& from_name, const std::string& message, const LLUUID& session_owner_id, const LLUUID& from_id) { + std::string from = from_name; + if (from_name.empty()) + { + from = SYSTEM_FROM; + } + LLUUID session_id = LLIMMgr::computeSessionID(session_type, session_owner_id); LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( session_id); if (session == NULL) { - LLIMModel::instance().logToFile(session_name, from_name, from_id, message); + // replace interactive system message marker with correct from string value + if (INTERACTIVE_SYSTEM_FROM == from_name) + { + from = SYSTEM_FROM; + } + LLIMModel::instance().logToFile(session_name, from, from_id, message); } else { @@ -201,7 +244,7 @@ void LLHandlerUtil::logToIM(const EInstantMessage& session_type, // set searched session as active to avoid IM toast popup LLIMModel::instance().setActiveSessionID(session_id); - LLIMModel::instance().addMessage(session_id, from_name, from_id, + LLIMModel::instance().addMessageSilently(session_id, from, from_id, message); // restore active session id @@ -250,13 +293,13 @@ void LLHandlerUtil::logToIMP2P(const LLNotificationPtr& notification, bool to_fi if(to_file_only) { - logToIM(IM_NOTHING_SPECIAL, session_name, name, notification->getMessage(), + logToIM(IM_NOTHING_SPECIAL, session_name, "", notification->getMessage(), LLUUID(), LLUUID()); } else { - logToIM(IM_NOTHING_SPECIAL, session_name, name, notification->getMessage(), - from_id, from_id); + logToIM(IM_NOTHING_SPECIAL, session_name, INTERACTIVE_SYSTEM_FROM, notification->getMessage(), + from_id, LLUUID()); } } } @@ -324,7 +367,14 @@ std::string LLHandlerUtil::getSubstitutionName(const LLNotificationPtr& notifica if (res.empty()) { LLUUID from_id = notification->getPayload()["FROM_ID"]; - gCacheName->getFullName(from_id, res); + if (from_id.isNull()) + { + from_id = notification->getPayload()["from_id"]; + } + if(!gCacheName->getFullName(from_id, res)) + { + res = ""; + } } return res; } @@ -343,11 +393,54 @@ void LLHandlerUtil::addNotifPanelToIM(const LLNotificationPtr& notification) LLSD offer; offer["notification_id"] = notification->getID(); - offer["from_id"] = notification->getPayload()["from_id"]; - offer["from"] = name; - offer["time"] = LLLogChat::timestamp(true); + offer["from"] = SYSTEM_FROM; + offer["time"] = LLLogChat::timestamp(false); offer["index"] = (LLSD::Integer)session->mMsgs.size(); session->mMsgs.push_front(offer); - LLIMFloater::show(session_id); + + // update IM floater and counters + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = ++(session->mNumUnread); + arg["participant_unread"] = ++(session->mParticipantUnreadMessageCount); + LLIMModel::getInstance()->mNewMsgSignal(arg); +} + +// static +void LLHandlerUtil::updateVisibleIMFLoaterMesages(const LLNotificationPtr& notification) +{ + const std::string name = LLHandlerUtil::getSubstitutionName(notification); + LLUUID from_id = notification->getPayload()["from_id"]; + LLUUID session_id = spawnIMSession(name, from_id); + + LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + if (im_floater != NULL && im_floater->getVisible()) + { + im_floater->updateMessages(); + } +} + +// static +void LLHandlerUtil::decIMMesageCounter(const LLNotificationPtr& notification) +{ + const std::string name = LLHandlerUtil::getSubstitutionName(notification); + LLUUID from_id = notification->getPayload()["from_id"]; + LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, from_id); + + LLIMModel::LLIMSession * session = LLIMModel::getInstance()->findIMSession( + session_id); + + if (session == NULL) + { + return; + } + + LLSD arg; + arg["session_id"] = session_id; + session->mNumUnread--; + arg["num_unread"] = session->mNumUnread; + session->mParticipantUnreadMessageCount--; + arg["participant_unread"] = session->mParticipantUnreadMessageCount; + LLIMModel::getInstance()->mNewMsgSignal(arg); } diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 8ebd5de258..0a42d8adbe 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -113,35 +113,58 @@ bool LLOfferHandler::processNotification(const LLSD& notify) session_id = LLHandlerUtil::spawnIMSession(name, from_id); } - if (LLHandlerUtil::canAddNotifPanelToIM(notification)) + bool show_toast = true; + bool add_notid_to_im = LLHandlerUtil::canAddNotifPanelToIM(notification); + if (add_notid_to_im) { LLHandlerUtil::addNotifPanelToIM(notification); - LLHandlerUtil::logToIMP2P(notification, true); + if (LLHandlerUtil::isIMFloaterOpened(notification)) + { + show_toast = false; + } } - else if (notification->getPayload().has("SUPPRESS_TOAST") + + if (notification->getPayload().has("SUPPRESS_TOAST") && notification->getPayload()["SUPPRESS_TOAST"]) { - LLHandlerUtil::logToIMP2P(notification); LLNotificationsUtil::cancel(notification); } - else + else if(show_toast) { LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification); - + // don't close notification on panel destroy since it will be used by IM floater + notify_box->setCloseNotificationOnDestroy(!add_notid_to_im); LLToast::Params p; p.notif_id = notification->getID(); p.notification = notification; p.panel = notify_box; p.on_delete_toast = boost::bind(&LLOfferHandler::onDeleteToast, this, _1); + // we not save offer notifications to the syswell floater that should be added to the IM floater + p.can_be_stored = !add_notid_to_im; LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel); if(channel) channel->addToast(p); - LLHandlerUtil::logToIMP2P(notification); + // if we not add notification to IM - add it to notification well + if (!add_notid_to_im) + { + // send a signal to the counter manager + mNewNotificationSignal(); + } + } - // send a signal to the counter manager - mNewNotificationSignal(); + if (LLHandlerUtil::canLogToIM(notification)) + { + // log only to file if notif panel can be embedded to IM and IM is opened + if (add_notid_to_im && LLHandlerUtil::isIMFloaterOpened(notification)) + { + LLHandlerUtil::logToIMP2P(notification, true); + } + else + { + LLHandlerUtil::logToIMP2P(notification); + } } } } @@ -155,6 +178,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify) } else { + if (LLHandlerUtil::canAddNotifPanelToIM(notification) + && !LLHandlerUtil::isIMFloaterOpened(notification)) + { + LLHandlerUtil::decIMMesageCounter(notification); + } mChannel->killToastByNotificationID(notification->getID()); } } @@ -166,8 +194,11 @@ bool LLOfferHandler::processNotification(const LLSD& notify) void LLOfferHandler::onDeleteToast(LLToast* toast) { - // send a signal to the counter manager - mDelNotificationSignal(); + if (!LLHandlerUtil::canAddNotifPanelToIM(toast->getNotification())) + { + // send a signal to the counter manager + mDelNotificationSignal(); + } // send a signal to a listener to let him perform some action // in this case listener is a SysWellWindow and it will remove a corresponding item from its list @@ -181,7 +212,9 @@ void LLOfferHandler::onRejectToast(LLUUID& id) if (notification && LLNotificationManager::getInstance()->getHandlerForNotification( - notification->getType()) == this) + notification->getType()) == this + // don't delete notification since it may be used by IM floater + && !LLHandlerUtil::canAddNotifPanelToIM(notification)) { LLNotifications::instance().cancel(notification); } diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 4e2c5085ed..1f1afe293a 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -150,6 +150,12 @@ bool LLTipHandler::processNotification(const LLSD& notify) LLHandlerUtil::spawnIMSession(name, from_id); } + // don't spawn toast for inventory accepted/declined offers if respective IM window is open (EXT-5909) + if (!LLHandlerUtil::canSpawnToast(notification)) + { + return true; + } + LLToastPanel* notify_box = NULL; if("FriendOffline" == notification->getName() || "FriendOnline" == notification->getName()) { diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index a4426b370e..dffb5e5e12 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -710,9 +710,7 @@ void LLScreenChannel::hideToast(const LLUUID& notification_id) if(mToastList.end() != it) { ToastElem te = *it; - te.toast->setVisible(FALSE); - te.toast->stopTimer(); - mToastList.erase(it); + te.toast->hide(); } } diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index e6d13a7613..77d1d1fc0b 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -44,6 +44,7 @@ #include "llrect.h" #include "lltrans.h" #include "llnotificationsutil.h" +#include "llviewermessage.h" const S32 BOTTOM_PAD = VPAD * 3; const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding @@ -60,7 +61,8 @@ mInfoPanel(NULL), mControlPanel(NULL), mNumOptions(0), mNumButtons(0), -mAddedDefaultBtn(false) +mAddedDefaultBtn(false), +mCloseNotificationOnDestroy(true) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_notification.xml"); if(rect != LLRect::null) @@ -193,6 +195,8 @@ mAddedDefaultBtn(false) // we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed adjustPanelForScriptNotice(button_panel_width, button_panel_height); updateButtonsLayout(buttons, h_pad); + // save buttons for later use in disableButtons() + mButtons.assign(buttons.begin(), buttons.end()); } } // adjust panel's height to the text size @@ -266,7 +270,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt LLToastNotifyPanel::~LLToastNotifyPanel() { std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer()); - if (LLNotificationsUtil::find(mNotification->getID()) != NULL) + if (mCloseNotificationOnDestroy && LLNotificationsUtil::find(mNotification->getID()) != NULL) { LLNotifications::getInstance()->cancel(mNotification); } @@ -342,6 +346,63 @@ void LLToastNotifyPanel::adjustPanelForTipNotice() } } +typedef std::set<std::string> button_name_set_t; +typedef std::map<std::string, button_name_set_t> disable_button_map_t; + +disable_button_map_t initUserGiveItemDisableButtonMap() +{ + // see EXT-5905 for disable rules + + disable_button_map_t disable_map; + button_name_set_t buttons; + + buttons.insert("Show"); + disable_map.insert(std::make_pair("Show", buttons)); + + buttons.insert("Discard"); + disable_map.insert(std::make_pair("Discard", buttons)); + + buttons.insert("Mute"); + disable_map.insert(std::make_pair("Mute", buttons)); + + return disable_map; +} + +button_name_set_t getButtonDisableList(const std::string& notification_name, const std::string& button_name) +{ + static disable_button_map_t user_give_item_disable_map = initUserGiveItemDisableButtonMap(); + + disable_button_map_t::const_iterator it; + disable_button_map_t::const_iterator it_end; + + if("UserGiveItem" == notification_name) + { + it = user_give_item_disable_map.find(button_name); + it_end = user_give_item_disable_map.end(); + } + + if(it_end != it) + { + return it->second; + } + return button_name_set_t(); +} + +void LLToastNotifyPanel::disableButtons(const std::string& notification_name, const std::string& selected_button) +{ + button_name_set_t buttons = getButtonDisableList(notification_name, selected_button); + + std::vector<index_button_pair_t>::const_iterator it = mButtons.begin(); + for ( ; it != mButtons.end(); it++) + { + LLButton* btn = it->second; + if(buttons.find(btn->getName()) != buttons.end()) + { + btn->setEnabled(FALSE); + } + } +} + // static void LLToastNotifyPanel::onClickButton(void* data) { @@ -354,8 +415,33 @@ void LLToastNotifyPanel::onClickButton(void* data) { response[button_name] = true; } + + bool is_reusable = self->mNotification->getPayload()["reusable"].asBoolean(); + // When we call respond(), LLOfferInfo will delete itself in inventory_offer_callback(), + // lets copy it while it's still valid. + LLOfferInfo* old_info = static_cast<LLOfferInfo*>(self->mNotification->getResponder()); + LLOfferInfo* new_info = NULL; + if(is_reusable && old_info) + { + new_info = new LLOfferInfo(*old_info); + self->mNotification->setResponder(new_info); + } + self->mNotification->respond(response); - // disable all buttons - self->mControlPanel->setEnabled(FALSE); + if(is_reusable) + { + self->disableButtons(self->mNotification->getName(), button_name); + + if(new_info) + { + self->mNotification->setResponseFunctor( + boost::bind(&LLOfferInfo::inventory_offer_callback, new_info, _1, _2)); + } + } + else + { + // disable all buttons + self->mControlPanel->setEnabled(FALSE); + } } diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h index 152975e7de..1539c613af 100644 --- a/indra/newview/lltoastnotifypanel.h +++ b/indra/newview/lltoastnotifypanel.h @@ -65,6 +65,7 @@ public: virtual ~LLToastNotifyPanel(); LLPanel * getControlPanel() { return mControlPanel; } + void setCloseNotificationOnDestroy(bool close) { mCloseNotificationOnDestroy = close; } protected: LLButton* createButton(const LLSD& form_element, BOOL is_option); @@ -76,6 +77,8 @@ protected: }; std::vector<InstanceAndS32*> mBtnCallbackData; + bool mCloseNotificationOnDestroy; + private: typedef std::pair<int,LLButton*> index_button_pair_t; @@ -90,6 +93,13 @@ private: */ void updateButtonsLayout(const std::vector<index_button_pair_t>& buttons, S32 h_pad); + /** + * Disable specific button(s) based on notification name and clicked button + */ + void disableButtons(const std::string& notification_name, const std::string& selected_button); + + std::vector<index_button_pair_t> mButtons; + // panel elements LLTextBase* mTextBox; LLPanel* mInfoPanel; // a panel, that contains an information diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 125c62474e..08f874d1d2 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -1503,15 +1503,38 @@ void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent, LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); + logInventoryOffer(to_agent, im_session_id); + + // add buddy to recent people list + LLRecentPeople::instance().add(to_agent); +} + +//static +void LLToolDragAndDrop::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im_session_id) +{ + // compute id of possible IM session with agent that has "to_agent" id + LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, to_agent); // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. - if (im_session_id != LLUUID::null) + if (im_session_id.notNull()) { LLSD args; gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } - - // add buddy to recent people list - LLRecentPeople::instance().add(to_agent); + // If this item was given by drag-and-drop on avatar while IM panel was open, log this action in the IM panel chat. + else if (LLIMModel::getInstance()->findIMSession(session_id)) + { + LLSD args; + gIMMgr->addSystemMessage(session_id, "inventory_item_offered", args); + } + // If this item was given by drag-and-drop on avatar while IM panel wasn't open, log this action to IM history. + else + { + std::string full_name; + if (gCacheName->getFullName(to_agent, full_name)) + { + LLIMModel::instance().logToFile(full_name, LLTrans::getString("SECOND_LIFE"), im_session_id, LLTrans::getString("inventory_item_offered")); + } + } } void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, @@ -1723,12 +1746,7 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, LLMuteList::getInstance()->autoRemove(to_agent, LLMuteList::AR_INVENTORY); - // If this item was given by drag-and-drop into an IM panel, log this action in the IM panel chat. - if (im_session_id != LLUUID::null) - { - LLSD args; - gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); - } + logInventoryOffer(to_agent, im_session_id); } } diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 79b2bc32a3..0da13dac8b 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -227,6 +227,10 @@ protected: LLInventoryCategory* cat, const LLUUID &im_session_id = LLUUID::null); + // log "Inventory item offered" to IM + static void logInventoryOffer(const LLUUID& to_agent, + const LLUUID &im_session_id = LLUUID::null); + public: // helper functions static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b90e3dcda4..e6cf6e45ac 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1081,6 +1081,21 @@ LLOfferInfo::LLOfferInfo(const LLSD& sd) mHost = LLHost(sd["sender"].asString()); } +LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) +{ + mIM = info.mIM; + mFromID = info.mFromID; + mFromGroup = info.mFromGroup; + mFromObject = info.mFromObject; + mTransactionID = info.mTransactionID; + mFolderID = info.mFolderID; + mObjectID = info.mObjectID; + mType = info.mType; + mFromName = info.mFromName; + mDesc = info.mDesc; + mHost = info.mHost; +} + LLSD LLOfferInfo::asLLSD() { LLSD sd; @@ -1570,7 +1585,12 @@ void inventory_offer_handler(LLOfferInfo* info) } else // Agent -> Agent Inventory Offer { + payload["reusable"] = true; + p.responder = info; // Note: sets inventory_offer_callback as the callback + // *TODO fix memory leak + // inventory_offer_callback() is not invoked if user received notification and + // closes viewer(without responding the notification) p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); p.name = "UserGiveItem"; diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 7dd629dcfd..88f9697037 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -215,6 +215,8 @@ struct LLOfferInfo mIM(IM_NOTHING_SPECIAL), mType(LLAssetType::AT_NONE) {}; LLOfferInfo(const LLSD& sd); + LLOfferInfo(const LLOfferInfo& info); + void forceResponse(InventoryOfferResponse response); EInstantMessage mIM; diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 4b9140ee90..338612664a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -2915,6 +2915,7 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="IM_default_text_label">Click here to instant message.</string> <string name="IM_to_label">To</string> <string name="IM_moderator_label">(Moderator)</string> + <string name="inventory_item_offered">Inventory item offered</string> <!-- voice calls --> <string name="started_call">Started a voice call</string> |