diff options
Diffstat (limited to 'indra')
| -rwxr-xr-x | indra/llui/CMakeLists.txt | 2 | ||||
| -rwxr-xr-x | indra/llui/llnotifications.cpp | 1 | ||||
| -rwxr-xr-x | indra/llui/llnotifications.h | 4 | ||||
| -rw-r--r-- | indra/llui/llnotificationslistener.cpp | 359 | ||||
| -rw-r--r-- | indra/llui/llnotificationslistener.h | 69 | 
5 files changed, 435 insertions, 0 deletions
| diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index aa6684e7a8..589ceac501 100755 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -75,6 +75,7 @@ set(llui_SOURCE_FILES      llmultislider.cpp      llmultisliderctrl.cpp      llnotifications.cpp +    llnotificationslistener.cpp      llnotificationsutil.cpp      llpanel.cpp      llprogressbar.cpp @@ -184,6 +185,7 @@ set(llui_HEADER_FILES      llmultislider.h      llnotificationptr.h      llnotifications.h +    llnotificationslistener.h      llnotificationsutil.h      llnotificationtemplate.h      llnotificationvisibilityrule.h diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 1789f003b9..743d34c57b 100755 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1206,6 +1206,7 @@ LLNotifications::LLNotifications()  :	LLNotificationChannelBase(LLNotificationFilters::includeEverything),  	mIgnoreAllNotifications(false)  { +        mListener.reset(new LLNotificationsListener(*this));  	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));  } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 87573c2a56..9037712cc8 100755 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -98,6 +98,8 @@  #include "llrefcount.h"  #include "llsdparam.h" +#include "llnotificationslistener.h" +  class LLAvatarName;  typedef enum e_notification_priority  { @@ -970,6 +972,8 @@ private:  	bool mIgnoreAllNotifications; +	boost::scoped_ptr<LLNotificationsListener> mListener; +  	std::vector<LLNotificationChannelPtr> mDefaultChannels;  }; diff --git a/indra/llui/llnotificationslistener.cpp b/indra/llui/llnotificationslistener.cpp new file mode 100644 index 0000000000..9e8e943ee6 --- /dev/null +++ b/indra/llui/llnotificationslistener.cpp @@ -0,0 +1,359 @@ +/** + * @file   llnotificationslistener.cpp + * @author Brad Kittenbrink + * @date   2009-07-08 + * @brief  Implementation for llnotificationslistener. + *  + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llnotificationslistener.h" +#include "llnotifications.h" +#include "llnotificationtemplate.h" +#include "llsd.h" +#include "llui.h" + +LLNotificationsListener::LLNotificationsListener(LLNotifications & notifications) : +    LLEventAPI("LLNotifications", +               "LLNotifications listener to (e.g.) pop up a notification"), +    mNotifications(notifications) +{ +    add("requestAdd", +        "Add a notification with specified [\"name\"], [\"substitutions\"] and [\"payload\"].\n" +        "If optional [\"reply\"] specified, arrange to send user response on that LLEventPump.", +        &LLNotificationsListener::requestAdd); +    /*    add("listChannels", +        "Post to [\"reply\"] a map of info on existing channels", +        &LLNotificationsListener::listChannels, +        LLSD().with("reply", LLSD())); +    */ +    add("listChannelNotifications", +        "Post to [\"reply\"] an array of info on notifications in channel [\"channel\"]", +        &LLNotificationsListener::listChannelNotifications, +        LLSD().with("reply", LLSD()).with("channel", LLSD())); +    add("respond", +        "Respond to notification [\"uuid\"] with data in [\"response\"]", +        &LLNotificationsListener::respond, +        LLSD().with("uuid", LLSD())); +    add("cancel", +        "Cancel notification [\"uuid\"]", +        &LLNotificationsListener::cancel, +        LLSD().with("uuid", LLSD())); +    add("ignore", +        "Ignore future notification [\"name\"]\n" +        "(from <notification name= > in notifications.xml)\n" +        "according to boolean [\"ignore\"].\n" +        "If [\"name\"] is omitted or undefined, [un]ignore all future notifications.\n" +        "Note that ignored notifications are not forwarded unless intercepted before\n" +        "the \"Ignore\" channel.", +        &LLNotificationsListener::ignore); +    add("forward", +        "Forward to [\"pump\"] future notifications on channel [\"channel\"]\n" +        "according to boolean [\"forward\"]. When enabled, only types matching\n" +        "[\"types\"] are forwarded, as follows:\n" +        "omitted or undefined: forward all notifications\n" +        "string: forward only the specific named [sig]type\n" +        "array of string: forward any notification matching any named [sig]type.\n" +        "When boolean [\"respond\"] is true, we auto-respond to each forwarded\n" +        "notification.", +        &LLNotificationsListener::forward, +        LLSD().with("channel", LLSD())); +} + +// This is here in the .cpp file so we don't need the definition of class +// Forwarder in the header file. +LLNotificationsListener::~LLNotificationsListener() +{ +} + +void LLNotificationsListener::requestAdd(const LLSD& event_data) const +{ +	if(event_data.has("reply")) +	{ +		mNotifications.add(event_data["name"],  +						   event_data["substitutions"],  +						   event_data["payload"], +						   boost::bind(&LLNotificationsListener::NotificationResponder,  +									   this,  +									   event_data["reply"].asString(),  +									   _1, _2 +									   ) +						   ); +	} +	else +	{ +		mNotifications.add(event_data["name"],  +						   event_data["substitutions"],  +						   event_data["payload"]); +	} +} + +void LLNotificationsListener::NotificationResponder(const std::string& reply_pump,  +										const LLSD& notification,  +										const LLSD& response) const +{ +	LLSD reponse_event; +	reponse_event["notification"] = notification; +	reponse_event["response"] = response; +	LLEventPumps::getInstance()->obtain(reply_pump).post(reponse_event); +} +/* +void LLNotificationsListener::listChannels(const LLSD& params) const +{ +    LLReqID reqID(params); +    LLSD response(reqID.makeResponse()); +    for (LLNotifications:: + + + +    for (LLNotifications::ChannelMap::const_iterator cmi(mNotifications.mChannels.begin()), +                                                     cmend(mNotifications.mChannels.end()); +         cmi != cmend; ++cmi) +    { +        LLSD channelInfo; +        channelInfo["parent"] = cmi->second->getParentChannelName(); +        response[cmi->first] = channelInfo; +    } +    LLEventPumps::instance().obtain(params["reply"]).post(response); +} +*/ +void LLNotificationsListener::listChannelNotifications(const LLSD& params) const +{ +    LLReqID reqID(params); +    LLSD response(reqID.makeResponse()); +    LLNotificationChannelPtr channel(mNotifications.getChannel(params["channel"])); +    if (channel) +    { +        LLSD notifications(LLSD::emptyArray()); +        for (LLNotificationChannel::Iterator ni(channel->begin()), nend(channel->end()); +             ni != nend; ++ni) +        { +            notifications.append(asLLSD(*ni)); +        } +        response["notifications"] = notifications; +    } +    LLEventPumps::instance().obtain(params["reply"]).post(response); +} + +void LLNotificationsListener::respond(const LLSD& params) const +{ +    LLNotificationPtr notification(mNotifications.find(params["uuid"])); +    if (notification) +    { +        notification->respond(params["response"]); +    } +} + +void LLNotificationsListener::cancel(const LLSD& params) const +{ +    LLNotificationPtr notification(mNotifications.find(params["uuid"])); +    if (notification) +    { +        mNotifications.cancel(notification); +    } +} + +void LLNotificationsListener::ignore(const LLSD& params) const +{ +    // Calling a method named "ignore", but omitting its "ignore" Boolean +    // argument, should by default cause something to be ignored. Explicitly +    // pass ["ignore"] = false to cancel ignore. +    bool ignore = true; +    if (params.has("ignore")) +    { +        ignore = params["ignore"].asBoolean(); +    } +    // This method can be used to affect either a single notification name or +    // all future notifications. The two use substantially different mechanisms. +    if (params["name"].isDefined()) +    { +        // ["name"] was passed: ignore just that notification +		LLNotificationTemplatePtr templatep = mNotifications.getTemplate(params["name"]); +		if (templatep) +		{ +			templatep->mForm->setIgnored(ignore); +		} +    } +    else +    { +        // no ["name"]: ignore all future notifications +        mNotifications.setIgnoreAllNotifications(ignore); +    } +} + +class LLNotificationsListener::Forwarder: public LLEventTrackable +{ +    LOG_CLASS(LLNotificationsListener::Forwarder); +public: +    Forwarder(LLNotifications& llnotifications, const std::string& channel): +        mNotifications(llnotifications), +        mRespond(false) +    { +        // Connect to the specified channel on construction. Because +        // LLEventTrackable is a base, we should automatically disconnect when +        // destroyed. +        LLNotificationChannelPtr channelptr(llnotifications.getChannel(channel)); +        if (channelptr) +        { +            // Insert our processing as a "passed filter" listener. This way +            // we get to run before all the "changed" listeners, and we get to +            // swipe it (hide it from the other listeners) if desired. +            channelptr->connectPassedFilter(boost::bind(&Forwarder::handle, this, _1)); +        } +    } + +    void setPumpName(const std::string& name) { mPumpName = name; } +    void setTypes(const LLSD& types) { mTypes = types; } +    void setRespond(bool respond) { mRespond = respond; } + +private: +    bool handle(const LLSD& notification) const; +    bool matchType(const LLSD& filter, const std::string& type) const; + +    LLNotifications& mNotifications; +    std::string mPumpName; +    LLSD mTypes; +    bool mRespond; +}; + +void LLNotificationsListener::forward(const LLSD& params) +{ +    std::string channel(params["channel"]); +    // First decide whether we're supposed to start forwarding or stop it. +    // Default to true. +    bool forward = true; +    if (params.has("forward")) +    { +        forward = params["forward"].asBoolean(); +    } +    if (! forward) +    { +        // This is a request to stop forwarding notifications on the specified +        // channel. The rest of the params don't matter. +        // Because mForwarders contains scoped_ptrs, erasing the map entry +        // DOES delete the heap Forwarder object. Because Forwarder derives +        // from LLEventTrackable, destroying it disconnects it from the +        // channel. +        mForwarders.erase(channel); +        return; +    } +    // From here on, we know we're being asked to start (or modify) forwarding +    // on the specified channel. Find or create an appropriate Forwarder. +    ForwarderMap::iterator +        entry(mForwarders.insert(ForwarderMap::value_type(channel, ForwarderMap::mapped_type())).first); +    if (! entry->second) +    { +        entry->second.reset(new Forwarder(mNotifications, channel)); +    } +    // Now, whether this Forwarder is brand-new or not, update it with the new +    // request info. +    Forwarder& fwd(*entry->second); +    fwd.setPumpName(params["pump"]); +    fwd.setTypes(params["types"]); +    fwd.setRespond(params["respond"]); +} + +bool LLNotificationsListener::Forwarder::handle(const LLSD& notification) const +{ +    LL_INFOS("LLNotificationsListener") << "handle(" << notification << ")" << LL_ENDL; +    if (notification["sigtype"].asString() == "delete") +    { +        LL_INFOS("LLNotificationsListener") << "ignoring delete" << LL_ENDL; +        // let other listeners see the "delete" operation +        return false; +    } +    LLNotificationPtr note(mNotifications.find(notification["id"])); +    if (! note) +    { +        LL_INFOS("LLNotificationsListener") << notification["id"] << " not found" << LL_ENDL; +        return false; +    } +    if (! matchType(mTypes, note->getType())) +    { +        LL_INFOS("LLNotificationsListener") << "didn't match types " << mTypes << LL_ENDL; +        // We're not supposed to intercept this particular notification. Let +        // other listeners process it. +        return false; +    } +    LL_INFOS("LLNotificationsListener") << "sending via '" << mPumpName << "'" << LL_ENDL; +    // This is a notification we care about. Forward it through specified +    // LLEventPump. +    LLEventPumps::instance().obtain(mPumpName).post(asLLSD(note)); +    // Are we also being asked to auto-respond? +    if (mRespond) +    { +        LL_INFOS("LLNotificationsListener") << "should respond" << LL_ENDL; +        note->respond(LLSD::emptyMap()); +        // Did that succeed in removing the notification? Only cancel() if +        // it's still around -- otherwise we get an LL_ERRS crash! +        note = mNotifications.find(notification["id"]); +        if (note) +        { +            LL_INFOS("LLNotificationsListener") << "respond() didn't clear, canceling" << LL_ENDL; +            mNotifications.cancel(note); +        } +    } +    // If we've auto-responded to this notification, then it's going to be +    // deleted. Other listeners would get the change operation, try to look it +    // up and be baffled by lookup failure. So when we auto-respond, suppress +    // this notification: don't pass it to other listeners. +    return mRespond; +} + +bool LLNotificationsListener::Forwarder::matchType(const LLSD& filter, const std::string& type) const +{ +    // Decide whether this notification matches filter: +    // undefined: forward all notifications +    if (filter.isUndefined()) +    { +        return true; +    } +    // array of string: forward any notification matching any named type +    if (filter.isArray()) +    { +        for (LLSD::array_const_iterator ti(filter.beginArray()), tend(filter.endArray()); +             ti != tend; ++ti) +        { +            if (ti->asString() == type) +            { +                return true; +            } +        } +        // Didn't match any entry in the array +        return false; +    } +    // string: forward only the specific named type +    return (filter.asString() == type); +} + +LLSD LLNotificationsListener::asLLSD(LLNotificationPtr note) +{ +    LLSD notificationInfo(note->asLLSD()); +    // For some reason the following aren't included in LLNotification::asLLSD(). +    notificationInfo["summary"] = note->summarize(); +    notificationInfo["id"]      = note->id(); +    notificationInfo["type"]    = note->getType(); +    notificationInfo["message"] = note->getMessage(); +    notificationInfo["label"]   = note->getLabel(); +    return notificationInfo; +} diff --git a/indra/llui/llnotificationslistener.h b/indra/llui/llnotificationslistener.h new file mode 100644 index 0000000000..f9f7641de6 --- /dev/null +++ b/indra/llui/llnotificationslistener.h @@ -0,0 +1,69 @@ +/** + * @file   llnotificationslistener.h + * @author Brad Kittenbrink + * @date   2009-07-08 + * @brief  Wrap subset of LLNotifications API in event API for test scripts. + *  + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLNOTIFICATIONSLISTENER_H +#define LL_LLNOTIFICATIONSLISTENER_H + +#include "lleventapi.h" +#include "llnotificationptr.h" +#include <boost/shared_ptr.hpp> +#include <map> +#include <string> + +class LLNotifications; +class LLSD; + +class LLNotificationsListener : public LLEventAPI +{ +public: +    LLNotificationsListener(LLNotifications & notifications); +    ~LLNotificationsListener(); + +private: +    void requestAdd(LLSD const & event_data) const; + +	void NotificationResponder(const std::string& replypump,  +							   const LLSD& notification,  +							   const LLSD& response) const; + +    void listChannels(const LLSD& params) const; +    void listChannelNotifications(const LLSD& params) const; +    void respond(const LLSD& params) const; +    void cancel(const LLSD& params) const; +    void ignore(const LLSD& params) const; +    void forward(const LLSD& params); + +    static LLSD asLLSD(LLNotificationPtr); + +    class Forwarder; +    typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap; +    ForwarderMap mForwarders; +	LLNotifications & mNotifications; +}; + +#endif // LL_LLNOTIFICATIONSLISTENER_H | 
