Merge Firestorm LGPL tip

master
Ansariel 2015-07-02 16:40:38 +02:00
commit bc85a86b3b
518 changed files with 17495 additions and 3288 deletions

View File

@ -1,6 +1,5 @@
syntax: glob
# WinMerge temp files
*.bak
# Compiled python bytecode

View File

@ -533,3 +533,4 @@ afd8d4756e8eda3c8f760625d1c17a2ad40ad6c8 3.7.27-release
566874eb5ab26c003ef7fb0e22ce40c5fa0013f4 3.7.28-release
d07f76c5b9860fb87924d00ca729f7d4532534d6 3.7.29-release
67edc442c80b8d2fadd2a6c4a7184b469906cdbf 3.7.30-release
797ed69e6134ef48bb922577ab2540fb2d964668 3.8.0-release

View File

@ -70,6 +70,12 @@ additional_packages = ""
# the viewer_channel_suffix is prefixed by a blank and then appended to the viewer_channel
# for the package in a setting that overrides the compiled-in value
################################################################
additional_packages = "EDU"
# The EDU package allows us to create a separate release channel whose expirations
# are synchronized as much as possible with the academic year
EDU_sourceid = ""
EDU_viewer_channel_suffix = "edu"
# Notifications - to configure email notices, add a setting like this:
# <username>_<reponame>.email = <email-address>

View File

@ -18,7 +18,7 @@ else (USESYSTEMLIBS)
use_prebuilt_binary(SDL)
set (SDL_FOUND TRUE)
set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/i686-linux)
set (SDL_LIBRARY SDL directfb fusion direct)
set (SDL_LIBRARY SDL directfb fusion direct X11)
endif (LINUX)
endif (USESYSTEMLIBS)

View File

@ -1163,8 +1163,17 @@ bool LLImageTGA::loadFile( const std::string& path )
{
return false;
}
//< FS:ND> FIRE-16342 make sure no one overwrites this file while we load it
// LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
#ifndef LL_WINDOWS
LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */
#else
LLFILE* file = LLFile::_fsopen(path, "rb", _SH_DENYWR);/* Flawfinder: ignore */
#endif
// </FS:ND:
if( !file )
{
LL_WARNS() << "Couldn't open file " << path << LL_ENDL;

View File

@ -40,6 +40,8 @@
#include "llsdutil_math.h"
#include "message.h"
#include "u64.h"
#include "llregionflags.h"
#include <boost/range/adaptor/map.hpp>
static const F32 SOME_BIG_NUMBER = 1000.0f;
static const F32 SOME_BIG_NEG_NUMBER = -1000.0f;
@ -627,8 +629,8 @@ void LLParcel::unpackMessage(LLMessageSystem* msg)
void LLParcel::packAccessEntries(LLMessageSystem* msg,
const std::map<LLUUID,LLAccessEntry>& list)
{
access_map_const_iterator cit = list.begin();
access_map_const_iterator end = list.end();
LLAccessEntry::map::const_iterator cit = list.begin();
LLAccessEntry::map::const_iterator end = list.end();
if (cit == end)
{
@ -679,9 +681,28 @@ void LLParcel::unpackAccessEntries(LLMessageSystem* msg,
}
void LLParcel::unpackExperienceEntries( LLMessageSystem* msg, U32 type )
{
LLUUID id;
S32 i;
S32 count = msg->getNumberOfBlocksFast(_PREHASH_List);
for (i = 0; i < count; i++)
{
msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i);
if (id.notNull())
{
mExperienceKeys[id]=type;
}
}
}
void LLParcel::expirePasses(S32 now)
{
access_map_iterator itor = mAccessList.begin();
LLAccessEntry::map::iterator itor = mAccessList.begin();
while (itor != mAccessList.end())
{
const LLAccessEntry& entry = (*itor).second;
@ -771,7 +792,7 @@ BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time)
// Can't add owner to these lists
return FALSE;
}
access_map_iterator itor = mAccessList.begin();
LLAccessEntry::map::iterator itor = mAccessList.begin();
while (itor != mAccessList.end())
{
const LLAccessEntry& entry = (*itor).second;
@ -814,7 +835,7 @@ BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time)
return FALSE;
}
access_map_iterator itor = mBanList.begin();
LLAccessEntry::map::iterator itor = mBanList.begin();
while (itor != mBanList.end())
{
const LLAccessEntry& entry = (*itor).second;
@ -849,7 +870,7 @@ BOOL remove_from_access_array(std::map<LLUUID,LLAccessEntry>* list,
const LLUUID& agent_id)
{
BOOL removed = FALSE;
access_map_iterator itor = list->begin();
LLAccessEntry::map::iterator itor = list->begin();
while (itor != list->end())
{
const LLAccessEntry& entry = (*itor).second;
@ -1192,3 +1213,58 @@ LLParcel::ECategory category_ui_string_to_category(const std::string& s)
// is a distinct option from "None" and "Other"
return LLParcel::C_ANY;
}
LLAccessEntry::map LLParcel::getExperienceKeysByType( U32 type ) const
{
LLAccessEntry::map access;
LLAccessEntry entry;
xp_type_map_t::const_iterator it = mExperienceKeys.begin();
for(/**/; it != mExperienceKeys.end(); ++it)
{
if(it->second == type)
{
entry.mID = it->first;
access[entry.mID] = entry;
}
}
return access;
}
void LLParcel::clearExperienceKeysByType( U32 type )
{
xp_type_map_t::iterator it = mExperienceKeys.begin();
while(it != mExperienceKeys.end())
{
if(it->second == type)
{
mExperienceKeys.erase(it++);
}
else
{
++it;
}
}
}
void LLParcel::setExperienceKeyType( const LLUUID& experience_key, U32 type )
{
if(type == EXPERIENCE_KEY_TYPE_NONE)
{
mExperienceKeys.erase(experience_key);
}
else
{
if(countExperienceKeyType(type) < PARCEL_MAX_EXPERIENCE_LIST)
{
mExperienceKeys[experience_key] = type;
}
}
}
U32 LLParcel::countExperienceKeyType( U32 type )
{
return std::count_if(
boost::begin(mExperienceKeys | boost::adaptors::map_values),
boost::end(mExperienceKeys | boost::adaptors::map_values),
std::bind2nd(std::equal_to<U32>(), type));
}

View File

@ -53,6 +53,9 @@ const S32 PARCEL_MAX_ACCESS_LIST = 300;
//for access/ban lists.
const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f;
// Maximum number of experiences
const S32 PARCEL_MAX_EXPERIENCE_LIST = 24;
// Weekly charge for listing a parcel in the directory
const S32 PARCEL_DIRECTORY_FEE = 30;
@ -130,9 +133,11 @@ class LLSD;
class LLAccessEntry
{
public:
typedef std::map<LLUUID,LLAccessEntry> map;
LLAccessEntry()
: mID(),
mTime(0),
: mTime(0),
mFlags(0)
{}
@ -141,8 +146,6 @@ public:
U32 mFlags; // Not used - currently should always be zero
};
typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
typedef std::map<LLUUID,LLAccessEntry>::const_iterator access_map_const_iterator;
class LLParcel
{
@ -320,6 +323,9 @@ public:
void unpackAccessEntries(LLMessageSystem* msg,
std::map<LLUUID,LLAccessEntry>* list);
void unpackExperienceEntries(LLMessageSystem* msg, U32 type);
void setAABBMin(const LLVector3& min) { mAABBMin = min; }
void setAABBMax(const LLVector3& max) { mAABBMax = max; }
@ -665,6 +671,17 @@ public:
std::map<LLUUID,LLAccessEntry> mTempBanList;
std::map<LLUUID,LLAccessEntry> mTempAccessList;
typedef std::map<LLUUID, U32> xp_type_map_t;
void setExperienceKeyType(const LLUUID& experience_key, U32 type);
U32 countExperienceKeyType(U32 type);
U32 getExperienceKeyType(const LLUUID& experience_key)const;
LLAccessEntry::map getExperienceKeysByType(U32 type)const;
void clearExperienceKeysByType(U32 type);
private:
xp_type_map_t mExperienceKeys;
};

View File

@ -90,8 +90,10 @@ const U32 PF_DEFAULT = PF_ALLOW_FLY
| PF_USE_ESTATE_VOICE_CHAN;
// Access list flags
const U32 AL_ACCESS = (1 << 0);
const U32 AL_BAN = (1 << 1);
const U32 AL_ACCESS = (1 << 0);
const U32 AL_BAN = (1 << 1);
const U32 AL_ALLOW_EXPERIENCE = (1 << 3);
const U32 AL_BLOCK_EXPERIENCE = (1 << 4);
//const U32 AL_RENTER = (1 << 2);
// Block access return values. BA_ALLOWED is the only success case

View File

@ -46,6 +46,7 @@ set(llmessage_SOURCE_FILES
llcurl.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
llhttpassetstorage.cpp
@ -137,6 +138,7 @@ set(llmessage_HEADER_FILES
lldbstrings.h
lldispatcher.h
lleventflags.h
llexperiencecache.h
llextendedstatus.h
llfiltersd2xmlrpc.h
llfollowcamparams.h

View File

@ -0,0 +1,641 @@
/**
* @file llexperiencecache.cpp
* @brief llexperiencecache and related class definitions
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "llexperiencecache.h"
#include "llavatarname.h"
#include "llframetimer.h"
#include "llhttpclient.h"
#include "llsdserialize.h"
#include <set>
#include <map>
#include "boost/tokenizer.hpp"
namespace LLExperienceCache
{
typedef std::map<LLUUID, LLUUID> KeyMap;
KeyMap privateToPublicKeyMap;
void mapKeys(const LLSD& legacyKeys);
std::string sLookupURL;
typedef std::map<LLUUID, std::string> ask_queue_t;
ask_queue_t sAskQueue;
typedef std::map<LLUUID, F64> pending_queue_t;
pending_queue_t sPendingQueue;
cache_t sCache;
int sMaximumLookups = 10;
LLFrameTimer sRequestTimer;
// Periodically clean out expired entries from the cache
LLFrameTimer sEraseExpiredTimer;
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
signal_map_t sSignalMap;
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age);
void eraseExpired();
void processExperience( const LLUUID& public_key, const LLSD& experience )
{
sCache[public_key]=experience;
LLSD & row = sCache[public_key];
if(row.has(EXPIRES))
{
row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds();
}
if(row.has(EXPERIENCE_ID))
{
sPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
}
//signal
signal_map_t::iterator sig_it = sSignalMap.find(public_key);
if (sig_it != sSignalMap.end())
{
callback_signal_t* signal = sig_it->second;
(*signal)(experience);
sSignalMap.erase(public_key);
delete signal;
}
}
void initClass( )
{
}
const cache_t& getCached()
{
return sCache;
}
void setMaximumLookups( int maximumLookups)
{
sMaximumLookups = maximumLookups;
}
void bootstrap(const LLSD& legacyKeys, int initialExpiration)
{
mapKeys(legacyKeys);
LLSD::array_const_iterator it = legacyKeys.beginArray();
for(/**/; it != legacyKeys.endArray(); ++it)
{
LLSD experience = *it;
if(experience.has(EXPERIENCE_ID))
{
if(!experience.has(EXPIRES))
{
experience[EXPIRES] = initialExpiration;
}
processExperience(experience[EXPERIENCE_ID].asUUID(), experience);
}
else
{
LL_WARNS("ExperienceCache")
<< "Skipping bootstrap entry which is missing " << EXPERIENCE_ID
<< LL_ENDL;
}
}
}
bool expirationFromCacheControl(LLSD headers, F64 *expires)
{
// Allow the header to override the default
LLSD cache_control_header = headers["cache-control"];
if (cache_control_header.isDefined())
{
S32 max_age = 0;
std::string cache_control = cache_control_header.asString();
if (max_age_from_cache_control(cache_control, &max_age))
{
LL_WARNS("ExperienceCache")
<< "got EXPIRES from headers, max_age " << max_age
<< LL_ENDL;
F64 now = LLFrameTimer::getTotalSeconds();
*expires = now + (F64)max_age;
return true;
}
}
return false;
}
static const std::string MAX_AGE("max-age");
static const boost::char_separator<char> EQUALS_SEPARATOR("=");
static const boost::char_separator<char> COMMA_SEPARATOR(",");
bool max_age_from_cache_control(const std::string& cache_control, S32 *max_age)
{
// Split the string on "," to get a list of directives
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer directives(cache_control, COMMA_SEPARATOR);
tokenizer::iterator token_it = directives.begin();
for ( ; token_it != directives.end(); ++token_it)
{
// Tokens may have leading or trailing whitespace
std::string token = *token_it;
LLStringUtil::trim(token);
if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
{
// ...this token starts with max-age, so let's chop it up by "="
tokenizer subtokens(token, EQUALS_SEPARATOR);
tokenizer::iterator subtoken_it = subtokens.begin();
// Must have a token
if (subtoken_it == subtokens.end()) return false;
std::string subtoken = *subtoken_it;
// Must exactly equal "max-age"
LLStringUtil::trim(subtoken);
if (subtoken != MAX_AGE) return false;
// Must have another token
++subtoken_it;
if (subtoken_it == subtokens.end()) return false;
subtoken = *subtoken_it;
// Must be a valid integer
// *NOTE: atoi() returns 0 for invalid values, so we have to
// check the string first.
// *TODO: Do servers ever send "0000" for zero? We don't handle it
LLStringUtil::trim(subtoken);
if (subtoken == "0")
{
*max_age = 0;
return true;
}
S32 val = atoi( subtoken.c_str() );
if (val > 0 && val < S32_MAX)
{
*max_age = val;
return true;
}
return false;
}
}
return false;
}
void importFile(std::istream& istr)
{
LLSD data;
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
if(parse_count < 1) return;
LLSD experiences = data["experiences"];
LLUUID public_key;
LLSD::map_const_iterator it = experiences.beginMap();
for(; it != experiences.endMap() ; ++it)
{
public_key.set(it->first);
sCache[public_key]=it->second;
}
LL_DEBUGS("ExperienceCache") << "importFile() loaded " << sCache.size() << LL_ENDL;
}
void exportFile(std::ostream& ostr)
{
LLSD experiences;
cache_t::const_iterator it =sCache.begin();
for( ; it != sCache.end() ; ++it)
{
if(!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() ||
it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID))
continue;
experiences[it->first.asString()] = it->second;
}
LLSD data;
data["experiences"] = experiences;
LLSDSerialize::toPrettyXML(data, ostr);
}
class LLExperienceResponder : public LLHTTPClient::Responder
{
public:
LLExperienceResponder(const ask_queue_t& keys)
:mKeys(keys)
{
}
/*virtual*/ void httpCompleted()
{
LLSD experiences = getContent()["experience_keys"];
LLSD::array_const_iterator it = experiences.beginArray();
for( /**/ ; it != experiences.endArray(); ++it)
{
const LLSD& row = *it;
LLUUID public_key = row[EXPERIENCE_ID].asUUID();
LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
<< " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL ;
processExperience(public_key, row);
}
LLSD error_ids = getContent()["error_ids"];
LLSD::array_const_iterator errIt = error_ids.beginArray();
for( /**/ ; errIt != error_ids.endArray() ; ++errIt )
{
LLUUID id = errIt->asUUID();
LLSD exp;
exp[EXPIRES]=DEFAULT_EXPIRATION;
exp[EXPERIENCE_ID] = id;
exp[PROPERTIES]=PROPERTY_INVALID;
exp[MISSING]=true;
exp[QUOTA] = DEFAULT_QUOTA;
processExperience(id, exp);
LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL ;
}
LL_DEBUGS("ExperienceCache") << sCache.size() << " cached experiences" << LL_ENDL;
}
/*virtual*/ void httpFailure()
{
LL_WARNS("ExperienceCache") << "Request failed "<<getStatus()<<" "<<getReason()<< LL_ENDL;
// We're going to construct a dummy record and cache it for a while,
// either briefly for a 503 Service Unavailable, or longer for other
// errors.
F64 retry_timestamp = errorRetryTimestamp(getStatus());
// Add dummy records for all agent IDs in this request
ask_queue_t::const_iterator it = mKeys.begin();
for ( ; it != mKeys.end(); ++it)
{
LLSD exp = get(it->first);
//leave the properties alone if we already have a cache entry for this xp
if(exp.isUndefined())
{
exp[PROPERTIES]=PROPERTY_INVALID;
}
exp[EXPIRES]=retry_timestamp;
exp[EXPERIENCE_ID] = it->first;
exp["key_type"] = it->second;
exp["uuid"] = it->first;
exp["error"] = (LLSD::Integer)getStatus();
exp[QUOTA] = DEFAULT_QUOTA;
LLExperienceCache::processExperience(it->first, exp);
}
}
// Return time to retry a request that generated an error, based on
// error type and headers. Return value is seconds-since-epoch.
F64 errorRetryTimestamp(S32 status)
{
// Retry-After takes priority
LLSD retry_after = getResponseHeaders()["retry-after"];
if (retry_after.isDefined())
{
// We only support the delta-seconds type
S32 delta_seconds = retry_after.asInteger();
if (delta_seconds > 0)
{
// ...valid delta-seconds
return F64(delta_seconds);
}
}
// If no Retry-After, look for Cache-Control max-age
F64 expires = 0.0;
if (LLExperienceCache::expirationFromCacheControl(getResponseHeaders(), &expires))
{
return expires;
}
// No information in header, make a guess
if (status == 503)
{
// ...service unavailable, retry soon
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
return SERVICE_UNAVAILABLE_DELAY;
}
else if (status == 499)
{
// ...we were probably too busy, retry quickly
const F64 BUSY_DELAY = 10.0; // 10 seconds
return BUSY_DELAY;
}
else
{
// ...other unexpected error
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
return DEFAULT_DELAY;
}
}
private:
ask_queue_t mKeys;
};
void requestExperiences()
{
if(sAskQueue.empty() || sLookupURL.empty())
return;
F64 now = LLFrameTimer::getTotalSeconds();
const U32 EXP_URL_SEND_THRESHOLD = 3000;
const U32 PAGE_SIZE = EXP_URL_SEND_THRESHOLD/UUID_STR_LENGTH;
std::ostringstream ostr;
ask_queue_t keys;
ostr << sLookupURL << "?page_size=" << PAGE_SIZE;
int request_count = 0;
while(!sAskQueue.empty() && request_count < sMaximumLookups)
{
ask_queue_t::iterator it = sAskQueue.begin();
const LLUUID& key = it->first;
const std::string& key_type = it->second;
ostr << '&' << key_type << '=' << key.asString() ;
keys[key]=key_type;
request_count++;
sPendingQueue[key] = now;
if(ostr.tellp() > EXP_URL_SEND_THRESHOLD)
{
LL_DEBUGS("ExperienceCache") << "requestExperiences() query: " << ostr.str() << LL_ENDL;
LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
ostr.clear();
ostr.str(sLookupURL);
ostr << "?page_size=" << PAGE_SIZE;
keys.clear();
}
sAskQueue.erase(it);
}
if(ostr.tellp() > sLookupURL.size())
{
LL_DEBUGS("ExperienceCache") << "requestExperiences() query 2: " << ostr.str() << LL_ENDL;
LLHTTPClient::get(ostr.str(), new LLExperienceResponder(keys));
}
}
bool isRequestPending(const LLUUID& public_key)
{
bool isPending = false;
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
pending_queue_t::const_iterator it = sPendingQueue.find(public_key);
if(it != sPendingQueue.end())
{
F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
isPending = (it->second > expire_time);
}
return isPending;
}
void setLookupURL( const std::string& lookup_url )
{
sLookupURL = lookup_url;
if(!sLookupURL.empty())
{
sLookupURL += "id/";
}
}
bool hasLookupURL()
{
return !sLookupURL.empty();
}
void idle()
{
const F32 SECS_BETWEEN_REQUESTS = 0.1f;
if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS))
{
return;
}
// Must be large relative to above
const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
if (sEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
{
eraseExpired();
}
if(!sAskQueue.empty())
{
requestExperiences();
}
}
void erase( const LLUUID& key )
{
cache_t::iterator it = sCache.find(key);
if(it != sCache.end())
{
sCache.erase(it);
}
}
void eraseExpired()
{
F64 now = LLFrameTimer::getTotalSeconds();
cache_t::iterator it = sCache.begin();
while (it != sCache.end())
{
cache_t::iterator cur = it;
LLSD& exp = cur->second;
++it;
if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now)
{
if(!exp.has(EXPERIENCE_ID))
{
LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ;
sCache.erase(cur);
}
else
{
LLUUID id = exp[EXPERIENCE_ID].asUUID();
LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null;
if(private_key.notNull() || !exp.has("DoesNotExist"))
{
fetch(id, true);
}
else
{
LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ;
sCache.erase(cur);
}
}
}
}
}
bool fetch( const LLUUID& key, bool refresh/* = true*/ )
{
if(!key.isNull() && !isRequestPending(key) && (refresh || sCache.find(key)==sCache.end()))
{
LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL ;
sAskQueue[key]=EXPERIENCE_ID;
return true;
}
return false;
}
void insert(const LLSD& experience_data )
{
if(experience_data.has(EXPERIENCE_ID))
{
processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data);
}
else
{
LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL;
}
}
static LLSD empty;
const LLSD& get(const LLUUID& key)
{
if(key.isNull()) return empty;
cache_t::const_iterator it = sCache.find(key);
if (it != sCache.end())
{
return it->second;
}
fetch(key);
return empty;
}
void get( const LLUUID& key, callback_slot_t slot )
{
if(key.isNull()) return;
cache_t::const_iterator it = sCache.find(key);
if (it != sCache.end())
{
// ...name already exists in cache, fire callback now
callback_signal_t signal;
signal.connect(slot);
signal(it->second);
return;
}
fetch(key);
// always store additional callback, even if request is pending
signal_map_t::iterator sig_it = sSignalMap.find(key);
if (sig_it == sSignalMap.end())
{
// ...new callback for this id
callback_signal_t* signal = new callback_signal_t();
signal->connect(slot);
sSignalMap[key] = signal;
}
else
{
// ...existing callback, bind additional slot
callback_signal_t* signal = sig_it->second;
signal->connect(slot);
}
}
}
void LLExperienceCache::mapKeys( const LLSD& legacyKeys )
{
LLSD::array_const_iterator exp = legacyKeys.beginArray();
for(/**/ ; exp != legacyKeys.endArray() ; ++exp)
{
if(exp->has(LLExperienceCache::EXPERIENCE_ID) && exp->has(LLExperienceCache::PRIVATE_KEY))
{
privateToPublicKeyMap[(*exp)[LLExperienceCache::PRIVATE_KEY].asUUID()]=(*exp)[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
}
}
LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found)
{
if (private_key.isNull())
return LLUUID::null;
KeyMap::const_iterator it=privateToPublicKeyMap.find(private_key);
if(it == privateToPublicKeyMap.end())
{
if(null_if_not_found)
{
return LLUUID::null;
}
return private_key;
}
LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL;
return it->second;
}

View File

@ -0,0 +1,104 @@
/**
* @file llexperiencecache.h
* @brief Caches information relating to experience keys
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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_LLEXPERIENCECACHE_H
#define LL_LLEXPERIENCECACHE_H
#include "linden_common.h"
#include <boost/signals2.hpp>
class LLSD;
class LLUUID;
namespace LLExperienceCache
{
const std::string PRIVATE_KEY = "private_id";
const std::string MISSING = "DoesNotExist";
const std::string AGENT_ID = "agent_id";
const std::string GROUP_ID = "group_id";
const std::string EXPERIENCE_ID = "public_id";
const std::string NAME = "name";
const std::string PROPERTIES = "properties";
const std::string EXPIRES = "expiration";
const std::string DESCRIPTION = "description";
const std::string QUOTA = "quota";
const std::string MATURITY = "maturity";
const std::string METADATA = "extended_metadata";
const std::string SLURL = "slurl";
// should be in sync with experience-api/experiences/models.py
const int PROPERTY_INVALID = 1 << 0;
const int PROPERTY_PRIVILEGED = 1 << 3;
const int PROPERTY_GRID = 1 << 4;
const int PROPERTY_PRIVATE = 1 << 5;
const int PROPERTY_DISABLED = 1 << 6;
const int PROPERTY_SUSPENDED = 1 << 7;
// default values
const static F64 DEFAULT_EXPIRATION = 600.0;
const static S32 DEFAULT_QUOTA = 128; // this is megabytes
// Callback types for get() below
typedef boost::signals2::signal<void (const LLSD& experience)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef std::map<LLUUID, LLSD> cache_t;
void setLookupURL(const std::string& lookup_url);
bool hasLookupURL();
void setMaximumLookups(int maximumLookups);
void idle();
void exportFile(std::ostream& ostr);
void importFile(std::istream& istr);
void initClass();
void bootstrap(const LLSD& legacyKeys, int initialExpiration);
void erase(const LLUUID& key);
bool fetch(const LLUUID& key, bool refresh=false);
void insert(const LLSD& experience_data);
const LLSD& get(const LLUUID& key);
// If name information is in cache, callback will be called immediately.
void get(const LLUUID& key, callback_slot_t slot);
const cache_t& getCached();
// maps an experience private key to the experience id
LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false);
};
#endif // LL_LLEXPERIENCECACHE_H

View File

@ -148,19 +148,20 @@ const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS
| ESTATE_ACCESS_BANNED_AGENTS
| ESTATE_ACCESS_MANAGERS;
// for EstateOwnerRequest, estateaccessdelta message
const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1 << 0;
const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1 << 1;
// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages
const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0;
const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1 << 2;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1 << 3;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1 << 4;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1 << 5;
const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1 << 6;
const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1 << 7;
const U32 ESTATE_ACCESS_MANAGER_ADD = 1 << 8;
const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9;
const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5;
const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6;
const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7;
const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8;
const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9;
const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10;
const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11;
const S32 ESTATE_MAX_MANAGERS = 10;
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned
@ -171,6 +172,26 @@ const U32 SWD_OTHERS_LAND_ONLY = (1 << 0);
const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1);
const U32 SWD_SCRIPTED_ONLY = (1 << 2);
// Controls experience key validity in the estate
const U32 EXPERIENCE_KEY_TYPE_NONE = 0;
const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1;
const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2;
const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3;
const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED;
const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED;
//
const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2;
const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3;
const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4;
const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5;
const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6;
const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7;
const S32 ESTATE_MAX_EXPERIENCE_IDS = 8;
#endif

View File

@ -1385,6 +1385,8 @@ char const* const _PREHASH_AppearanceVersion = LLMessageStringTable::getInstance
char const* const _PREHASH_CofVersion = LLMessageStringTable::getInstance()->getString("CofVersion");
char const* const _PREHASH_AppearanceHover = LLMessageStringTable::getInstance()->getString("AppearanceHover");
char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->getString("HoverHeight");
char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience");
char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID");
// <FS:CR> Aurora Sim
char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX");

View File

@ -1385,6 +1385,8 @@ extern char const* const _PREHASH_AppearanceVersion;
extern char const* const _PREHASH_CofVersion;
extern char const* const _PREHASH_AppearanceHover;
extern char const* const _PREHASH_HoverHeight;
extern char const* const _PREHASH_Experience;
extern char const* const _PREHASH_ExperienceID;
// <FS:CR> Aurora Sim
extern char const* const _PREHASH_RegionSizeX;

View File

@ -239,4 +239,23 @@ const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
// Start per-function errors below, starting at 2000:
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
const S32 LSL_XP_ERROR_NONE = 0;
const S32 LSL_XP_ERROR_THROTTLED = 1;
const S32 LSL_XP_ERROR_EXPERIENCES_DISABLED = 2;
const S32 LSL_XP_ERROR_INVALID_PARAMETERS = 3;
const S32 LSL_XP_ERROR_NOT_PERMITTED = 4;
const S32 LSL_XP_ERROR_NO_EXPERIENCE = 5;
const S32 LSL_XP_ERROR_NOT_FOUND = 6;
const S32 LSL_XP_ERROR_INVALID_EXPERIENCE = 7;
const S32 LSL_XP_ERROR_EXPERIENCE_DISABLED = 8;
const S32 LSL_XP_ERROR_EXPERIENCE_SUSPENDED = 9;
const S32 LSL_XP_ERROR_UNKNOWN_ERROR = 10;
const S32 LSL_XP_ERROR_QUOTA_EXCEEDED = 11;
const S32 LSL_XP_ERROR_STORE_DISABLED = 12;
const S32 LSL_XP_ERROR_STORAGE_EXCEPTION = 13;
const S32 LSL_XP_ERROR_KEY_NOT_FOUND = 14;
const S32 LSL_XP_ERROR_RETRY_UPDATE = 15;
const S32 LSL_XP_ERROR_MATURITY_EXCEEDED = 16;
#endif

View File

@ -679,7 +679,7 @@ void LLNotification::respond(const LLSD& response)
// and then call it
functor(asLLSD(), response);
}
else
else if (mCombinedNotifications.empty())
{
// no registered responder
return;
@ -701,6 +701,14 @@ void LLNotification::respond(const LLSD& response)
}
}
for (std::vector<LLNotificationPtr>::const_iterator it = mCombinedNotifications.begin(); it != mCombinedNotifications.end(); ++it)
{
if ((*it))
{
(*it)->respond(response);
}
}
update();
}
@ -1331,6 +1339,28 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
}
}
break;
case LLNotification::COMBINE_WITH_NEW:
// Add to the existing unique notification with the data from this particular instance...
// This guarantees that duplicate notifications will be collapsed to the one
// most recently triggered
for (LLNotificationMap::iterator existing_it = mUniqueNotifications.find(pNotif->getName());
existing_it != mUniqueNotifications.end();
++existing_it)
{
LLNotificationPtr existing_notification = existing_it->second;
if (pNotif != existing_notification
&& pNotif->isEquivalentTo(existing_notification))
{
// copy the notifications from the newest instance into the oldest
existing_notification->mCombinedNotifications.push_back(pNotif);
existing_notification->mCombinedNotifications.insert(existing_notification->mCombinedNotifications.end(),
pNotif->mCombinedNotifications.begin(), pNotif->mCombinedNotifications.end());
// pop up again
existing_notification->update();
}
}
break;
case LLNotification::KEEP_OLD:
break;
case LLNotification::CANCEL_OLD:

View File

@ -416,6 +416,9 @@ private:
using the same mechanism.
*/
bool mTemporaryResponder;
// keep track of other notifications combined with COMBINE_WITH_NEW
std::vector<LLNotificationPtr> mCombinedNotifications;
void init(const std::string& template_name, const LLSD& form_elements);
@ -566,6 +569,7 @@ public:
typedef enum e_combine_behavior
{
REPLACE_WITH_NEW,
COMBINE_WITH_NEW,
KEEP_OLD,
CANCEL_OLD

View File

@ -43,6 +43,7 @@ struct LLNotificationTemplate
static void declareValues()
{
declare("replace_with_new", LLNotification::REPLACE_WITH_NEW);
declare("combine_with_new", LLNotification::COMBINE_WITH_NEW);
declare("keep_old", LLNotification::KEEP_OLD);
declare("cancel_old", LLNotification::CANCEL_OLD);
}

View File

@ -2296,6 +2296,11 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y)
}
}
S32 LLTabContainer::getTotalTabWidth() const
{
return mTotalTabWidth;
}
// <FS:ND> Hide one tab. Will switch to the first visible tab if one exists. Otherwise the Tabcontainer is hidden
void LLTabContainer::setTabVisibility( LLPanel const *aPanel, bool aVisible )
{

View File

@ -194,7 +194,8 @@ public:
LLPanel* getPanelByIndex(S32 index);
S32 getIndexForPanel(LLPanel* panel);
S32 getPanelIndexByTitle(const std::string& title);
LLPanel* getPanelByName(const std::string& name);
LLPanel* getPanelByName(const std::string& name);
S32 getTotalTabWidth() const;
void setCurrentTabName(const std::string& name);
void selectFirstTab();
@ -302,7 +303,7 @@ private:
S32 mMaxTabWidth;
S32 mTotalTabWidth;
S32 mTabHeight;
S32 mTabHeight;
// Padding under the text labels of tab buttons
S32 mLabelPadBottom;

View File

@ -38,6 +38,7 @@
#include "lltrans.h"
#include "lluicolortable.h"
#include "message.h"
#include "llexperiencecache.h"
// <FS:AW> hop:// protocol>
//#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
@ -1540,3 +1541,57 @@ std::string LLUrlEntryJira::getUrl(const std::string &string) const
return llformat("https://jira.secondlife.com/browse/%s", string.c_str());
}
}
LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile()
{
mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*",
boost::regex::perl|boost::regex::icase);
mIcon = "Generic_Experience";
mMenuName = "menu_url_experience.xml";
}
std::string LLUrlEntryExperienceProfile::getLabel( const std::string &url, const LLUrlLabelCallback &cb )
{
if (!gCacheName)
{
// probably at the login screen, use short string for layout
return LLTrans::getString("LoadingData");
}
std::string experience_id_string = getIDStringFromUrl(url);
if (experience_id_string.empty())
{
// something went wrong, just give raw url
return unescapeUrl(url);
}
LLUUID experience_id(experience_id_string);
if (experience_id.isNull())
{
return LLTrans::getString("ExperienceNameNull");
}
const LLSD& experience_details = LLExperienceCache::get(experience_id);
if(!experience_details.isUndefined())
{
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
return experience_name_string.empty() ? LLTrans::getString("ExperienceNameUntitled") : experience_name_string;
}
addObserver(experience_id_string, url, cb);
LLExperienceCache::get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
return LLTrans::getString("LoadingData");
}
void LLUrlEntryExperienceProfile::onExperienceDetails( const LLSD& experience_details )
{
std::string name = experience_details[LLExperienceCache::NAME].asString();
if(name.empty())
{
name = LLTrans::getString("ExperienceNameUntitled");
}
callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null);
}

View File

@ -351,6 +351,20 @@ private:
};
// [/RLVa:KB]
///
/// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g.,
/// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile
/// that displays the experience name
class LLUrlEntryExperienceProfile : public LLUrlEntryBase
{
public:
LLUrlEntryExperienceProfile();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
private:
void onExperienceDetails(const LLSD& experience_details);
};
///
/// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
/// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about

View File

@ -41,7 +41,7 @@ LLUrlRegistry::LLUrlRegistry()
{
// mUrlEntry.reserve(20);
// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Added: RLVa-1.2.2a
mUrlEntry.reserve(24);
mUrlEntry.reserve(25);
// [/RLVa:KB]
// Urls are matched in the order that they were registered
@ -84,6 +84,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntryInventory());
registerUrl(new LLUrlEntryExperienceProfile());
//LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern,
//so it should be registered in the end of list
registerUrl(new LLUrlEntrySL());

View File

@ -32,9 +32,23 @@
#include "lltut.h"
#include "../lluicolortable.h"
#include "../llrender/lluiimage.h"
#include "../llmessage/llexperiencecache.h"
#include <boost/regex.hpp>
namespace LLExperienceCache
{
const LLSD& get( const LLUUID& key)
{
static LLSD boo;
return boo;
}
void get( const LLUUID& key, callback_slot_t slot ){}
}
typedef std::map<std::string, LLControlGroup*> settings_map_t;
settings_map_t LLUI::sSettingGroups;

View File

@ -355,6 +355,10 @@ typedef enum e_lscript_state_event_type
LSTT_REMOTE_DATA,
LSTT_HTTP_RESPONSE,
LSTT_HTTP_REQUEST,
LSTT_EXPERMISSIONS,
LSTT_TRANSACTION_RESULT,
LSTT_PATH_UPDATE,
LSTT_EXPERMISSIONS_DENIED,
LSTT_EOF,
LSTT_STATE_BEGIN = LSTT_STATE_ENTRY,
@ -397,7 +401,11 @@ const U64 LSCRIPTStateBitField[LSTT_EOF] =
0x0000000040000000, // LSTT_OBJECT_REZ
0x0000000080000000, // LSTT_REMOTE_DATA
0x0000000100000000LL, // LSTT_HTTP_RESPOSE
0x0000000200000000LL // LSTT_HTTP_REQUEST
0x0000000200000000LL, // LSTT_HTTP_REQUEST
0x0000000400000000LL, // LSTT_EXPERMISSIONS
0x0000000800000000LL, // LSTT_TRANSACTION_RESULT
0x0000001000000000LL, // LSTT_PATH_UPDATE
0x0000002000000000LL, //LSTT_EXPERMISSIONS_DENIED
};
inline S32 get_event_handler_jump_position(U64 bit_field, LSCRIPTStateEventType type)
@ -511,6 +519,7 @@ typedef enum e_lscript_runtime_faults
LSRF_TOO_MANY_LISTENS,
LSRF_NESTING_LISTS,
LSRF_CLI,
LSRF_INVALID_STATE,
LSRF_EOF
} LSCRIPTRunTimeFaults;
@ -551,10 +560,10 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] =
(0x1 << 10),// SCRIPT_PERMISSION_TRACK_CAMERA
(0x1 << 11),// SCRIPT_PERMISSION_CONTROL_CAMERA
(0x1 << 12),// SCRIPT_PERMISSION_TELEPORT
(0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE,
(0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT,
(0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS,
(0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS,
(0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE
(0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT
(0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS
(0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS
};
// http_request string constants

View File

@ -132,6 +132,8 @@ int yyerror(const char *fmt, ...);
"money" { count(); return(MONEY); }
"email" { count(); return(EMAIL); }
"run_time_permissions" { count(); return(RUN_TIME_PERMISSIONS); }
"experience_permissions" { count(); return(EXPERIENCE_PERMISSIONS); }
"experience_permissions_denied" { count(); return(EXPERIENCE_PERMISSIONS_DENIED); }
"changed" { count(); return(INVENTORY); }
"attach" { count(); return(ATTACH); }
"dataserver" { count(); return(DATASERVER); }
@ -394,7 +396,6 @@ int yyerror(const char *fmt, ...);
"PSYS_PART_END_ALPHA" { count(); yylval.ival = LLPS_PART_END_ALPHA; return (INTEGER_CONSTANT); }
"PSYS_PART_END_SCALE" { count(); yylval.ival = LLPS_PART_END_SCALE; return (INTEGER_CONSTANT); }
"PSYS_PART_MAX_AGE" { count(); yylval.ival = LLPS_PART_MAX_AGE; return (INTEGER_CONSTANT); }
"PSYS_PART_BLEND_FUNC_SOURCE" { count(); yylval.ival = LLPS_PART_BLEND_FUNC_SOURCE; return (INTEGER_CONSTANT); }
"PSYS_PART_BLEND_FUNC_DEST" { count(); yylval.ival = LLPS_PART_BLEND_FUNC_DEST; return (INTEGER_CONSTANT); }
"PSYS_PART_START_GLOW" { count(); yylval.ival = LLPS_PART_START_GLOW; return (INTEGER_CONSTANT); }
@ -420,7 +421,6 @@ int yyerror(const char *fmt, ...);
"PSYS_PART_BF_SOURCE_ALPHA" { count(); yylval.ival = LLPartData::LL_PART_BF_SOURCE_ALPHA; return(INTEGER_CONSTANT); }
"PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA" { count(); yylval.ival = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; return(INTEGER_CONSTANT); }
"PSYS_SRC_MAX_AGE" { count(); yylval.ival = LLPS_SRC_MAX_AGE; return(INTEGER_CONSTANT); }
"PSYS_SRC_PATTERN" { count(); yylval.ival = LLPS_SRC_PATTERN; return(INTEGER_CONSTANT); }
"PSYS_SRC_INNERANGLE" { count(); yylval.ival = LLPS_SRC_INNERANGLE; return(INTEGER_CONSTANT); }
@ -738,6 +738,24 @@ int yyerror(const char *fmt, ...);
"STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); }
"STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); }
"XP_ERROR_NONE" { count(); yylval.ival = LSL_XP_ERROR_NONE ; return (INTEGER_CONSTANT); }
"XP_ERROR_THROTTLED" { count(); yylval.ival = LSL_XP_ERROR_THROTTLED ; return (INTEGER_CONSTANT); }
"XP_ERROR_EXPERIENCES_DISABLED" { count(); yylval.ival = LSL_XP_ERROR_EXPERIENCES_DISABLED; return (INTEGER_CONSTANT); }
"XP_ERROR_INVALID_PARAMETERS" { count(); yylval.ival = LSL_XP_ERROR_INVALID_PARAMETERS ; return (INTEGER_CONSTANT); }
"XP_ERROR_NOT_PERMITTED" { count(); yylval.ival = LSL_XP_ERROR_NOT_PERMITTED ; return (INTEGER_CONSTANT); }
"XP_ERROR_NO_EXPERIENCE" { count(); yylval.ival = LSL_XP_ERROR_NO_EXPERIENCE ; return (INTEGER_CONSTANT); }
"XP_ERROR_NOT_FOUND" { count(); yylval.ival = LSL_XP_ERROR_NOT_FOUND ; return (INTEGER_CONSTANT); }
"XP_ERROR_INVALID_EXPERIENCE" { count(); yylval.ival = LSL_XP_ERROR_INVALID_EXPERIENCE ; return (INTEGER_CONSTANT); }
"XP_ERROR_EXPERIENCE_DISABLED" { count(); yylval.ival = LSL_XP_ERROR_EXPERIENCE_DISABLED ; return (INTEGER_CONSTANT); }
"XP_ERROR_EXPERIENCE_SUSPENDED" { count(); yylval.ival = LSL_XP_ERROR_EXPERIENCE_SUSPENDED; return (INTEGER_CONSTANT); }
"XP_ERROR_UNKNOWN_ERROR" { count(); yylval.ival = LSL_XP_ERROR_UNKNOWN_ERROR ; return (INTEGER_CONSTANT); }
"XP_ERROR_QUOTA_EXCEEDED" { count(); yylval.ival = LSL_XP_ERROR_QUOTA_EXCEEDED ; return (INTEGER_CONSTANT); }
"XP_ERROR_STORE_DISABLED" { count(); yylval.ival = LSL_XP_ERROR_STORE_DISABLED ; return (INTEGER_CONSTANT); }
"XP_ERROR_STORAGE_EXCEPTION" { count(); yylval.ival = LSL_XP_ERROR_STORAGE_EXCEPTION ; return (INTEGER_CONSTANT); }
"XP_ERROR_KEY_NOT_FOUND" { count(); yylval.ival = LSL_XP_ERROR_KEY_NOT_FOUND ; return (INTEGER_CONSTANT); }
"XP_ERROR_RETRY_UPDATE" { count(); yylval.ival = LSL_XP_ERROR_RETRY_UPDATE ; return (INTEGER_CONSTANT); }
"XP_ERROR_MATURITY_EXCEEDED" { count(); yylval.ival = LSL_XP_ERROR_MATURITY_EXCEEDED ; return (INTEGER_CONSTANT); }
{L}({L}|{N})* { count(); yylval.sval = new char[strlen(yytext) + 1]; strcpy(yylval.sval, yytext); return(IDENTIFIER); }
{N}+{E} { count(); yylval.fval = (F32)atof(yytext); return(FP_CONSTANT); }

View File

@ -15,7 +15,6 @@
#pragma warning (disable : 4702) // warning C4702: unreachable code
#pragma warning( disable : 4065 ) // warning: switch statement contains 'default' but no 'case' labels
#endif
%}
%union
@ -75,6 +74,8 @@
%token MONEY
%token EMAIL
%token RUN_TIME_PERMISSIONS
%token EXPERIENCE_PERMISSIONS
%token EXPERIENCE_PERMISSIONS_DENIED
%token INVENTORY
%token ATTACH
%token DATASERVER
@ -180,6 +181,8 @@
%type <event> money
%type <event> email
%type <event> run_time_permissions
%type <event> experience_permissions
%type <event> experience_permissions_denied
%type <event> inventory
%type <event> attach
%type <event> dataserver
@ -788,6 +791,16 @@ event
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| experience_permissions compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| experience_permissions_denied compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| inventory compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
@ -1040,6 +1053,28 @@ run_time_permissions
}
;
experience_permissions
: EXPERIENCE_PERMISSIONS '(' LLKEY IDENTIFIER ')'
{
LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4);
gAllocationManager->addAllocation(id1);
$$ = new LLScriptEXPEvent(gLine, gColumn, id1);
gAllocationManager->addAllocation($$);
}
;
experience_permissions_denied
: EXPERIENCE_PERMISSIONS_DENIED '(' LLKEY IDENTIFIER ',' INTEGER IDENTIFIER ')'
{
LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4);
gAllocationManager->addAllocation(id1);
LLScriptIdentifier *id2 = new LLScriptIdentifier(gLine, gColumn, $7);
gAllocationManager->addAllocation(id2);
$$ = new LLScriptEXPDeniedEvent(gLine, gColumn, id1, id2);
gAllocationManager->addAllocation($$);
}
;
inventory
: INVENTORY '(' INTEGER IDENTIFIER ')'
{

View File

@ -3844,6 +3844,156 @@ S32 LLScriptNotAtTarget::getSize()
return 0;
}
void LLScriptEXPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
{
return;
}
switch(pass)
{
case LSCP_PRETTY_PRINT:
case LSCP_EMIT_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions( key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )\n");
break;
case LSCP_SCOPE_PASS1:
checkForDuplicateHandler(fp, this, scope, "experience_permissions");
if (scope->checkEntry(mName->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY);
}
break;
case LSCP_RESOURCE:
{
// we're just tryng to determine how much space the variable needs
if (mName->mScopeEntry)
{
mName->mScopeEntry->mOffset = (S32)count;
mName->mScopeEntry->mSize = 4;
count += mName->mScopeEntry->mSize;
}
}
break;
case LSCP_EMIT_BYTE_CODE:
{
#ifdef LSL_INCLUDE_DEBUG_INFO
char name[] = "experience_permissions";
chunk->addBytes(name, strlen(name) + 1);
chunk->addBytes(mName->mName, strlen(mName->mName) + 1);
#endif
}
break;
case LSCP_EMIT_CIL_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions( valuetype [ScriptTypes]LindenLab.SecondLife.Key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )");
break;
default:
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
break;
}
}
S32 LLScriptEXPEvent::getSize()
{
// key = 4
return 4;
}
void LLScriptEXPDeniedEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
{
return;
}
switch(pass)
{
case LSCP_PRETTY_PRINT:
case LSCP_EMIT_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions_denied( key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, ", integer ");
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )\n");
break;
case LSCP_SCOPE_PASS1:
checkForDuplicateHandler(fp, this, scope, "experience_permissions_denied");
if (scope->checkEntry(mName->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY);
}
if (scope->checkEntry(mReason->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mReason->mScopeEntry = scope->addEntry(mReason->mName, LIT_VARIABLE, LST_INTEGER);
}
break;
case LSCP_RESOURCE:
{
// we're just trying to determine how much space the variable needs
if (mName->mScopeEntry)
{
mName->mScopeEntry->mOffset = (S32)count;
mName->mScopeEntry->mSize = 4;
count += mName->mScopeEntry->mSize;
mReason->mScopeEntry->mOffset = (S32)count;
mReason->mScopeEntry->mSize = 4;
count += mReason->mScopeEntry->mSize;
}
}
break;
case LSCP_EMIT_BYTE_CODE:
{
#ifdef LSL_INCLUDE_DEBUG_INFO
char name[] = "experience_permissions_denied";
chunk->addBytes(name, strlen(name) + 1);
chunk->addBytes(mName->mName, strlen(mName->mName) + 1);
chunk->addBytes(mReason->mName, strlen(mReason->mName) + 1);
#endif
}
break;
case LSCP_EMIT_CIL_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions_denied( valuetype [ScriptTypes]LindenLab.SecondLife.Key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, ", int32 ");
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )");
break;
default:
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
break;
}
}
S32 LLScriptEXPDeniedEvent::getSize()
{
// key = 4 + integer
return LSCRIPTDataSize[LST_KEY]+LSCRIPTDataSize[LST_INTEGER];
}
void LLScriptAtRotTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
@ -8569,6 +8719,7 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa
}
}
prunearg = TRUE;
break;
case LSCP_TYPE:
// if there is a return expression, it must be promotable to the return type of the function
if (mExpression)
@ -9767,7 +9918,13 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom
mScopeEntry->mFunctionArgs.addType(LST_STRING);
mScopeEntry->mFunctionArgs.addType(LST_STRING);
break;
case LSTT_EXPERMISSIONS:
mScopeEntry->mFunctionArgs.addType(LST_KEY);
break;
case LSTT_EXPERMISSIONS_DENIED:
mScopeEntry->mFunctionArgs.addType(LST_KEY);
mScopeEntry->mFunctionArgs.addType(LST_INTEGER);
break;
default:
break;
}

View File

@ -627,6 +627,39 @@ public:
LLScriptIdentifier *mRTPermissions;
};
class LLScriptEXPEvent : public LLScriptEvent
{
public:
LLScriptEXPEvent(S32 line, S32 col, LLScriptIdentifier *name)
: LLScriptEvent(line, col, LSTT_EXPERMISSIONS), mName(name)
{
}
~LLScriptEXPEvent() {}
void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);
S32 getSize();
LLScriptIdentifier *mName;
};
class LLScriptEXPDeniedEvent : public LLScriptEvent
{
public:
LLScriptEXPDeniedEvent(S32 line, S32 col, LLScriptIdentifier *name, LLScriptIdentifier *reason)
: LLScriptEvent(line, col, LSTT_EXPERMISSIONS_DENIED), mName(name), mReason(reason)
{
}
~LLScriptEXPDeniedEvent() {}
void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);
S32 getSize();
LLScriptIdentifier *mName;
LLScriptIdentifier *mReason;
};
class LLScriptChatEvent : public LLScriptEvent
{
public:

View File

@ -308,6 +308,8 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
llexperienceassociationresponder.cpp
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
llfacebookconnect.cpp
@ -349,6 +351,9 @@ set(viewer_SOURCE_FILES
llfloatereditwater.cpp
llfloaterenvironmentsettings.cpp
llfloaterevent.cpp
llfloaterexperiencepicker.cpp
llfloaterexperienceprofile.cpp
llfloaterexperiences.cpp
llfloaterfacebook.cpp
llfloaterflickr.cpp
llfloaterfonttest.cpp
@ -531,11 +536,16 @@ set(viewer_SOURCE_FILES
llpanelclassified.cpp
llpanelcontents.cpp
llpaneleditwearable.cpp
llpanelexperiencelisteditor.cpp
llpanelexperiencelog.cpp
llpanelexperiencepicker.cpp
llpanelexperiences.cpp
llpanelface.cpp
llpanelgenerictip.cpp
llpanelgroup.cpp
llpanelgroupbulk.cpp
llpanelgroupbulkban.cpp
llpanelgroupexperiences.cpp
llpanelgroupgeneral.cpp
llpanelgroupinvite.cpp
llpanelgrouplandmoney.cpp
@ -1038,6 +1048,8 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
llexperienceassociationresponder.h
llexperiencelog.h
llexternaleditor.h
llface.h
llfacebookconnect.h
@ -1079,6 +1091,9 @@ set(viewer_HEADER_FILES
llfloatereditwater.h
llfloaterenvironmentsettings.h
llfloaterevent.h
llfloaterexperiencepicker.h
llfloaterexperienceprofile.h
llfloaterexperiences.h
llfloaterfacebook.h
llfloaterflickr.h
llfloaterfonttest.h
@ -1254,12 +1269,17 @@ set(viewer_HEADER_FILES
llpanelclassified.h
llpanelcontents.h
llpaneleditwearable.h
llpanelexperiencelisteditor.h
llpanelexperiencelog.h
llpanelexperiencepicker.h
llpanelexperiences.h
llpanelface.h
llpanelgenerictip.h
llpanelgroup.h
llpanelgroupbulk.h
llpanelgroupbulkimpl.h
llpanelgroupbulkban.h
llpanelgroupexperiences.h
llpanelgroupgeneral.h
llpanelgroupinvite.h
llpanelgrouplandmoney.h

View File

@ -55,6 +55,7 @@ remote_data remote_data(integer event_type, key channel, key message_id, str
http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests
http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL
# integer constants
[word .1, .1, .5]
TRUE Integer constant for Boolean operations
@ -717,6 +718,25 @@ TEXTURE_TRANSPARENT UUID for the "White - Transparent" texture
URL_REQUEST_GRANTED Used with http_request when a public URL is successfully granted
URL_REQUEST_DENIED Used with http_request when a public URL is not available
XP_ERROR_NONE No error was detected
XP_ERROR_THROTTLED The call failed due to too many recent calls.
XP_ERROR_EXPERIENCES_DISABLED The region currently has experiences disabled.
XP_ERROR_INVALID_PARAMETERS One of the string arguments was too big to fit in the key-value store.
XP_ERROR_NOT_PERMITTED This experience is not allowed to run on the current region.
XP_ERROR_NO_EXPERIENCE This script is not associated with an experience.
XP_ERROR_NOT_FOUND The sim was unable to verify the validity of the experience. Retrying after a short wait is advised.
XP_ERROR_INVALID_EXPERIENCE The script is associated with an experience that no longer exists.
XP_ERROR_EXPERIENCE_DISABLED The experience owner has temporarily disabled the experience.
XP_ERROR_EXPERIENCE_SUSPENDED The experience has been suspended by Linden Customer Support.
XP_ERROR_QUOTA_EXCEEDED An attempted write data to the key-value store failed due to the data quota being met.
XP_ERROR_STORE_DISABLED The key-value store is currently disabled on this region.
XP_ERROR_STORAGE_EXCEPTION Unable to communicate with the key-value store.
XP_ERROR_KEY_NOT_FOUND The requested key does not exist.
XP_ERROR_RETRY_UPDATE A checked update failed due to an out of date request.
XP_ERROR_MATURITY_EXCEEDED The request failed due to agent content preferences.
XP_ERROR_UNKNOWN_ERROR Other unknown error.
# float constants
[word .3, .1, .5]
PI 3.1415926535897932384626433832795

View File

@ -3153,7 +3153,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>100</real>
<integer>100</integer>
</map>
<key>ChatLoadGroupTimeout</key>
<map>
@ -6304,7 +6304,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>3</real>
<real>3.0</real>
</map>
<key>FullScreenAutoDetectAspectRatio</key>
<map>
@ -8606,7 +8606,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -8619,7 +8619,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>1</real>
<integer>1</integer>
</map>
<key>MeshImportUseSLM</key>
<map>
@ -8630,7 +8630,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>MeshUploadLogXML</key>
<map>
@ -8641,7 +8641,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -8654,7 +8654,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -8667,7 +8667,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>600</real>
<integer>600</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11069,7 +11069,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>64</real>
<real>64.0</real>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11223,7 +11223,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11277,7 +11277,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>4</real>
<real>4.0</real>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11356,7 +11356,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0</real>
<real>0.0</real>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11580,7 +11580,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>RenderSpecularResX</key>
@ -11592,7 +11592,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>1024</real>
<integer>1024</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11606,7 +11606,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>256</real>
<integer>256</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11786,7 +11786,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -11961,9 +11961,9 @@ Change of this parameter will affect the layout of buttons in notification toast
<string>Vector3</string>
<key>Value</key>
<array>
<real>1</real>
<real>0</real>
<real>0</real>
<real>1.0</real>
<real>0.0</real>
<real>0.0</real>
</array>
</map>
<key>RenderGlowMaxExtractAlpha</key>
@ -12603,7 +12603,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>RenderAutoMuteLogging</key>
<map>
@ -12843,7 +12843,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>250000</real>
<integer>250000</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -12856,7 +12856,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>384</real>
<integer>384</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -12869,7 +12869,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -12882,7 +12882,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
<key>Backup</key>
<integer>0</integer>
</map>
@ -13047,7 +13047,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>1024</real>
<integer>1024</integer>
</map>
<key>SceneLoadLowMemoryBound</key>
<map>
@ -13058,7 +13058,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>750</real>
<integer>750</integer>
</map>
<key>SceneLoadMinRadius</key>
<map>
@ -14888,7 +14888,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>6</real>
<integer>6</integer>
</map>
<key>UICheckboxctrlBtnSize</key>
<map>
@ -14899,7 +14899,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>13</real>
<integer>13</integer>
</map>
<key>UICheckboxctrlHeight</key>
<map>
@ -14910,7 +14910,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>UICheckboxctrlHPad</key>
<map>
@ -14921,7 +14921,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>2</real>
<integer>2</integer>
</map>
<key>UICheckboxctrlSpacing</key>
<map>
@ -14932,7 +14932,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>5</real>
<integer>5</integer>
</map>
<key>UICheckboxctrlVPad</key>
<map>
@ -14943,7 +14943,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>2</real>
<integer>2</integer>
</map>
<key>UICloseBoxFromTop</key>
<map>
@ -14954,7 +14954,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>5</real>
<integer>5</integer>
</map>
<key>UIExtraTriangleHeight</key>
<map>
@ -14965,7 +14965,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>-1</real>
<integer>-1</integer>
</map>
<key>UIExtraTriangleWidth</key>
<map>
@ -14976,7 +14976,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
</map>
<key>UIFloaterCloseBoxSize</key>
<map>
@ -14987,7 +14987,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>UIFloaterHPad</key>
<map>
@ -14998,7 +14998,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>6</real>
<integer>6</integer>
</map>
<key>UIFloaterTestBool</key>
<map>
@ -15242,7 +15242,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>500</real>
<integer>500</integer>
</map>
<key>UIMinimizedWidth</key>
<map>
@ -15253,7 +15253,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>160</real>
<integer>160</integer>
</map>
<key>UIMultiSliderctrlSpacing</key>
<map>
@ -15264,7 +15264,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
</map>
<key>UIMultiTrackHeight</key>
<map>
@ -16249,7 +16249,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>3</real>
<integer>3</integer>
</map>
<key>UseCircuitCodeTimeout</key>
<map>
@ -19135,9 +19135,9 @@ Change of this parameter will affect the layout of buttons in notification toast
<string>Color4</string>
<key>Value</key>
<array>
<real>0</real>
<real>0</real>
<real>0</real>
<real>0.0</real>
<real>0.0</real>
<real>0.0</real>
<real>1.0</real>
</array>
</map>
@ -19454,7 +19454,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>2</real>
<real>2.0</real>
</map>
<key>TeleportLocalDelay</key>
<map>
@ -19465,7 +19465,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1</real>
<real>1.0</real>
</map>
<key>FMODExProfilerEnable</key>
<map>
@ -23400,6 +23400,28 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<string/>
</map>
<key>FSEnablePerGroupSnoozeDuration</key>
<map>
<key>Comment</key>
<string>Enables input of a snooze duration per group.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSExperienceSearchMaturityRating</key>
<map>
<key>Comment</key>
<string>Setting for the user's preferred maturity level for experiences search (consts in indra_constants.h)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>13</integer>
</map>
</map>
</llsd>

View File

@ -49,6 +49,7 @@
#include "llchiclet.h"
#include "llchicletbar.h"
#include "llfloaterabout.h" // for sysinfo button -Zi
#include "llfloateravatarpicker.h"
#include "llfloaterreg.h"
#include "llgroupactions.h"
#include "llhttpclient.h"
@ -105,13 +106,10 @@ FSFloaterIM::FSFloaterIM(const LLUUID& session_id)
mUnreadMessagesNotificationPanel(NULL),
mUnreadMessagesNotificationTextBox(NULL)
{
LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(mSessionID);
if (im_session)
initIMSession(session_id);
switch (mDialog)
{
mSessionInitialized = im_session->mSessionInitialized;
mDialog = im_session->mType;
switch(mDialog){
case IM_NOTHING_SPECIAL:
case IM_SESSION_P2P_INVITE:
mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this);
@ -123,7 +121,7 @@ FSFloaterIM::FSFloaterIM(const LLUUID& session_id)
setCanSnooze(TRUE);
mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this);
break;
case IM_SESSION_INVITE:
case IM_SESSION_INVITE:
if (gAgent.isInGroup(mSessionID))
{
setCanSnooze(TRUE);
@ -135,9 +133,8 @@ FSFloaterIM::FSFloaterIM(const LLUUID& session_id)
}
break;
default: break;
}
}
mCommitCallbackRegistrar.add("IMSession.Menu.Action", boost::bind(&FSFloaterIM::doToSelected, this, _2));
mEnableCallbackRegistrar.add("IMSession.Menu.Enable", boost::bind(&FSFloaterIM::checkEnabled, this, _2));
@ -211,8 +208,7 @@ void FSFloaterIM::onClose(bool app_quitting)
void FSFloaterIM::onSnooze()
{
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(
mSessionID);
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID);
if (session == NULL)
{
@ -229,10 +225,57 @@ void FSFloaterIM::onSnooze()
{
LLSD payload;
payload["session_id"] = mSessionID;
payload["snooze"] = true;
LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
return;
}
confirmSnooze();
}
void FSFloaterIM::confirmSnooze()
{
if (gSavedSettings.getBOOL("FSEnablePerGroupSnoozeDuration"))
{
LLSD args;
args["DURATION"] = gSavedSettings.getS32("GroupSnoozeTime");
LLNotificationsUtil::add("SnoozeDuration", args, LLSD(), boost::bind(&FSFloaterIM::snoozeDurationCallback, this, _1, _2));
return;
}
snooze();
}
void FSFloaterIM::snoozeDurationCallback(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (0 == option)
{
std::istringstream duration_str(response["duration"].asString());
S32 duration(-1);
if (duration_str >> duration && duration >= 0)
{
snooze(duration);
}
else
{
LLNotificationsUtil::add("SnoozeDurationInvalidInput");
}
}
}
void FSFloaterIM::snooze(S32 duration /*= -1*/)
{
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID);
if (session == NULL)
{
LL_WARNS("FSFloaterIM") << "Empty session." << LL_ENDL;
return;
}
session->mSnoozeTime = duration;
session->mCloseAction = LLIMModel::LLIMSession::CLOSE_SNOOZE;
LLFloater::onClickCloseBtn();
@ -477,6 +520,8 @@ void FSFloaterIM::doToSelected(const LLSD& userdata)
LLAvatarActions::teleportRequest(mOtherParticipantUUID);
else if (command == "share")
LLAvatarActions::share(mOtherParticipantUUID);
else if (command == "add_participant")
onAddButtonClicked();
else if (command == "pay")
LLAvatarActions::pay(mOtherParticipantUUID);
else if (command == "show_profile")
@ -495,7 +540,7 @@ void FSFloaterIM::doToSelected(const LLSD& userdata)
{
if (gSavedSettings.getBOOL("FSUseBuiltInHistory"))
{
LLFloaterReg::showInstance("preview_conversation", mSessionID, true);
LLFloaterReg::showInstance("preview_conversation", mSessionID, TRUE);
}
else
{
@ -575,7 +620,7 @@ void FSFloaterIM::updateCallButton()
if (!session)
{
getChild<LLButton>("call_btn")->setEnabled(false);
getChild<LLButton>("call_btn")->setEnabled(FALSE);
return;
}
@ -632,7 +677,7 @@ BOOL FSFloaterIM::postBuild()
// AO: always hide the control panel to start.
LL_DEBUGS("FSFloaterIM") << "mControlPanel->getParent()" << mControlPanel->getParent() << LL_ENDL;
mControlPanel->getParent()->setVisible(false);
mControlPanel->getParent()->setVisible(FALSE);
LL_DEBUGS("FSFloaterIM") << "buttons setup in IM start" << LL_ENDL;
@ -657,10 +702,10 @@ BOOL FSFloaterIM::postBuild()
case LLIMModel::LLIMSession::P2P_SESSION: // One-on-one IM
{
LL_DEBUGS("FSFloaterIM") << "LLIMModel::LLIMSession::P2P_SESSION" << LL_ENDL;
getChild<LLLayoutPanel>("slide_panel")->setVisible(false);
getChild<LLLayoutPanel>("gprofile_panel")->setVisible(false);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("slide_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("gprofile_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(FALSE);
LL_DEBUGS("FSFloaterIM") << "adding FSFloaterIM removing/adding particularfriendobserver" << LL_ENDL;
LLAvatarTracker::instance().removeParticularFriendObserver(mOtherParticipantUUID, this);
@ -690,13 +735,14 @@ BOOL FSFloaterIM::postBuild()
case LLIMModel::LLIMSession::GROUP_SESSION: // Group chat
{
LL_DEBUGS("FSFloaterIM") << "LLIMModel::LLIMSession::GROUP_SESSION start" << LL_ENDL;
getChild<LLLayoutPanel>("profile_panel")->setVisible(false);
getChild<LLLayoutPanel>("friend_panel")->setVisible(false);
getChild<LLLayoutPanel>("tp_panel")->setVisible(false);
getChild<LLLayoutPanel>("share_panel")->setVisible(false);
getChild<LLLayoutPanel>("pay_panel")->setVisible(false);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("profile_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("friend_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("tp_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("share_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("pay_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("add_participant_panel")->setVisible(FALSE);
LL_DEBUGS("FSFloaterIM") << "LLIMModel::LLIMSession::GROUP_SESSION end" << LL_ENDL;
break;
@ -704,21 +750,21 @@ BOOL FSFloaterIM::postBuild()
case LLIMModel::LLIMSession::ADHOC_SESSION: // Conference chat
{
LL_DEBUGS("FSFloaterIM") << "LLIMModel::LLIMSession::ADHOC_SESSION start" << LL_ENDL;
getChild<LLLayoutPanel>("profile_panel")->setVisible(false);
getChild<LLLayoutPanel>("gprofile_panel")->setVisible(false);
getChild<LLLayoutPanel>("friend_panel")->setVisible(false);
getChild<LLLayoutPanel>("tp_panel")->setVisible(false);
getChild<LLLayoutPanel>("share_panel")->setVisible(false);
getChild<LLLayoutPanel>("pay_panel")->setVisible(false);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("profile_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("gprofile_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("friend_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("tp_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("share_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("pay_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(FALSE);
LL_DEBUGS("FSFloaterIM") << "LLIMModel::LLIMSession::ADHOC_SESSION end" << LL_ENDL;
break;
}
default:
LL_DEBUGS("FSFloaterIM") << "default buttons start" << LL_ENDL;
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(false);
getChild<LLLayoutPanel>("end_call_btn_panel")->setVisible(FALSE);
getChild<LLLayoutPanel>("voice_ctrls_btn_panel")->setVisible(FALSE);
LL_DEBUGS("FSFloaterIM") << "default buttons end" << LL_ENDL;
break;
}
@ -926,6 +972,13 @@ void FSFloaterIM::draw()
mOtherTyping = false;
}
// add people who were added via dropPerson()
if (!mPendingParticipants.empty())
{
addSessionParticipants(mPendingParticipants);
mPendingParticipants.clear();
}
LLTransientDockableFloater::draw();
}
@ -1214,14 +1267,17 @@ void FSFloaterIM::sessionInitReplyReceived(const LLUUID& im_session_id)
//need to send delayed messaged collected while waiting for session initialization
if (!mQueuedMsgsForInit.size()) return;
LLSD::array_iterator iter;
for ( iter = mQueuedMsgsForInit.beginArray();
iter != mQueuedMsgsForInit.endArray();
++iter)
if (mQueuedMsgsForInit.size())
{
LLIMModel::sendMessage(iter->asString(), mSessionID,
mOtherParticipantUUID, mDialog);
LLSD::array_iterator iter;
for ( iter = mQueuedMsgsForInit.beginArray();
iter != mQueuedMsgsForInit.endArray(); ++iter)
{
LLIMModel::sendMessage(iter->asString(), mSessionID,
mOtherParticipantUUID, mDialog);
}
mQueuedMsgsForInit.clear();
}
}
@ -1443,31 +1499,68 @@ void FSFloaterIM::processIMTyping(const LLIMInfo* im_info, BOOL typing)
void FSFloaterIM::processAgentListUpdates(const LLSD& body)
{
if ( !body.isMap() ) return;
loadInitialInvitedIDs();
if ( body.has("agent_updates") && body["agent_updates"].isMap() )
uuid_vec_t joined_uuids;
if (body.isMap() && body.has("agent_updates") && body["agent_updates"].isMap())
{
LLSD agent_data = body["agent_updates"].get(gAgentID.asString());
if (agent_data.isMap() && agent_data.has("info"))
LLSD::map_const_iterator update_it;
for(update_it = body["agent_updates"].beginMap();
update_it != body["agent_updates"].endMap();
++update_it)
{
LLSD agent_info = agent_data["info"];
LLUUID agent_id(update_it->first);
LLSD agent_data = update_it->second;
if (agent_info.has("mutes"))
if (agent_data.isMap())
{
BOOL moderator_muted_text = agent_info["mutes"]["text"].asBoolean();
mInputEditor->setEnabled(!moderator_muted_text);
std::string label;
if (moderator_muted_text)
label = LLTrans::getString("IM_muted_text_label");
else
label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID);
mInputEditor->setLabel(label);
// store the new participants in joined_uuids
if (agent_data.has("transition") && agent_data["transition"].asString() == "ENTER")
{
joined_uuids.push_back(agent_id);
}
if (moderator_muted_text)
LLNotificationsUtil::add("TextChatIsMutedByModerator");
// process the moderator mutes
if (agent_id == gAgentID && agent_data.has("info") && agent_data["info"].has("mutes"))
{
BOOL moderator_muted_text = agent_data["info"]["mutes"]["text"].asBoolean();
mInputEditor->setEnabled(!moderator_muted_text);
std::string label;
if (moderator_muted_text)
label = LLTrans::getString("IM_muted_text_label");
else
label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID);
mInputEditor->setLabel(label);
if (moderator_muted_text)
LLNotificationsUtil::add("TextChatIsMutedByModerator");
}
}
}
}
// the vectors need to be sorted for computing the intersection and difference
std::sort(mInvitedParticipants.begin(), mInvitedParticipants.end());
std::sort(joined_uuids.begin(), joined_uuids.end());
uuid_vec_t intersection; // uuids of invited residents who have joined the conversation
std::set_intersection(mInvitedParticipants.begin(), mInvitedParticipants.end(),
joined_uuids.begin(), joined_uuids.end(),
std::back_inserter(intersection));
if (intersection.size() > 0)
{
sendParticipantsAddedNotification(intersection);
}
// Remove all joined participants from invited array.
// The difference between the two vectors (the elements in mInvitedParticipants which are not in joined_uuids)
// is placed at the beginning of mInvitedParticipants, then all other elements are erased.
mInvitedParticipants.erase(std::set_difference(mInvitedParticipants.begin(), mInvitedParticipants.end(),
joined_uuids.begin(), joined_uuids.end(),
mInvitedParticipants.begin()),
mInvitedParticipants.end());
}
void FSFloaterIM::sendParticipantsAddedNotification(const uuid_vec_t& uuids)
@ -1537,15 +1630,26 @@ BOOL FSFloaterIM::handleDragAndDrop(S32 x, S32 y, MASK mask,
void *cargo_data, EAcceptance *accept,
std::string& tooltip_msg)
{
if (cargo_type == DAD_PERSON)
{
if (dropPerson(static_cast<LLUUID*>(cargo_data), drop))
{
*accept = ACCEPT_YES_MULTI;
}
else
{
*accept = ACCEPT_NO;
}
}
if (mDialog == IM_NOTHING_SPECIAL)
else if (mDialog == IM_NOTHING_SPECIAL)
{
LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionID, drop,
cargo_type, cargo_data, accept);
}
// handle case for dropping calling cards (and folders of calling cards) onto invitation panel for invites
else if (isInviteAllowed())
else if (isInviteAllowed() && !mIsP2PChat)
{
*accept = ACCEPT_NO;
@ -1567,30 +1671,37 @@ BOOL FSFloaterIM::handleDragAndDrop(S32 x, S32 y, MASK mask,
return TRUE;
}
BOOL FSFloaterIM::dropCallingCard(LLInventoryItem* item, BOOL drop)
bool FSFloaterIM::dropCallingCard(LLInventoryItem* item, bool drop)
{
BOOL rv = isInviteAllowed();
if(rv && item && item->getCreatorUUID().notNull())
bool rv = true;
if(item && item->getCreatorUUID().notNull())
{
if(drop)
uuid_vec_t ids;
ids.push_back(item->getCreatorUUID());
if (canAddSelectedToChat(ids))
{
uuid_vec_t ids;
ids.push_back(item->getCreatorUUID());
inviteToSession(ids);
if (drop)
{
mPendingParticipants.push_back(item->getCreatorUUID());
}
}
else
{
rv = false;
}
}
else
{
// set to false if creator uuid is null.
rv = FALSE;
rv = false;
}
return rv;
}
BOOL FSFloaterIM::dropCategory(LLInventoryCategory* category, BOOL drop)
bool FSFloaterIM::dropCategory(LLInventoryCategory* category, bool drop)
{
BOOL rv = isInviteAllowed();
if(rv && category)
bool rv = true;
if(category)
{
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
@ -1603,9 +1714,9 @@ BOOL FSFloaterIM::dropCategory(LLInventoryCategory* category, BOOL drop)
S32 count = items.size();
if(count == 0)
{
rv = FALSE;
rv = false;
}
else if(drop)
else
{
uuid_vec_t ids;
ids.reserve(count);
@ -1613,17 +1724,48 @@ BOOL FSFloaterIM::dropCategory(LLInventoryCategory* category, BOOL drop)
{
ids.push_back(items.at(i)->getCreatorUUID());
}
inviteToSession(ids);
if (canAddSelectedToChat(ids))
{
if (drop)
{
mPendingParticipants.insert(mPendingParticipants.end(), ids.begin(), ids.end());
}
}
else
{
rv = false;
}
}
}
return rv;
}
bool FSFloaterIM::dropPerson(LLUUID* person_id, bool drop)
{
bool res = person_id && person_id->notNull();
if(res)
{
uuid_vec_t ids;
ids.push_back(*person_id);
res = canAddSelectedToChat(ids);
if(res && drop)
{
// these people will be added during the next draw() call
// (so they can be added all at once)
mPendingParticipants.push_back(*person_id);
}
}
return res;
}
BOOL FSFloaterIM::isInviteAllowed() const
{
return ((IM_SESSION_CONFERENCE_START == mDialog) ||
(IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID)));
return ( (IM_SESSION_CONFERENCE_START == mDialog)
|| (IM_SESSION_INVITE == mDialog && !gAgent.isInGroup(mSessionID))
|| mIsP2PChat);
}
class FSSessionInviteResponder : public LLHTTPClient::Responder
@ -1761,10 +1903,22 @@ void FSFloaterIM::confirmLeaveCallCallback(const LLSD& notification, const LLSD&
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
const LLSD& payload = notification["payload"];
LLUUID session_id = payload["session_id"];
bool snooze = payload["snooze"].asBoolean();
LLFloater* im_floater = LLFloaterReg::findInstance("fs_impanel", session_id);
FSFloaterIM* im_floater = LLFloaterReg::findTypedInstance<FSFloaterIM>("fs_impanel", session_id);
if (option == 0 && im_floater != NULL)
{
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
if (session)
{
if (snooze)
{
im_floater->confirmSnooze();
return;
}
session->mCloseAction = LLIMModel::LLIMSession::CLOSE_DEFAULT;
}
im_floater->closeFloater();
}
@ -1841,6 +1995,7 @@ void FSFloaterIM::onClickCloseBtn(bool app_quitting)
{
LLSD payload;
payload["session_id"] = mSessionID;
payload["snooze"] = false;
LLNotificationsUtil::add("ConfirmLeaveCall", LLSD(), payload, confirmLeaveCallCallback);
return;
}
@ -1905,6 +2060,7 @@ void FSFloaterIM::initIMSession(const LLUUID& session_id)
if (session)
{
mIsP2PChat = session->isP2PSessionType();
mSessionInitialized = session->mSessionInitialized;
mDialog = session->mType;
}
@ -1932,3 +2088,158 @@ void FSFloaterIM::updateUnreadMessageNotification(S32 unread_messages)
mUnreadMessagesNotificationPanel->setVisible(TRUE);
}
}
void FSFloaterIM::onAddButtonClicked()
{
LLView* button = findChild<LLButton>("add_participant_btn");
LLFloater* root_floater = this;
LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&FSFloaterIM::addSessionParticipants, this, _1), TRUE, TRUE, FALSE, root_floater->getName(), button);
if (!picker)
{
return;
}
// Need to disable 'ok' button when selected users are already in conversation.
picker->setOkBtnEnableCb(boost::bind(&FSFloaterIM::canAddSelectedToChat, this, _1));
if (root_floater)
{
root_floater->addDependentFloater(picker);
}
}
bool FSFloaterIM::canAddSelectedToChat(const uuid_vec_t& uuids)
{
if (!LLIMModel::instance().findIMSession(mSessionID)
|| mDialog == IM_SESSION_GROUP_START
|| (mDialog == IM_SESSION_INVITE && gAgent.isInGroup(mSessionID)))
{
return false;
}
if (mIsP2PChat)
{
// For a P2P session just check if we are not adding the other participant.
for (uuid_vec_t::const_iterator id = uuids.begin();
id != uuids.end(); ++id)
{
if (*id == mOtherParticipantUUID)
{
return false;
}
}
}
else
{
// For a conference session we need to check against the list from LLSpeakerMgr,
// because this list may change when participants join or leave the session.
LLSpeakerMgr::speaker_list_t speaker_list;
LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
if (speaker_mgr)
{
speaker_mgr->getSpeakerList(&speaker_list, true);
}
for (uuid_vec_t::const_iterator id = uuids.begin();
id != uuids.end(); ++id)
{
for (LLSpeakerMgr::speaker_list_t::const_iterator it = speaker_list.begin();
it != speaker_list.end(); ++it)
{
const LLPointer<LLSpeaker>& speaker = *it;
if (*id == speaker->mID)
{
return false;
}
}
}
}
return true;
}
void FSFloaterIM::addSessionParticipants(const uuid_vec_t& uuids)
{
if (mIsP2PChat)
{
LLSD payload;
LLSD args;
LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload,
boost::bind(&FSFloaterIM::addP2PSessionParticipants, this, _1, _2, uuids));
}
else
{
if(findInstance(mSessionID))
{
// remember whom we have invited, to notify others later, when the invited ones actually join
mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
}
inviteToSession(uuids);
}
}
void FSFloaterIM::addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option != 0)
{
return;
}
LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID);
// first check whether this is a voice session
bool is_voice_call = voice_channel != NULL && voice_channel->isActive();
uuid_vec_t temp_ids;
uuid_vec_t invited_ids;
// Add the initial participant of a P2P session
temp_ids.push_back(mOtherParticipantUUID);
temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end());
LLUUID session_id = mSessionID;
// then we can close the current session
if(findInstance(mSessionID))
{
// remember whom we have invited, to notify others later, when the invited ones actually join
mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end());
invited_ids.insert(invited_ids.end(), mInvitedParticipants.begin(), mInvitedParticipants.end());
// Ansariel: This will result in the floater actually being closed as opposed in CHUI!
onClose(false);
}
// Start a new ad hoc voice call if we invite new participants to a P2P call,
// or start a text chat otherwise.
if (is_voice_call)
{
session_id = LLAvatarActions::startAdhocCall(temp_ids, session_id);
}
else
{
session_id = LLAvatarActions::startConference(temp_ids, session_id);
}
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
if (session)
{
session->mInitialInvitedIDs = invited_ids;
}
}
void FSFloaterIM::loadInitialInvitedIDs()
{
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID);
if (session && !session->mInitialInvitedIDs.empty())
{
mInvitedParticipants = session->mInitialInvitedIDs;
session->mInitialInvitedIDs.clear();
}
}

View File

@ -150,6 +150,8 @@ public:
void updateUnreadMessageNotification(S32 unread_messages);
void loadInitialInvitedIDs();
protected:
/* virtual */
void onClickCloseBtn(bool app_quitting = false);
@ -174,8 +176,9 @@ private:
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
void fetchAvatarName(LLUUID& agent_id);
BOOL dropCallingCard(LLInventoryItem* item, BOOL drop);
BOOL dropCategory(LLInventoryCategory* category, BOOL drop);
bool dropCallingCard(LLInventoryItem* item, bool drop);
bool dropCategory(LLInventoryCategory* category, bool drop);
bool dropPerson(LLUUID* person_id, bool drop);
BOOL isInviteAllowed() const;
BOOL inviteToSession(const uuid_vec_t& agent_ids);
@ -213,6 +216,15 @@ private:
void sendParticipantsAddedNotification(const uuid_vec_t& uuids);
void confirmSnooze();
void snoozeDurationCallback(const LLSD& notification, const LLSD& response);
void snooze(S32 duration = -1);
void onAddButtonClicked();
bool canAddSelectedToChat(const uuid_vec_t& uuids);
void addSessionParticipants(const uuid_vec_t& uuids);
void addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids);
FSPanelChatControlPanel* mControlPanel;
LLUUID mSessionID;
S32 mLastMessageIndex;
@ -240,12 +252,17 @@ private:
bool mSessionInitialized;
LLSD mQueuedMsgsForInit;
bool mIsP2PChat;
LLVoiceChannel* mVoiceChannel;
S32 mInputEditorPad;
S32 mChatLayoutPanelHeight;
S32 mFloaterHeight;
uuid_vec_t mInvitedParticipants;
uuid_vec_t mPendingParticipants;
boost::signals2::connection mAvatarNameCacheConnection;
};

View File

@ -180,12 +180,12 @@ FSPanelProfileSecondLife::FSPanelProfileSecondLife()
FSPanelProfileSecondLife::~FSPanelProfileSecondLife()
{
if(getAvatarId().notNull())
if (getAvatarId().notNull())
{
LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
}
if(LLVoiceClient::instanceExists())
if (LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
}
@ -214,7 +214,7 @@ BOOL FSPanelProfileSecondLife::postBuild()
mIMButton = getChild<LLButton>("im");
mOverflowButton = getChild<LLMenuButton>("overflow_btn");
mStatusText->setVisible(false);
mStatusText->setVisible(FALSE);
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("Profile.Call", boost::bind(&FSPanelProfileSecondLife::onCallButtonClick, this));
@ -249,8 +249,8 @@ BOOL FSPanelProfileSecondLife::postBuild()
mOverflowButton->setMenu(profile_menu, LLMenuButton::MP_TOP_RIGHT);
// allow skins to have copy buttons for name and avatar URI -Zi
LLButton* copy_uri_button=findChild<LLButton>("copy_uri_button");
LLButton* copy_name_button=findChild<LLButton>("copy_name_button");
LLButton* copy_uri_button = findChild<LLButton>("copy_uri_button");
LLButton* copy_name_button = findChild<LLButton>("copy_name_button");
if (copy_uri_button)
{
@ -277,50 +277,50 @@ void FSPanelProfileSecondLife::onOpen(const LLSD& key)
resetData();
LLUUID avatar_id = getAvatarId();
LLAvatarPropertiesProcessor::getInstance()->addObserver(avatar_id,this);
LLAvatarPropertiesProcessor::getInstance()->addObserver(avatar_id, this);
BOOL own_profile = getSelfProfile();
mGroupInviteButton->setVisible( !own_profile );
mShowOnMapButton->setVisible( !own_profile );
mPayButton->setVisible( !own_profile );
mTeleportButton->setVisible( !own_profile );
mIMButton->setVisible( !own_profile );
mAddFriendButton->setVisible( !own_profile );
mBlockButton->setVisible( !own_profile );
mUnblockButton->setVisible( !own_profile );
mOverflowButton->setVisible( !own_profile );
mGroupList->setShowNone( !own_profile );
mGroupInviteButton->setVisible(!own_profile);
mShowOnMapButton->setVisible(!own_profile);
mPayButton->setVisible(!own_profile);
mTeleportButton->setVisible(!own_profile);
mIMButton->setVisible(!own_profile);
mAddFriendButton->setVisible(!own_profile);
mBlockButton->setVisible(!own_profile);
mUnblockButton->setVisible(!own_profile);
mOverflowButton->setVisible(!own_profile);
mGroupList->setShowNone(!own_profile);
if (own_profile && !getEmbedded())
{
// Group list control cannot toggle ForAgent loading
// Less than ideal, but viewing own profile via search is edge case
mGroupList->enableForAgent( false );
mGroupList->enableForAgent(false);
}
if (own_profile && LLAvatarName::useDisplayNames() && !getEmbedded() )
if (own_profile && LLAvatarName::useDisplayNames() && !getEmbedded())
{
mDisplayNameButton->setVisible( true );
mDisplayNameButton->setEnabled( true );
mDisplayNameButton->setVisible(TRUE);
mDisplayNameButton->setEnabled(TRUE);
}
mDescriptionEdit->setParseHTML( !own_profile && !getEmbedded() );
FSDropTarget* drop_target = getChild<FSDropTarget> ("drop_target");
drop_target->setVisible( !own_profile );
drop_target->setEnabled( !own_profile );
FSDropTarget* drop_target = getChild<FSDropTarget>("drop_target");
drop_target->setVisible(!own_profile);
drop_target->setEnabled(!own_profile);
if (!own_profile)
{
mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : TRUE);
drop_target->setAgentID( avatar_id );
drop_target->setAgentID(avatar_id);
updateOnlineStatus();
}
updateButtons();
getChild<LLUICtrl>("user_key")->setValue( avatar_id.asString() );
getChild<LLUICtrl>("user_key")->setValue(avatar_id.asString());
}
void FSPanelProfileSecondLife::apply(LLAvatarData* data)
@ -769,7 +769,7 @@ void FSPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id,
{
// something is wrong, tell user to try again later
LLNotificationsUtil::add("SetDisplayNameFailedGeneric");
return;
return;
}
LL_INFOS("LegacyProfile") << "name-change now " << LLDate::now() << " next_update "
@ -780,7 +780,7 @@ void FSPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id,
{
// if the update time is more than a year in the future, it means updates have been blocked
// show a more general message
const int YEAR = 60*60*24*365;
static const S32 YEAR = 60*60*24*365;
if (now_secs + YEAR < av_name.mNextUpdate)
{
LLNotificationsUtil::add("SetDisplayNameBlocked");
@ -835,7 +835,7 @@ BOOL FSPanelProfileWeb::postBuild()
mWebBrowser = getChild<LLMediaCtrl>("profile_html");
mWebBrowser->addObserver(this);
mUrlEdit->setEnabled( FALSE );
mUrlEdit->setEnabled(FALSE);
return TRUE;
}
@ -926,7 +926,7 @@ void FSPanelProfileWeb::onCommitLoad(LLUICtrl* ctrl)
if (!mURLHome.empty())
{
LLSD::String valstr = ctrl->getValue().asString();
if (valstr == "")
if (valstr.empty())
{
mWebBrowser->setVisible(TRUE);
mPerformanceTimer.start();
@ -950,7 +950,7 @@ void FSPanelProfileWeb::onCommitWebProfile(LLUICtrl* ctrl)
if (!mURLWebProfile.empty())
{
LLSD::String valstr = ctrl->getValue().asString();
if (valstr == "")
if (valstr.empty())
{
mWebBrowser->setVisible(TRUE);
mPerformanceTimer.start();
@ -1226,7 +1226,7 @@ void FSPanelPick::setAvatarId(const LLUUID& avatar_id)
FSPanelProfileTab::setAvatarId(avatar_id);
// creating new Pick
if (getPickId().isNull())
if (getPickId().isNull() && getSelfProfile())
{
mNewPick = true;
@ -1269,9 +1269,9 @@ void FSPanelPick::setAvatarId(const LLUUID& avatar_id)
if (getSelfProfile() && !getEmbedded())
{
mPickName->setEnabled( TRUE );
mPickDescription->setEnabled( TRUE );
mSetCurrentLocationButton->setVisible( TRUE );
mPickName->setEnabled(TRUE);
mPickDescription->setEnabled(TRUE);
mSetCurrentLocationButton->setVisible(TRUE);
}
/*else
{
@ -1296,7 +1296,7 @@ BOOL FSPanelPick::postBuild()
mSetCurrentLocationButton->setCommitCallback(boost::bind(&FSPanelPick::onClickSetLocation, this));
mPickName->setKeystrokeCallback(boost::bind(&FSPanelPick::onPickChanged, this, _1), NULL);
mPickName->setEnabled( FALSE );
mPickName->setEnabled(FALSE);
mPickDescription->setKeystrokeCallback(boost::bind(&FSPanelPick::onPickChanged, this, _1));
mPickDescription->setFocusReceivedCallback(boost::bind(&FSPanelPick::onDescriptionFocusReceived, this));
@ -1322,6 +1322,7 @@ void FSPanelPick::processProperties(void* data, EAvatarProcessorType type)
{
return;
}
LLPickData* pick_info = static_cast<LLPickData*>(data);
if (!pick_info
|| pick_info->creator_id != getAvatarId()
@ -1363,6 +1364,7 @@ void FSPanelPick::setSnapshotId(const LLUUID& id)
void FSPanelPick::setPickName(const std::string& name)
{
mPickName->setValue(name);
updateTabLabel(name);
}
const std::string FSPanelPick::getPickName()
@ -1408,6 +1410,11 @@ void FSPanelPick::onSnapshotChanged()
void FSPanelPick::onPickChanged(LLUICtrl* ctrl)
{
if (ctrl && ctrl == mPickName)
{
updateTabLabel(mPickName->getText());
}
enableSaveButton(isDirty());
}
@ -1478,7 +1485,7 @@ void FSPanelPick::apply()
std::string FSPanelPick::getLocationNotice()
{
static std::string notice = getString("location_notice");
static const std::string notice = getString("location_notice");
return notice;
}
@ -1486,6 +1493,10 @@ void FSPanelPick::sendParcelInfoRequest()
{
if (mParcelId != mRequestedId)
{
if (mRequestedId.notNull())
{
LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this);
}
LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this);
LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId);
@ -1532,7 +1543,6 @@ void FSPanelPick::sendUpdate()
pick_data.sort_order = 0;
pick_data.enabled = TRUE;
// LLAvatarPropertiesProcessor::instance().sendPickInfoUpdate(&pick_data);
LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data);
if(mNewPick)
@ -1547,21 +1557,30 @@ void FSPanelPick::sendUpdate()
// static
std::string FSPanelPick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global)
{
std::string location_text;
location_text.append(owner_name);
std::string location_text(owner_name);
if (!original_name.empty())
{
if (!location_text.empty()) location_text.append(", ");
if (!location_text.empty())
{
location_text.append(", ");
}
location_text.append(original_name);
}
if (!sim_name.empty())
{
if (!location_text.empty()) location_text.append(", ");
if (!location_text.empty())
{
location_text.append(", ");
}
location_text.append(sim_name);
}
if (!location_text.empty()) location_text.append(" ");
if (!location_text.empty())
{
location_text.append(" ");
}
if (!pos_global.isNull())
{
@ -1573,6 +1592,15 @@ std::string FSPanelPick::createLocationText(const std::string& owner_name, const
return location_text;
}
void FSPanelPick::updateTabLabel(const std::string& title)
{
setLabel(title);
LLTabContainer* parent = dynamic_cast<LLTabContainer*>(getParent());
if (parent)
{
parent->setCurrentTabName(title);
}
}
//////////////////////////////////////////////////////////////////////////
@ -1598,11 +1626,11 @@ void FSPanelProfilePicks::onOpen(const LLSD& key)
if (getSelfProfile() && !getEmbedded())
{
mNewButton->setVisible( TRUE );
mNewButton->setEnabled( TRUE );
mNewButton->setVisible(TRUE);
mNewButton->setEnabled(FALSE);
mDeleteButton->setVisible( TRUE );
mDeleteButton->setEnabled( TRUE );
mDeleteButton->setVisible(TRUE);
mDeleteButton->setEnabled(FALSE);
}
}
@ -1617,20 +1645,27 @@ BOOL FSPanelProfilePicks::postBuild()
mDeleteButton->setCommitCallback(boost::bind(&FSPanelProfilePicks::onClickDelete, this));
mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&FSPanelProfilePicks::updateRlvRestrictions, this, _1, _2));
mNewButton->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
mNewButton->setEnabled(canAddNewPick());
mDeleteButton->setEnabled(canDeletePick());
LLTextBox* intro_txt = getChild<LLTextBox>("Tell everyone about your favorite places in Second Life.");
intro_txt->setTextArg("[GRID]", LLTrans::getString("SECOND_LIFE"));
return TRUE;
}
void FSPanelProfilePicks::onClickNewBtn()
{
mNoItemsLabel->setVisible(false);
mNoItemsLabel->setVisible(FALSE);
FSPanelPick* pick_panel = FSPanelPick::create();
pick_panel->setAvatarId(getAvatarId());
mTabContainer->addTabPanel(
LLTabContainer::TabPanelParams().
panel(pick_panel).
select_tab(true));
mNewButton->setEnabled(canAddNewPick());
mDeleteButton->setEnabled(canDeletePick());
}
void FSPanelProfilePicks::onClickDelete()
@ -1639,43 +1674,38 @@ void FSPanelProfilePicks::onClickDelete()
if (pick_panel)
{
LLUUID pick_id = pick_panel->getPickId();
if (!pick_id.isNull())
{
LLSD args;
args["PICK"] = pick_panel->getPickName();
LLSD payload;
payload["pick_id"] = pick_id;
LLNotificationsUtil::add("DeleteAvatarPick", args, payload, boost::bind(&FSPanelProfilePicks::callbackDeletePick, this, _1, _2));
return;
}
LLSD args;
args["PICK"] = pick_panel->getPickName();
LLSD payload;
payload["pick_id"] = pick_id;
payload["tab_idx"] = mTabContainer->getCurrentPanelIndex();
LLNotificationsUtil::add("DeleteAvatarPick", args, payload, boost::bind(&FSPanelProfilePicks::callbackDeletePick, this, _1, _2));
}
}
bool FSPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response)
void FSPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (0 == option)
{
LLUUID pick_id = notification["payload"]["pick_id"].asUUID();
LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id);
// LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_id);
mNewButton->setEnabled(!LLAgentPicksInfo::getInstance()->isPickLimitReached());
S32 tab_idx = notification["payload"]["tab_idx"].asInteger();
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
FSPanelPick* pick_panel = dynamic_cast<FSPanelPick*>(mTabContainer->getPanelByIndex(tab_idx));
if (pick_panel && pick_panel->getPickId() == pick_id)
{
FSPanelPick* pick_panel = (FSPanelPick*)mTabContainer->getPanelByIndex(tab_idx);
if (pick_panel)
{
if (pick_id == pick_panel->getPickId())
{
mTabContainer->removeTabPanel(pick_panel);
}
}
mTabContainer->removeTabPanel(pick_panel);
}
}
return false;
if (pick_id.notNull())
{
LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id);
}
mNewButton->setEnabled(canAddNewPick());
mDeleteButton->setEnabled(canDeletePick());
}
}
void FSPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type)
@ -1717,9 +1747,10 @@ void FSPanelProfilePicks::processProperties(void* data, EAvatarProcessorType typ
label(pick_name));
}
mNewButton->setEnabled(!LLAgentPicksInfo::getInstance()->isPickLimitReached());
mNewButton->setEnabled(canAddNewPick());
mDeleteButton->setEnabled(canDeletePick());
bool no_data = !mTabContainer->getTabCount();
BOOL no_data = !mTabContainer->getTabCount();
mNoItemsLabel->setVisible(no_data);
if (no_data)
{
@ -1754,7 +1785,7 @@ void FSPanelProfilePicks::apply()
{
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
FSPanelPick* pick_panel = (FSPanelPick*)mTabContainer->getPanelByIndex(tab_idx);
FSPanelPick* pick_panel = dynamic_cast<FSPanelPick*>(mTabContainer->getPanelByIndex(tab_idx));
if (pick_panel)
{
pick_panel->apply();
@ -1780,10 +1811,22 @@ void FSPanelProfilePicks::updateRlvRestrictions(ERlvBehaviour behavior, ERlvPara
{
if (behavior == RLV_BHVR_SHOWLOC)
{
mNewButton->setEnabled(type != RLV_TYPE_ADD);
mNewButton->setEnabled(canAddNewPick());
}
}
bool FSPanelProfilePicks::canAddNewPick()
{
return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() &&
mTabContainer->getTabCount() < LLAgentPicksInfo::getInstance()->getMaxNumberOfPicks() &&
!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
}
bool FSPanelProfilePicks::canDeletePick()
{
return (mTabContainer->getTabCount() > 0);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
@ -2099,27 +2142,10 @@ void FSPanelProfile::processProperties(void* data, EAvatarProcessorType type)
void FSPanelProfile::onTabChange()
{
LLPanel* active_panel = mTabContainer->getCurrentPanel();
if (active_panel == mPanelSecondlife)
FSPanelProfileTab* active_panel = dynamic_cast<FSPanelProfileTab*>(mTabContainer->getCurrentPanel());
if (active_panel)
{
mPanelSecondlife->updateData(); // load groups
}
else if (active_panel == mPanelWeb)
{
mPanelWeb->updateData(); // load web profile
}
else if (active_panel == mPanelPicks)
{
mPanelPicks->updateData();
}
else if (active_panel == mPanelClassifieds)
{
mPanelClassifieds->updateData();
}
else if (active_panel == mPanelNotes)
{
mPanelNotes->updateData();
active_panel->updateData();
}
}
@ -2164,8 +2190,8 @@ void FSPanelProfile::onOpen(const LLSD& key)
// Only show commit buttons on own profile on floater version
if (getSelfProfile() && !getEmbedded())
{
getChild<LLUICtrl>("ok_btn")->setVisible( true );
getChild<LLUICtrl>("cancel_btn")->setVisible( true );
getChild<LLUICtrl>("ok_btn")->setVisible(TRUE);
getChild<LLUICtrl>("cancel_btn")->setVisible(TRUE);
}
LLAvatarNameCache::get(getAvatarId(), boost::bind(&FSPanelProfile::onAvatarNameCache, this, _1, _2));

View File

@ -63,6 +63,11 @@ public:
*/
virtual void setAvatarId(const LLUUID& id);
/**
* Sends update data request to server.
*/
virtual void updateData() { }
/**
* Processes data received from server.
*/
@ -152,7 +157,7 @@ public:
/**
* Sends update data request to server.
*/
void updateData();
/*virtual*/ void updateData();
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
@ -297,7 +302,7 @@ public:
/**
* Loads web profile.
*/
void updateData();
/*virtual*/ void updateData();
/*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
@ -394,6 +399,8 @@ public:
*/
virtual void apply();
void updateTabLabel(const std::string& title);
//This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing
/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);
/*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; }
@ -529,16 +536,19 @@ public:
/**
* Sends update data request to server.
*/
void updateData();
/*virtual*/ void updateData();
private:
void onClickNewBtn();
void onClickDelete();
bool callbackDeletePick(const LLSD& notification, const LLSD& response);
void callbackDeletePick(const LLSD& notification, const LLSD& response);
boost::signals2::connection mRlvBehaviorCallbackConnection;
void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type);
bool canAddNewPick();
bool canDeletePick();
LLTabContainer* mTabContainer;
LLUICtrl* mNoItemsLabel;
LLButton* mNewButton;
@ -603,7 +613,7 @@ public:
void resetData();
void updateData();
/*virtual*/ void updateData();
/**
* Saves changes.
@ -643,6 +653,8 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void updateData();
/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
/*virtual*/ void onOpen(const LLSD& key);
@ -655,7 +667,6 @@ public:
private:
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
void onTabChange();
void updateData();
FSPanelProfileSecondLife* mPanelSecondlife;
FSPanelProfileWeb* mPanelWeb;

View File

@ -29,6 +29,7 @@
#include "fsradarlistctrl.h"
#include "llscrolllistitem.h"
#include "lltooldraganddrop.h"
#include "rlvhandler.h"
static LLDefaultChildRegistry::Register<FSRadarListCtrl> r("radar_list");
@ -68,3 +69,59 @@ BOOL FSRadarListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
}
return handled;
}
BOOL FSRadarListCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
{
gFocusMgr.setMouseCapture(this);
S32 screen_x;
S32 screen_y;
localPointToScreen(x, y, &screen_x, &screen_y);
LLToolDragAndDrop::getInstance()->setDragStart(screen_x, screen_y);
return FSScrollListCtrl::handleMouseDown(x, y, mask);
}
BOOL FSRadarListCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
{
if (hasMouseCapture())
{
gFocusMgr.setMouseCapture(NULL);
}
return FSScrollListCtrl::handleMouseUp(x, y, mask);
}
BOOL FSRadarListCtrl::handleHover(S32 x, S32 y, MASK mask)
{
bool handled = hasMouseCapture();
if (handled)
{
S32 screen_x;
S32 screen_y;
localPointToScreen(x, y, &screen_x, &screen_y);
if(LLToolDragAndDrop::getInstance()->isOverThreshold(screen_x, screen_y))
{
// First, create the global drag and drop object
std::vector<EDragAndDropType> types;
uuid_vec_t cargo_ids;
typedef std::vector<LLScrollListItem*> item_vec_t;
item_vec_t selected_items = getAllSelected();
for (item_vec_t::const_iterator it = selected_items.begin(); it != selected_items.end(); ++it)
{
cargo_ids.push_back((*it)->getUUID());
}
types.resize(cargo_ids.size(), DAD_PERSON);
LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_PEOPLE;
LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, src);
}
}
else
{
handled = FSScrollListCtrl::handleHover(x, y, mask);
}
return handled;
}

View File

@ -43,6 +43,9 @@ public:
virtual ~FSRadarListCtrl() {}
/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
protected:
friend class LLUICtrlFactory;

View File

@ -120,6 +120,7 @@
// Linden library includes
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llexperiencecache.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
@ -4008,8 +4009,8 @@ LLSD LLAppViewer::getViewerInfo() const
//}
if (gPacketsIn > 0)
{
info["PACKETS_LOST"] = LLStatViewer::PACKETS_LOST.getTotalSamples();
info["PACKETS_IN"] = LLStatViewer::PACKETS_IN.getTotalSamples();
info["PACKETS_LOST"] = S32(LLStatViewer::PACKETS_LOST.getTotalSamples());
info["PACKETS_IN"] = S32(LLStatViewer::PACKETS_IN.getTotalSamples());
info["PACKETS_PCT"] = 100.f*info["PACKETS_LOST"].asReal() / info["PACKETS_IN"].asReal();
}
@ -5514,6 +5515,32 @@ void LLAppViewer::saveNameCache()
}
}
void LLAppViewer::saveExperienceCache()
{
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
LL_INFOS("ExperienceCache") << "Saving " << filename << LL_ENDL;
llofstream cache_stream(filename.c_str());
if(cache_stream.is_open())
{
LLExperienceCache::exportFile(cache_stream);
}
}
void LLAppViewer::loadExperienceCache()
{
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
LL_INFOS("ExperienceCache") << "Loading " << filename << LL_ENDL;
llifstream cache_stream(filename.c_str());
if(cache_stream.is_open())
{
LLExperienceCache::importFile(cache_stream);
}
}
/*! @brief This class is an LLFrameTimer that can be created with
an elapsed time that starts counting up from the given value
rather than 0.0.
@ -5725,7 +5752,7 @@ void LLAppViewer::idle()
// floating throughout the various object lists.
//
idleNameCache();
idleExperienceCache();
idleNetwork();
@ -6171,6 +6198,22 @@ void LLAppViewer::idleNameCache()
LLAvatarNameCache::idle();
}
void LLAppViewer::idleExperienceCache()
{
LLViewerRegion* region = gAgent.getRegion();
if (!region) return;
std::string lookup_url=region->getCapability("GetExperienceInfo");
if(!lookup_url.empty() && *lookup_url.rbegin() != '/')
{
lookup_url += '/';
}
LLExperienceCache::setLookupURL(lookup_url);
LLExperienceCache::idle();
}
//
// Handle messages, and all message related stuff
//
@ -6341,6 +6384,7 @@ void LLAppViewer::disconnectViewer()
}
saveNameCache();
saveExperienceCache();
// close inventory interface, close all windows
LLFloaterInventory::cleanup();

View File

@ -123,6 +123,9 @@ public:
void loadNameCache();
void saveNameCache();
void loadExperienceCache();
void saveExperienceCache();
void removeMarkerFiles();
void removeDumpDir();
@ -245,6 +248,7 @@ private:
void idle();
void idleShutdown();
// update avatar SLID and display name caches
void idleExperienceCache();
void idleNameCache();
void idleNetwork();

View File

@ -178,6 +178,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier)
body["item_id"] = data.mItemId;
body["is_script_running"] = data.mIsRunning;
body["target"] = data.mIsTargetMono? "mono" : "lsl2";
body["experience"] = data.mExperienceId;
std::string url = "";
LLViewerObject* object = gObjectList.findObject(data.mTaskId);
@ -201,7 +202,8 @@ void LLAssetUploadQueue::queue(const std::string& filename,
const LLUUID& queue_id,
U8* script_data,
U32 data_size,
std::string script_name)
std::string script_name,
const LLUUID& experience_id)
{
UploadData data;
data.mTaskId = task_id;
@ -213,6 +215,7 @@ void LLAssetUploadQueue::queue(const std::string& filename,
data.mData = script_data;
data.mDataSize = data_size;
data.mScriptName = script_name;
data.mExperienceId = experience_id;
mQueue.push_back(data);

View File

@ -50,7 +50,8 @@ public:
const LLUUID& queue_id,
U8* data,
U32 data_size,
std::string script_name);
std::string script_name,
const LLUUID& experience_id);
bool isEmpty() const {return mQueue.empty();}
@ -69,6 +70,7 @@ private:
U8* mData;
U32 mDataSize;
std::string mScriptName;
LLUUID mExperienceId;
};
// Ownership of mSupplier passed to currently waiting responder

View File

@ -300,11 +300,17 @@ void LLAvatarActions::startCall(const LLUUID& id)
}
// static
void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id)
// <FS:Ansariel> [FS Communication UI]
//void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id)
const LLUUID LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id)
// </FS:Ansariel>
{
if (ids.size() == 0)
{
return;
// <FS:Ansariel> [FS Communication UI]
//return;
return LLUUID::null;
// </FS:Ansariel>
}
// convert vector into std::vector for addSession
@ -318,7 +324,7 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate
{
make_ui_sound("UISndInvalidOp");
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
return;
return LLUUID::null;
}
id_array.push_back(idAgent);
// [/RLVa:KB]
@ -331,12 +337,18 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids, const LLUUID& floate
ids[0], id_array, true, floater_id);
if (session_id == LLUUID::null)
{
return;
// <FS:Ansariel> [FS Communication UI]
//return;
return session_id;
// </FS:Ansariel>
}
gIMMgr->autoStartCallOnStartup(session_id);
make_ui_sound("UISndStartIM");
// <FS:Ansariel> [FS Communication UI]
return session_id;
}
/* AD *TODO: Is this function needed any more?
@ -361,7 +373,10 @@ bool LLAvatarActions::canCall()
}
// static
void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& floater_id)
// <FS:Ansariel> [FS Communication UI]
//void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& floater_id)
const LLUUID LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& floater_id)
// </FS:Ansariel>
{
// *HACK: Copy into dynamic array
std::vector<LLUUID> id_array;
@ -375,7 +390,7 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
{
make_ui_sound("UISndInvalidOp");
RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
return;
return LLUUID::null;
}
id_array.push_back(idAgent);
// [/RLVa:KB]
@ -386,7 +401,10 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
if (session_id == LLUUID::null)
{
return;
// <FS:Ansariel> [FS Communication UI]
//return;
return session_id;
// </FS:Ansariel>
}
// <FS:Ansariel> [FS communication UI]
@ -395,6 +413,9 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float
// </FS:Ansariel> [FS communication UI]
make_ui_sound("UISndStartIM");
// <FS:Ansariel> [FS Communication UI]
return session_id;
}
static const char* get_profile_floater_name(const LLUUID& avatar_id)

View File

@ -84,12 +84,18 @@ public:
/**
* Start an ad-hoc conference voice call with multiple users in a specific IM floater.
*/
static void startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
// <FS:Ansariel> [FS Communication UI]
//static void startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
static const LLUUID startAdhocCall(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
// </FS:Ansariel>
/**
* Start conference chat with the given avatars in a specific IM floater.
*/
static void startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
// <FS:Ansariel> [FS Communication UI]
//static void startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
static const LLUUID startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null);
// </FS:Ansariel>
/**
* Show avatar profile.

View File

@ -59,6 +59,8 @@
#include "lltrans.h"
#include "llselectmgr.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
// *TODO: This should be separated into the script queue, and the floater views of that queue.
// There should only be one floater class that can view any queue type
@ -70,11 +72,13 @@
struct LLScriptQueueData
{
LLUUID mQueueID;
std::string mScriptName;
LLUUID mTaskId;
LLUUID mItemId;
LLScriptQueueData(const LLUUID& q_id, const std::string& name, const LLUUID& task_id, const LLUUID& item_id) :
mQueueID(q_id), mScriptName(name), mTaskId(task_id), mItemId(item_id) {}
LLPointer<LLInventoryItem> mItem;
LLHost mHost;
LLUUID mExperienceId;
std::string mExperiencename;
LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item) :
mQueueID(q_id), mTaskId(task_id), mItem(new LLInventoryItem(item)) {}
};
@ -88,6 +92,7 @@ LLFloaterScriptQueue::LLFloaterScriptQueue(const LLSD& key) :
mDone(false),
mMono(false)
{
}
// Destroys the object
@ -190,7 +195,7 @@ bool LLFloaterScriptQueue::onScriptModifyConfirmation(const LLSD& notification,
getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
return nextObject();
return startQueue();
}
BOOL LLFloaterScriptQueue::isDone() const
@ -255,6 +260,40 @@ BOOL LLFloaterScriptQueue::popNext()
return rv;
}
BOOL LLFloaterScriptQueue::startQueue()
{
return nextObject();
}
class CompileQueueExperienceResponder : public LLHTTPClient::Responder
{
public:
CompileQueueExperienceResponder(const LLUUID& parent):mParent(parent)
{
}
LLUUID mParent;
/*virtual*/ void httpSuccess()
{
sendResult(getContent());
}
/*virtual*/ void httpFailure()
{
sendResult(LLSD());
}
void sendResult(const LLSD& content)
{
LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", mParent);
if(!queue)
return;
queue->experienceIdsReceived(content["experience_ids"]);
}
};
///----------------------------------------------------------------------------
/// Class LLFloaterCompileQueue
@ -307,6 +346,21 @@ LLFloaterCompileQueue::~LLFloaterCompileQueue()
{
}
void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content )
{
for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it)
{
mExperienceIds.insert(it->asUUID());
}
nextObject();
}
BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
{
return mExperienceIds.find(id) != mExperienceIds.end();
}
void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
LLInventoryObject::object_list_t* inv)
{
@ -347,25 +401,52 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
{
LLInventoryItem *itemp = iter->second;
LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(),
itemp->getName(),
viewer_object->getID(),
itemp->getUUID());
viewer_object->getID(), itemp);
//LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL;
gAssetStorage->getInvItemAsset(viewer_object->getRegion()->getHost(),
gAgent.getID(),
gAgent.getSessionID(),
itemp->getPermissions().getOwner(),
viewer_object->getID(),
itemp->getUUID(),
itemp->getAssetUUID(),
itemp->getType(),
LLFloaterCompileQueue::scriptArrived,
(void*)datap);
ExperienceAssociationResponder::fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1));
}
}
}
void LLFloaterCompileQueue::requestAsset( LLScriptQueueData* datap, const LLSD& experience )
{
LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance<LLFloaterCompileQueue>("compile_queue", datap->mQueueID);
if(!queue)
{
delete datap;
return;
}
if(experience.has(LLExperienceCache::EXPERIENCE_ID))
{
datap->mExperienceId=experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
if(!queue->hasExperience(datap->mExperienceId))
{
std::string buffer = LLTrans::getString("CompileNoExperiencePerm", LLSD::emptyMap()
.with("SCRIPT", datap->mItem->getName())
.with("EXPERIENCE", experience[LLExperienceCache::NAME].asString()));
queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
queue->removeItemByItemID(datap->mItem->getUUID());
delete datap;
return;
}
}
//LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL;
gAssetStorage->getInvItemAsset(datap->mHost,
gAgent.getID(),
gAgent.getSessionID(),
datap->mItem->getPermissions().getOwner(),
datap->mTaskId,
datap->mItem->getUUID(),
datap->mItem->getAssetUUID(),
datap->mItem->getType(),
LLFloaterCompileQueue::scriptArrived,
(void*)datap);
}
// This is the callback for when each script arrives
// static
void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
@ -405,12 +486,12 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
file.read(script_data, script_size);
queue->mUploadQueue->queue(filename, data->mTaskId,
data->mItemId, is_running, queue->mMono, queue->getKey().asUUID(),
script_data, script_size, data->mScriptName);
data->mItem->getUUID(), is_running, queue->mMono, queue->getKey().asUUID(),
script_data, script_size, data->mItem->getName(), data->mExperienceId);
}
else
{
buffer = LLTrans::getString("CompileQueueServiceUnavailable") + (": ") + data->mScriptName;
buffer = LLTrans::getString("CompileQueueServiceUnavailable") + (": ") + data->mItem->getName();
}
}
}
@ -422,7 +503,7 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
args["MESSAGE"] = LLTrans::getString("CompileQueueScriptNotFound");
LLNotificationsUtil::add("SystemMessage", args);
buffer = LLTrans::getString("CompileQueueProblemDownloading") + (": ") + data->mScriptName;
buffer = LLTrans::getString("CompileQueueProblemDownloading") + (": ") + data->mItem->getName();
}
else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
{
@ -430,15 +511,15 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
args["MESSAGE"] = LLTrans::getString("CompileQueueInsufficientPermDownload");
LLNotificationsUtil::add("SystemMessage", args);
buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + (": ") + data->mScriptName;
buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + (": ") + data->mItem->getName();
}
else
{
buffer = LLTrans::getString("CompileQueueUnknownFailure") + (" ") + data->mScriptName;
buffer = LLTrans::getString("CompileQueueUnknownFailure") + (" ") + data->mItem->getName();
}
LL_WARNS() << "Problem downloading script asset." << LL_ENDL;
if(queue) queue->removeItemByItemID(data->mItemId);
if(queue) queue->removeItemByItemID(data->mItem->getUUID());
}
if(queue && (buffer.size() > 0))
{
@ -586,6 +667,23 @@ void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id)
}
}
BOOL LLFloaterCompileQueue::startQueue()
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
{
LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(getKey().asUUID()));
return TRUE;
}
}
return nextObject();
}
void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t* inv)
{

View File

@ -83,13 +83,15 @@ protected:
// returns true if this is done
BOOL isDone() const;
virtual BOOL startQueue();
// go to the next object. If no objects left, it falls out
// silently and waits to be killed by the deleteIfDone() callback.
BOOL nextObject();
BOOL popNext();
void setStartString(const std::string& s) { mStartString = s; }
protected:
// UI
LLScrollListCtrl* mMessages;
@ -133,6 +135,9 @@ public:
LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; }
void experienceIdsReceived( const LLSD& content );
BOOL hasExperience(const LLUUID& id)const;
protected:
LLFloaterCompileQueue(const LLSD& key);
virtual ~LLFloaterCompileQueue();
@ -141,16 +146,21 @@ protected:
virtual void handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t* inv);
static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience);
// This is the callback for when each script arrives
static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
LLAssetType::EType type,
void* user_data, S32 status, LLExtStat ext_status);
virtual BOOL startQueue();
protected:
LLViewerInventoryItem::item_array_t mCurrentScripts;
private:
LLAssetUploadQueue* mUploadQueue;
uuid_list_t mExperienceIds;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -116,7 +116,7 @@ LLExpandableTextBox::LLTextBoxEx::LLTextBoxEx(const Params& p)
mExpanderVisible(false)
{
setIsChrome(TRUE);
setMaxTextLength(p.max_text_length);
}
void LLExpandableTextBox::LLTextBoxEx::reshape(S32 width, S32 height, BOOL called_from_parent)

View File

@ -103,7 +103,7 @@ public:
Optional<LLScrollContainer::Params> scroll;
Optional<S32> max_height;
Optional<bool> bg_visible,
expanded_bg_visible;

View File

@ -0,0 +1,97 @@
/**
* @file llexperienceassociationresponder.cpp
* @brief llexperienceassociationresponder implementation. This class combines
* a lookup for a script association and an experience details request. The first
* is always async, but the second may be cached locally.
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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 "llviewerprecompiledheaders.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "llviewerregion.h"
#include "llagent.h"
ExperienceAssociationResponder::ExperienceAssociationResponder(ExperienceAssociationResponder::callback_t callback):mCallback(callback)
{
ref();
}
void ExperienceAssociationResponder::fetchAssociatedExperience( const LLUUID& object_id, const LLUUID& item_id, callback_t callback )
{
LLSD request;
request["object-id"]=object_id;
request["item-id"]=item_id;
fetchAssociatedExperience(request, callback);
}
void ExperienceAssociationResponder::fetchAssociatedExperience(LLSD& request, callback_t callback)
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetMetadata");
if(!lookup_url.empty())
{
LLSD fields;
fields.append("experience");
request["fields"] = fields;
LLHTTPClient::post(lookup_url, request, new ExperienceAssociationResponder(callback));
}
}
}
void ExperienceAssociationResponder::httpFailure()
{
LLSD msg;
msg["error"]=(LLSD::Integer)getStatus();
msg["message"]=getReason();
LL_INFOS("ExperienceAssociation") << "Failed to look up associated experience: " << getStatus() << ": " << getReason() << LL_ENDL;
sendResult(msg);
}
void ExperienceAssociationResponder::httpSuccess()
{
if(!getContent().has("experience"))
{
LLSD msg;
msg["message"]="no experience";
msg["error"]=-1;
sendResult(msg);
return;
}
LLExperienceCache::get(getContent()["experience"].asUUID(), boost::bind(&ExperienceAssociationResponder::sendResult, this, _1));
}
void ExperienceAssociationResponder::sendResult( const LLSD& experience )
{
mCallback(experience);
unref();
}

View File

@ -0,0 +1,58 @@
#include "llhttpclient.h"
#include "llsd.h"
/**
* @file llexperienceassociationresponder.h
* @brief llexperienceassociationresponder and related class definitions
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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_LLEXPERIENCEASSOCIATIONRESPONDER_H
#define LL_LLEXPERIENCEASSOCIATIONRESPONDER_H
#include "llhttpclient.h"
#include "llsd.h"
class ExperienceAssociationResponder : public LLHTTPClient::Responder
{
public:
typedef boost::function<void(const LLSD& experience)> callback_t;
ExperienceAssociationResponder(callback_t callback);
/*virtual*/ void httpSuccess();
/*virtual*/ void httpFailure();
static void fetchAssociatedExperience(const LLUUID& object_it, const LLUUID& item_id, callback_t callback);
private:
static void fetchAssociatedExperience(LLSD& request, callback_t callback);
void sendResult(const LLSD& experience);
callback_t mCallback;
};
#endif // LL_LLEXPERIENCEASSOCIATIONRESPONDER_H

View File

@ -0,0 +1,273 @@
/**
* @file llexperiencelog.cpp
* @brief llexperiencelog implementation
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llviewerprecompiledheaders.h"
#include "llexperiencelog.h"
#include "lldispatcher.h"
#include "llsdserialize.h"
#include "llviewergenericmessage.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llerror.h"
#include "lldate.h"
class LLExperienceLogDispatchHandler : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
LLSD message;
sparam_t::const_iterator it = strings.begin();
if(it != strings.end()){
const std::string& llsdRaw = *it++;
std::istringstream llsdData(llsdRaw);
if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
{
LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
}
}
message["public_id"] = invoice;
// Object Name
if(it != strings.end())
{
message["ObjectName"] = *it++;
}
// parcel Name
if(it != strings.end())
{
message["ParcelName"] = *it++;
}
message["Count"] = 1;
LLExperienceLog::instance().handleExperienceMessage(message);
return true;
}
};
static LLExperienceLogDispatchHandler experience_log_dispatch_handler;
void LLExperienceLog::handleExperienceMessage(LLSD& message)
{
time_t now;
time(&now);
char daybuf[16];/* Flawfinder: ignore */
char time_of_day[16];/* Flawfinder: ignore */
strftime(daybuf, 16, "%Y-%m-%d", localtime(&now));
strftime(time_of_day, 16, " %H:%M:%S", localtime(&now));
message["Time"] = time_of_day;
std::string day = daybuf;
if(!mEvents.has(day))
{
mEvents[day] = LLSD::emptyArray();
}
LLSD& dayEvents = mEvents[day];
if(dayEvents.size() > 0)
{
LLSD& last = *(dayEvents.rbeginArray());
if( last["public_id"].asUUID() == message["public_id"].asUUID()
&& last["ObjectName"].asString() == message["ObjectName"].asString()
&& last["OwnerID"].asUUID() == message["OwnerID"].asUUID()
&& last["ParcelName"].asString() == message["ParcelName"].asString()
&& last["Permission"].asInteger() == message["Permission"].asInteger())
{
last["Count"] = last["Count"].asInteger() + 1;
last["Time"] = time_of_day;
mSignals(last);
return;
}
}
message["Time"] = time_of_day;
mEvents[day].append(message);
mSignals(message);
}
LLExperienceLog::LLExperienceLog()
: mMaxDays(7)
, mPageSize(25)
, mNotifyNewEvent(false)
{
}
void LLExperienceLog::initialize()
{
loadEvents();
if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent"))
{
gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler);
}
}
std::string LLExperienceLog::getFilename()
{
return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml");
}
std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base )
{
std::ostringstream buf;
if(message.has("Permission"))
{
buf << base << message["Permission"].asInteger();
std::string entry;
if(LLTrans::findString(entry, buf.str()))
{
buf.str(entry);
}
else
{
buf.str();
}
}
if(buf.str().empty())
{
buf << base << "Unknown";
buf.str(LLTrans::getString(buf.str(), message));
}
return buf.str();
}
void LLExperienceLog::notify( LLSD& message )
{
message["EventType"] = getPermissionString(message, "ExperiencePermission");
if(message.has("IsAttachment") && message["IsAttachment"].asBoolean())
{
LLNotificationsUtil::add("ExperienceEventAttachment", message);
}
else
{
LLNotificationsUtil::add("ExperienceEvent", message);
}
message.erase("EventType");
}
void LLExperienceLog::saveEvents()
{
eraseExpired();
std::string filename = getFilename();
LLSD settings = LLSD::emptyMap().with("Events", mEvents);
settings["MaxDays"] = (int)mMaxDays;
settings["Notify"] = mNotifyNewEvent;
settings["PageSize"] = (int)mPageSize;
llofstream stream(filename.c_str());
LLSDSerialize::toPrettyXML(settings, stream);
}
void LLExperienceLog::loadEvents()
{
LLSD settings = LLSD::emptyMap();
std::string filename = getFilename();
llifstream stream(filename.c_str());
LLSDSerialize::fromXMLDocument(settings, stream);
if(settings.has("MaxDays"))
{
setMaxDays((U32)settings["MaxDays"].asInteger());
}
if(settings.has("Notify"))
{
setNotifyNewEvent(settings["Notify"].asBoolean());
}
if(settings.has("PageSize"))
{
setPageSize((U32)settings["PageSize"].asInteger());
}
mEvents.clear();
if(mMaxDays > 0 && settings.has("Events"))
{
mEvents = settings["Events"];
}
eraseExpired();
}
LLExperienceLog::~LLExperienceLog()
{
saveEvents();
}
void LLExperienceLog::eraseExpired()
{
while(mEvents.size() > mMaxDays && mMaxDays > 0)
{
mEvents.erase(mEvents.beginMap()->first);
}
}
const LLSD& LLExperienceLog::getEvents() const
{
return mEvents;
}
void LLExperienceLog::clear()
{
mEvents.clear();
}
void LLExperienceLog::setMaxDays( U32 val )
{
mMaxDays = val;
if(mMaxDays > 0)
{
eraseExpired();
}
}
LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb )
{
return mSignals.connect(cb);
}
void LLExperienceLog::setNotifyNewEvent( bool val )
{
mNotifyNewEvent = val;
if(!val && mNotifyConnection.connected())
{
mNotifyConnection.disconnect();
}
else if( val && !mNotifyConnection.connected())
{
mNotifyConnection = addUpdateSignal(boost::function<void(LLSD&)>(LLExperienceLog::notify));
}
}

View File

@ -0,0 +1,85 @@
/**
* @file llexperiencelog.h
* @brief llexperiencelog and related class definitions
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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_LLEXPERIENCELOG_H
#define LL_LLEXPERIENCELOG_H
#include "llsingleton.h"
class LLExperienceLog : public LLSingleton<LLExperienceLog>
{
public:
typedef boost::signals2::signal<void(LLSD&)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
callback_connection_t addUpdateSignal(const callback_slot_t& cb);
void initialize();
U32 getMaxDays() const { return mMaxDays; }
void setMaxDays(U32 val);
bool getNotifyNewEvent() const { return mNotifyNewEvent; }
void setNotifyNewEvent(bool val);
U32 getPageSize() const { return mPageSize; }
void setPageSize(U32 val) { mPageSize = val; }
const LLSD& getEvents()const;
void clear();
virtual ~LLExperienceLog();
static void notify(LLSD& message);
static std::string getFilename();
static std::string getPermissionString(const LLSD& message, const std::string& base);
protected:
LLExperienceLog();
void handleExperienceMessage(LLSD& message);
void loadEvents();
void saveEvents();
void eraseExpired();
LLSD mEvents;
callback_signal_t mSignals;
callback_connection_t mNotifyConnection;
U32 mMaxDays;
U32 mPageSize;
bool mNotifyNewEvent;
friend class LLExperienceLogDispatchHandler;
friend class LLSingleton<LLExperienceLog>;
};
#endif // LL_LLEXPERIENCELOG_H

View File

@ -381,13 +381,16 @@ void LLFloaterAuction::doResetParcel()
msg->sendReliable(region->getHost());
// Clear the access lists
clearParcelAccessLists(parcelp, region);
clearParcelAccessList(parcelp, region, AL_ACCESS);
clearParcelAccessList(parcelp, region, AL_BAN);
clearParcelAccessList(parcelp, region, AL_ALLOW_EXPERIENCE);
clearParcelAccessList(parcelp, region, AL_BLOCK_EXPERIENCE);
}
}
void LLFloaterAuction::clearParcelAccessLists(LLParcel* parcel, LLViewerRegion* region)
void LLFloaterAuction::clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list)
{
if (!region || !parcel) return;
@ -396,15 +399,12 @@ void LLFloaterAuction::clearParcelAccessLists(LLParcel* parcel, LLViewerRegion*
LLMessageSystem* msg = gMessageSystem;
// Clear access list
// parcel->mAccessList.clear();
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, AL_ACCESS);
msg->addU32Fast(_PREHASH_Flags, list);
msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, 1); // sequence_id
@ -417,27 +417,6 @@ void LLFloaterAuction::clearParcelAccessLists(LLParcel* parcel, LLViewerRegion*
msg->addU32Fast(_PREHASH_Flags, 0 );
msg->sendReliable( region->getHost() );
// Send message for empty ban list
//parcel->mBanList.clear();
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, AL_BAN);
msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, 1); // sequence_id
msg->addS32Fast(_PREHASH_Sections, 0); // num_sections
// pack an empty block since there will be no data
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
msg->addS32Fast(_PREHASH_Time, 0 );
msg->addU32Fast(_PREHASH_Flags, 0 );
msg->sendReliable( region->getHost() );
}

View File

@ -67,7 +67,7 @@ private:
void doResetParcel();
void doSellToAnyone();
void clearParcelAccessLists( LLParcel* parcel, LLViewerRegion* region );
void clearParcelAccessList( LLParcel* parcel, LLViewerRegion* region, U32 list);
void cleanupAndClose();
private:

View File

@ -0,0 +1,162 @@
/**
* @file llfloaterexperiencepicker.cpp
* @brief Implementation of llfloaterexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llviewerprecompiledheaders.h"
#include "llfloaterexperiencepicker.h"
#include "lllineeditor.h"
#include "llfloaterreg.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "llexperiencecache.h"
#include "llslurl.h"
#include "llavatarnamecache.h"
#include "llfloaterexperienceprofile.h"
#include "llcombobox.h"
#include "llviewercontrol.h"
#include "lldraghandle.h"
#include "llpanelexperiencepicker.h"
LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin )
{
LLFloaterExperiencePicker* floater =
LLFloaterReg::showTypedInstance<LLFloaterExperiencePicker>("experience_search", key);
if (!floater)
{
LL_WARNS() << "Cannot instantiate experience picker" << LL_ENDL;
return NULL;
}
if (floater->mSearchPanel)
{
floater->mSearchPanel->mSelectionCallback = callback;
floater->mSearchPanel->mCloseOnSelect = close_on_select;
floater->mSearchPanel->setAllowMultiple(allow_multiple);
floater->mSearchPanel->setDefaultFilters();
floater->mSearchPanel->addFilters(filters.begin(), filters.end());
floater->mSearchPanel->filterContent();
}
if(frustumOrigin)
{
floater->mFrustumOrigin = frustumOrigin->getHandle();
}
return floater;
}
void LLFloaterExperiencePicker::drawFrustum()
{
if(mFrustumOrigin.get())
{
LLView * frustumOrigin = mFrustumOrigin.get();
LLRect origin_rect;
frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
// draw context cone connecting color picker with color swatch in parent floater
LLRect local_rect = getLocalRect();
if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLGLEnable(GL_CULL_FACE);
gGL.begin(LLRender::QUADS);
{
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mRight, local_rect.mTop);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.vertex2i(local_rect.mRight, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
}
gGL.end();
}
if (gFocusMgr.childHasMouseCapture(getDragHandle()))
{
mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
}
else
{
mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
}
}
}
void LLFloaterExperiencePicker::draw()
{
drawFrustum();
LLFloater::draw();
}
LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
:LLFloater(key)
,mSearchPanel(NULL)
,mContextConeOpacity(0.f)
,mContextConeInAlpha(0.f)
,mContextConeOutAlpha(0.f)
,mContextConeFadeTime(0.f)
{
mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
{
gFocusMgr.releaseFocusIfNeeded( this );
}
BOOL LLFloaterExperiencePicker::postBuild()
{
mSearchPanel = new LLPanelExperiencePicker();
addChild(mSearchPanel);
mSearchPanel->setOrigin(0, 0);
return LLFloater::postBuild();
}

View File

@ -0,0 +1,67 @@
/**
* @file llfloaterexperiencepicker.h
* @brief Header file for llfloaterexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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_LLFLOATEREXPERIENCEPICKER_H
#define LL_LLFLOATEREXPERIENCEPICKER_H
#include "llfloater.h"
class LLScrollListCtrl;
class LLLineEditor;
class LLPanelExperiencePicker;
class LLFloaterExperiencePicker : public LLFloater
{
public:
typedef boost::function<void (const uuid_vec_t&)> select_callback_t;
// filter function for experiences, return true if the experience should be hidden.
typedef boost::function<bool (const LLSD&)> filter_function;
typedef std::vector<filter_function> filter_list;
static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin);
LLFloaterExperiencePicker(const LLSD& key);
virtual ~LLFloaterExperiencePicker();
BOOL postBuild();
virtual void draw();
private:
LLPanelExperiencePicker* mSearchPanel;
void drawFrustum();
LLHandle <LLView> mFrustumOrigin;
F32 mContextConeOpacity;
F32 mContextConeInAlpha;
F32 mContextConeOutAlpha;
F32 mContextConeFadeTime;
};
#endif // LL_LLFLOATEREXPERIENCEPICKER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
/**
* @file llfloaterexperienceprofile.h
* @brief llfloaterexperienceprofile and related class definitions
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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_LLFLOATEREXPERIENCEPROFILE_H
#define LL_LLFLOATEREXPERIENCEPROFILE_H
#include "llfloater.h"
#include "lluuid.h"
#include "llsd.h"
class LLLayoutPanel;
class LLTextBox;
class LLComboBox;
class LLFloaterExperienceProfile : public LLFloater
{
LOG_CLASS(LLFloaterExperienceProfile);
public:
enum PostSaveAction
{
NOTHING,
CLOSE,
VIEW,
};
LLFloaterExperienceProfile(const LLSD& data);
virtual ~LLFloaterExperienceProfile();
LLUUID getExperienceId() const { return mExperienceId; }
void setPreferences( const LLSD& content );
void refreshExperience(const LLSD& experience);
void onSaveComplete( const LLSD& content );
virtual BOOL canClose();
virtual void onClose(bool app_quitting);
protected:
void onClickEdit();
void onClickPermission(const char* permission);
void onClickForget();
void onClickCancel();
void onClickSave();
void onClickLocation();
void onClickClear();
void onPickGroup();
void onFieldChanged();
void onReportExperience();
void setEditGroup(LLUUID group_id);
void changeToView();
void experienceForgotten();
void experienceBlocked();
void experienceAllowed();
static void experienceCallback(LLHandle<LLFloaterExperienceProfile> handle, const LLSD& experience);
static bool experiencePermission(LLHandle<LLFloaterExperienceProfile> handle, const LLSD& permission);
BOOL postBuild();
bool setMaturityString(U8 maturity, LLTextBox* child, LLComboBox* combo);
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response, PostSaveAction action);
void doSave( int success_action );
void updatePackage();
void updatePermission( const LLSD& permission );
LLUUID mExperienceId;
LLSD mExperienceDetails;
LLSD mPackage;
std::string mLocationSLURL;
int mSaveCompleteAction;
bool mDirty;
bool mForceClose;
};
#endif // LL_LLFLOATEREXPERIENCEPROFILE_H

View File

@ -0,0 +1,340 @@
/**
* @file llfloaterexperiences.cpp
* @brief LLFloaterExperiences class implementation
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "llviewerprecompiledheaders.h"
#include "llfloaterexperiences.h"
#include "llfloaterreg.h"
#include "llagent.h"
#include "llevents.h"
#include "llexperiencecache.h"
#include "llfloaterregioninfo.h"
#include "llhttpclient.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
#include "llpanelexperiencepicker.h"
#include "llpanelexperiences.h"
#include "lltabcontainer.h"
#include "lltrans.h"
#include "llviewerregion.h"
#define SHOW_RECENT_TAB (0)
class LLExperienceListResponder : public LLHTTPClient::Responder
{
public:
typedef std::map<std::string, std::string> NameMap;
typedef boost::function<void(LLPanelExperiences*, const LLSD&)> Callback;
LLExperienceListResponder(const LLHandle<LLFloaterExperiences>& parent, NameMap& nameMap, const std::string& errorMessage="ErrorMessage"):mParent(parent),mErrorMessage(errorMessage)
{
mNameMap.swap(nameMap);
}
Callback mCallback;
LLHandle<LLFloaterExperiences> mParent;
NameMap mNameMap;
const std::string mErrorMessage;
/*virtual*/ void httpSuccess()
{
if(mParent.isDead())
return;
LLFloaterExperiences* parent=mParent.get();
LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs");
NameMap::iterator it = mNameMap.begin();
while(it != mNameMap.end())
{
if(getContent().has(it->first))
{
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it->second);
if(tab)
{
const LLSD& ids = getContent()[it->first];
tab->setExperienceList(ids);
if(!mCallback.empty())
{
mCallback(tab, getContent());
}
}
}
++it;
}
}
/*virtual*/ void httpFailure()
{
LLSD subs;
subs["ERROR_MESSAGE"] = getReason();
LLNotificationsUtil::add(mErrorMessage, subs);
}
};
LLFloaterExperiences::LLFloaterExperiences(const LLSD& data)
:LLFloater(data)
{
}
LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name, bool select)
{
LLPanelExperiences* newPanel = LLPanelExperiences::create(name);
getChild<LLTabContainer>("xp_tabs")->addTabPanel(LLTabContainer::TabPanelParams().
panel(newPanel).
label(LLTrans::getString(name)).
select_tab(select));
return newPanel;
}
BOOL LLFloaterExperiences::postBuild()
{
getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperiencePicker());
addTab("Allowed_Experiences_Tab", true);
addTab("Blocked_Experiences_Tab", false);
addTab("Admin_Experiences_Tab", false);
addTab("Contrib_Experiences_Tab", false);
LLPanelExperiences* owned = addTab("Owned_Experiences_Tab", false);
owned->setButtonAction("acquire", boost::bind(&LLFloaterExperiences::sendPurchaseRequest, this));
owned->enableButton(false);
#if SHOW_RECENT_TAB
addTab("Recent_Experiences_Tab", false);
#endif //SHOW_RECENT_TAB
getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperienceLog());
resizeToTabs();
LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences",
boost::bind(&LLFloaterExperiences::updatePermissions, this, _1));
return TRUE;
}
void LLFloaterExperiences::clearFromRecent(const LLSD& ids)
{
#if SHOW_RECENT_TAB
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab");
if(!tab)
return;
tab->removeExperiences(ids);
#endif // SHOW_RECENT_TAB
}
void LLFloaterExperiences::setupRecentTabs()
{
#if SHOW_RECENT_TAB
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab");
if(!tab)
return;
LLSD recent;
const LLExperienceCache::cache_t& experiences = LLExperienceCache::getCached();
LLExperienceCache::cache_t::const_iterator it = experiences.begin();
while( it != experiences.end() )
{
if(!it->second.has(LLExperienceCache::MISSING))
{
recent.append(it->first);
}
++it;
}
tab->setExperienceList(recent);
#endif // SHOW_RECENT_TAB
}
void LLFloaterExperiences::resizeToTabs()
{
const S32 TAB_WIDTH_PADDING = 16;
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLRect rect = getRect();
if(rect.getWidth() < tabs->getTotalTabWidth() + TAB_WIDTH_PADDING)
{
rect.mRight = rect.mLeft + tabs->getTotalTabWidth() + TAB_WIDTH_PADDING;
}
reshape(rect.getWidth(), rect.getHeight(), FALSE);
}
void LLFloaterExperiences::refreshContents()
{
setupRecentTabs();
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
LLExperienceListResponder::NameMap nameMap;
std::string lookup_url=region->getCapability("GetExperiences");
if(!lookup_url.empty())
{
nameMap["experiences"]="Allowed_Experiences_Tab";
nameMap["blocked"]="Blocked_Experiences_Tab";
LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap));
}
updateInfo("GetAdminExperiences","Admin_Experiences_Tab");
updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
lookup_url = region->getCapability("AgentExperiences");
if(!lookup_url.empty())
{
nameMap["experience_ids"]="Owned_Experiences_Tab";
LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed");
responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2);
LLHTTPClient::get(lookup_url, responder);
}
}
}
void LLFloaterExperiences::onOpen( const LLSD& key )
{
LLViewerRegion* region = gAgent.getRegion();
if(region)
{
if(region->capabilitiesReceived())
{
refreshContents();
return;
}
region->setCapabilitiesReceivedCallback(boost::bind(&LLFloaterExperiences::refreshContents, this));
return;
}
}
bool LLFloaterExperiences::updatePermissions( const LLSD& permission )
{
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLUUID experience;
std::string permission_string;
if(permission.has("experience"))
{
experience = permission["experience"].asUUID();
permission_string = permission[experience.asString()]["permission"].asString();
}
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Allowed_Experiences_Tab");
if(tab)
{
if(permission.has("experiences"))
{
tab->setExperienceList(permission["experiences"]);
}
else if(experience.notNull())
{
if(permission_string != "Allow")
{
tab->removeExperience(experience);
}
else
{
tab->addExperience(experience);
}
}
}
tab = (LLPanelExperiences*)tabs->getPanelByName("Blocked_Experiences_Tab");
if(tab)
{
if(permission.has("blocked"))
{
tab->setExperienceList(permission["blocked"]);
}
else if(experience.notNull())
{
if(permission_string != "Block")
{
tab->removeExperience(experience);
}
else
{
tab->addExperience(experience);
}
}
}
return false;
}
void LLFloaterExperiences::onClose( bool app_quitting )
{
LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences");
LLFloater::onClose(app_quitting);
}
void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content) const
{
panel->enableButton(content.has("purchase"));
LLFloaterExperiences::findInstance()->updateInfo("GetAdminExperiences","Admin_Experiences_Tab");
LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
}
void LLFloaterExperiences::updateInfo(std::string experiences, std::string tab)
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
LLExperienceListResponder::NameMap nameMap;
std::string lookup_url = region->getCapability(experiences);
if(!lookup_url.empty())
{
nameMap["experience_ids"]=tab;
LLHTTPClient::get(lookup_url, new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap));
}
}
}
void LLFloaterExperiences::sendPurchaseRequest() const
{
LLViewerRegion* region = gAgent.getRegion();
std::string url = region->getCapability("AgentExperiences");
if(!url.empty())
{
LLSD content;
LLExperienceListResponder::NameMap nameMap;
nameMap["experience_ids"]="Owned_Experiences_Tab";
LLExperienceListResponder* responder = new LLExperienceListResponder(getDerivedHandle<LLFloaterExperiences>(), nameMap, "ExperienceAcquireFailed");
responder->mCallback = boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2);
LLHTTPClient::post(url, content, responder);
}
}
LLFloaterExperiences* LLFloaterExperiences::findInstance()
{
return LLFloaterReg::findTypedInstance<LLFloaterExperiences>("experiences");
}

View File

@ -0,0 +1,60 @@
/**
* @file llfloaterexperiences.h
* @brief LLFloaterExperiences class definition
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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_LLFLOATEREXPERIENCES_H
#define LL_LLFLOATEREXPERIENCES_H
#include "llfloater.h"
class LLPanelExperiences;
class LLFloaterExperiences :
public LLFloater
{
public:
LLFloaterExperiences(const LLSD& data);
virtual void onClose(bool app_quitting);
virtual void onOpen(const LLSD& key);
static LLFloaterExperiences* findInstance();
protected:
void clearFromRecent(const LLSD& ids);
void resizeToTabs();
/*virtual*/ BOOL postBuild();
void refreshContents();
void setupRecentTabs();
LLPanelExperiences* addTab(const std::string& name, bool select);
bool updatePermissions(const LLSD& permission);
void sendPurchaseRequest() const;
void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const;
void updateInfo(std::string experiences, std::string tab);
private:
};
#endif //LL_LLFLOATEREXPERIENCES_H

View File

@ -75,6 +75,9 @@
#include "llviewercontrol.h"
#include "roles_constants.h"
#include "lltrans.h"
#include "llpanelexperiencelisteditor.h"
#include "llpanelexperiencepicker.h"
#include "llexperiencecache.h"
#include "llgroupactions.h"
#include "llsdutil_math.h"
@ -121,6 +124,28 @@ public:
}
};
class LLPanelLandExperiences
: public LLPanel
{
public:
LLPanelLandExperiences(LLSafeHandle<LLParcelSelection>& parcelp);
virtual BOOL postBuild();
void refresh();
void experienceAdded(const LLUUID& id, U32 xp_type, U32 access_type);
void experienceRemoved(const LLUUID& id, U32 access_type);
protected:
LLPanelExperienceListEditor* setupList( const char* control_name, U32 xp_type, U32 access_type );
void refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type);
LLSafeHandle<LLParcelSelection>& mParcel;
LLPanelExperienceListEditor* mAllowed;
LLPanelExperienceListEditor* mBlocked;
};
// inserts maturity info(icon and text) into target textbox
// names_floater - pointer to floater which contains strings with maturity icons filenames
// str_to_parse is string in format "txt1[MATURITY]txt2" where maturity icon and text will be inserted instead of [MATURITY]
@ -259,6 +284,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed)
mFactoryMap["land_audio_panel"] = LLCallbackMap(createPanelLandAudio, this);
mFactoryMap["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this);
mFactoryMap["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this);
mFactoryMap["land_experiences_panel"] = LLCallbackMap(createPanelLandExperiences, this);
sObserver = new LLParcelSelectionObserver();
LLViewerParcelMgr::getInstance()->addObserver( sObserver );
@ -299,6 +325,7 @@ void LLFloaterLand::refresh()
mPanelMedia->refresh();
mPanelAccess->refresh();
mPanelCovenant->refresh();
mPanelExperiences->refresh();
}
@ -359,6 +386,15 @@ void* LLFloaterLand::createPanelLandAccess(void* data)
return self->mPanelAccess;
}
// static
void* LLFloaterLand::createPanelLandExperiences(void* data)
{
LLFloaterLand* self = (LLFloaterLand*)data;
self->mPanelExperiences = new LLPanelLandExperiences(self->mParcel);
return self->mPanelExperiences;
}
//---------------------------------------------------------------------------
// LLPanelLandGeneral
//---------------------------------------------------------------------------
@ -2136,7 +2172,7 @@ void LLPanelLandOptions::refresh()
else
{
// something selected, hooray!
LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion();
//LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); // <FS:LO> FIRE-16112 fix
// Display options
BOOL can_change_options = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS);
@ -2152,7 +2188,7 @@ void LLPanelLandOptions::refresh()
mCheckGroupObjectEntry ->set( parcel->getAllowGroupObjectEntry() || parcel->getAllowAllObjectEntry());
mCheckGroupObjectEntry ->setEnabled( can_change_options && !parcel->getAllowAllObjectEntry() );
BOOL region_damage = regionp ? regionp->getAllowDamage() : FALSE;
//BOOL region_damage = regionp ? regionp->getAllowDamage() : FALSE; // <FS:LO> FIRE-16112 fix
// <FS:WF> FIRE-6604 : Reinstate the "Allow Other Residents to Edit Terrain" option in About Land
BOOL can_change_terraform = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_EDIT);
@ -2161,7 +2197,10 @@ void LLPanelLandOptions::refresh()
// <FS:WF>
mCheckSafe ->set( !parcel->getAllowDamage() );
mCheckSafe ->setEnabled( can_change_options && region_damage );
// <FS:LO> FIRE-16112 fix
//mCheckSafe ->setEnabled( can_change_options && region_damage );
mCheckSafe ->setEnabled( can_change_options );
// </FS:LO>
mCheckFly ->set( parcel->getAllowFly() );
mCheckFly ->setEnabled( can_change_options );
@ -2247,6 +2286,7 @@ void LLPanelLandOptions::refresh()
// they can see the checkbox, but its disposition depends on the
// state of the region
LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); // <FS:LO> FIRE-16112 fix
if (regionp)
{
if (regionp->getSimAccess() == SIM_ACCESS_PG)
@ -2627,7 +2667,7 @@ void LLPanelLandAccess::refresh()
getChild<LLUICtrl>("AllowedText")->setTextArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
// </FS:Ansariel>
for (access_map_const_iterator cit = parcel->mAccessList.begin();
for (LLAccessEntry::map::const_iterator cit = parcel->mAccessList.begin();
cit != parcel->mAccessList.end(); ++cit)
{
const LLAccessEntry& entry = (*cit).second;
@ -2677,7 +2717,7 @@ void LLPanelLandAccess::refresh()
getChild<LLUICtrl>("BanCheck")->setTextArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
// </FS:Ansariel>
for (access_map_const_iterator cit = parcel->mBanList.begin();
for (LLAccessEntry::map::const_iterator cit = parcel->mBanList.begin();
cit != parcel->mBanList.end(); ++cit)
{
const LLAccessEntry& entry = (*cit).second;
@ -3303,3 +3343,103 @@ void insert_maturity_into_textbox(LLTextBox* target_textbox, LLFloater* names_fl
target_textbox->appendText(LLViewerParcelMgr::getInstance()->getSelectionRegion()->getSimAccessString(), false);
target_textbox->appendText(text_after_rating, false);
}
LLPanelLandExperiences::LLPanelLandExperiences( LLSafeHandle<LLParcelSelection>& parcelp )
: mParcel(parcelp)
{
}
BOOL LLPanelLandExperiences::postBuild()
{
mAllowed = setupList("panel_allowed", EXPERIENCE_KEY_TYPE_ALLOWED, AL_ALLOW_EXPERIENCE);
mBlocked = setupList("panel_blocked", EXPERIENCE_KEY_TYPE_BLOCKED, AL_BLOCK_EXPERIENCE);
// only non-grid-wide experiences
mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID));
// no privileged ones
mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithoutProperties, _1, LLExperienceCache::PROPERTY_PRIVILEGED|LLExperienceCache::PROPERTY_GRID));
getChild<LLLayoutPanel>("trusted_layout_panel")->setVisible(FALSE);
getChild<LLTextBox>("experiences_help_text")->setVisible(FALSE);
getChild<LLTextBox>("allowed_text_help")->setText(getString("allowed_parcel_text"));
getChild<LLTextBox>("blocked_text_help")->setText(getString("blocked_parcel_text"));
return LLPanel::postBuild();
}
LLPanelExperienceListEditor* LLPanelLandExperiences::setupList( const char* control_name, U32 xp_type, U32 access_type )
{
LLPanelExperienceListEditor* child = findChild<LLPanelExperienceListEditor>(control_name);
if(child)
{
child->getChild<LLTextBox>("text_name")->setText(child->getString(control_name));
child->setMaxExperienceIDs(PARCEL_MAX_EXPERIENCE_LIST);
child->setAddedCallback(boost::bind(&LLPanelLandExperiences::experienceAdded, this, _1, xp_type, access_type));
child->setRemovedCallback(boost::bind(&LLPanelLandExperiences::experienceRemoved, this, _1, access_type));
}
return child;
}
void LLPanelLandExperiences::experienceAdded( const LLUUID& id, U32 xp_type, U32 access_type )
{
LLParcel* parcel = mParcel->getParcel();
if (parcel)
{
parcel->setExperienceKeyType(id, xp_type);
LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type);
refresh();
}
}
void LLPanelLandExperiences::experienceRemoved( const LLUUID& id, U32 access_type )
{
LLParcel* parcel = mParcel->getParcel();
if (parcel)
{
parcel->setExperienceKeyType(id, EXPERIENCE_KEY_TYPE_NONE);
LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type);
refresh();
}
}
void LLPanelLandExperiences::refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type)
{
LLParcel *parcel = mParcel->getParcel();
// Display options
if (panel == NULL)
{
return;
}
if (parcel == NULL)
{
// disable the panel
panel->setEnabled(FALSE);
panel->setExperienceIds(LLSD::emptyArray());
}
else
{
// enable the panel
panel->setEnabled(TRUE);
LLAccessEntry::map entries = parcel->getExperienceKeysByType(xp_type);
LLAccessEntry::map::iterator it = entries.begin();
LLSD ids = LLSD::emptyArray();
for (/**/; it != entries.end(); ++it)
{
ids.append(it->second.mID);
}
panel->setExperienceIds(ids);
panel->setReadonly(!LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS));
panel->refreshExperienceCounter();
}
}
void LLPanelLandExperiences::refresh()
{
refreshPanel(mAllowed, EXPERIENCE_KEY_TYPE_ALLOWED);
refreshPanel(mBlocked, EXPERIENCE_KEY_TYPE_BLOCKED);
}

View File

@ -67,6 +67,7 @@ class LLPanelLandBan;
class LLPanelLandRenters;
class LLPanelLandCovenant;
class LLParcel;
class LLPanelLandExperiences;
class LLFloaterLand
: public LLFloater
@ -102,6 +103,7 @@ protected:
static void* createPanelLandAudio(void* data);
static void* createPanelLandMedia(void* data);
static void* createPanelLandAccess(void* data);
static void* createPanelLandExperiences(void* data);
static void* createPanelLandBan(void* data);
@ -117,6 +119,7 @@ protected:
LLPanelLandMedia* mPanelMedia;
LLPanelLandAccess* mPanelAccess;
LLPanelLandCovenant* mPanelCovenant;
LLPanelLandExperiences* mPanelExperiences;
LLSafeHandle<LLParcelSelection> mParcel;

View File

@ -63,6 +63,9 @@
#include "rlvhandler.h"
// [/RLVa:KB]
#include "llviewernetwork.h" // <FS:CR> For OpenSim export perms
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "llslurl.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLPropertiesObserver
@ -265,6 +268,17 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
is_obj_modify = object->permOwnerModify();
}
// <FS:Ansariel> Experience info
if(item->getInventoryType() == LLInventoryType::IT_LSL)
{
getChildView("LabelItemExperienceTitle")->setVisible(TRUE);
LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience");
tb->setText(getString("loading_experience"));
tb->setVisible(TRUE);
ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLFloaterProperties::setAssociatedExperience, getDerivedHandle<LLFloaterProperties>(), _1));
}
// </FS:Ansariel>
//////////////////////
// ITEM NAME & DESC //
//////////////////////
@ -574,6 +588,29 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
}
}
// <FS:Ansariel> Experience info
void LLFloaterProperties::setAssociatedExperience( LLHandle<LLFloaterProperties> hInfo, const LLSD& experience )
{
LLFloaterProperties* info = hInfo.get();
if(info)
{
LLUUID id;
if(experience.has(LLExperienceCache::EXPERIENCE_ID))
{
id=experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
if(id.notNull())
{
info->getChild<LLTextBox>("LabelItemExperience")->setText(LLSLURL("experience", id, "profile").getSLURLString());
}
else
{
info->getChild<LLTextBox>("LabelItemExperience")->setText(LLTrans::getString("ExperienceNameNull"));
}
}
}
// </FS:Ansariel>
void LLFloaterProperties::onClickCreator()
{
LLInventoryItem* item = findItem();

View File

@ -75,6 +75,9 @@ protected:
void refreshFromItem(LLInventoryItem* item);
virtual void draw();
// <FS:Ansariel> Experience info
static void setAssociatedExperience( LLHandle<LLFloaterProperties> hInfo, const LLSD& experience );
protected:
// The item id of the inventory item in question.
LLUUID mItemID;

View File

@ -92,6 +92,11 @@
#include "llagentui.h"
#include "llmeshrepository.h"
#include "llfloaterregionrestarting.h"
#include "llpanelexperiencelisteditor.h"
#include <boost/function.hpp>
#include "llpanelexperiencepicker.h"
#include "llexperiencecache.h"
#include "llpanelexperiences.h"
// <FS:CR> Aurora Sim - Region Settings Console
#include "llviewernetwork.h"
@ -132,6 +137,18 @@ public:
const sparam_t& strings);
};
class LLDispatchSetEstateExperience : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings);
LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count );
};
/*
void unpack_request_params(
@ -233,6 +250,14 @@ BOOL LLFloaterRegionInfo::postBuild()
panel->buildFromFile("panel_region_debug.xml");
mTab->addTabPanel(panel);
if(!gAgent.getRegion()->getCapability("RegionExperiences").empty())
{
panel = new LLPanelRegionExperiences;
mInfoPanels.push_back(panel);
panel->buildFromFile("panel_region_experiences.xml");
mTab->addTabPanel(panel);
}
gMessageSystem->setHandlerFunc(
"EstateOwnerMessage",
&processEstateOwnerRequest);
@ -480,6 +505,16 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain()
return panel;
}
LLPanelRegionExperiences* LLFloaterRegionInfo::getPanelExperiences()
{
LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
if (!floater) return NULL;
LLTabContainer* tab = floater->getChild<LLTabContainer>("region_panels");
return (LLPanelRegionExperiences*)tab->getChild<LLPanel>("Experiences");
}
// <FS:CR> Aurora Sim - Region Settings Console
// static
LLPanelRegionOpenSettingsInfo* LLFloaterRegionInfo::getPanelOpenSettings()
@ -1572,6 +1607,11 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch)
static LLDispatchSetEstateAccess set_access;
dispatch.addHandler(name, &set_access);
name.assign("setexperience");
static LLDispatchSetEstateExperience set_experience;
dispatch.addHandler(name, &set_experience);
estate_dispatch_initialized = true;
}
@ -3081,6 +3121,56 @@ bool LLDispatchSetEstateAccess::operator()(
return true;
}
LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count )
{
LLSD idList = LLSD::emptyArray();
LLUUID id;
while(count--> 0)
{
memcpy(id.mData, (*(it++)).data(), UUID_BYTES);
idList.append(id);
}
return idList;
}
// key = "setexperience"
// strings[0] = str(estate_id)
// strings[1] = str(send_to_agent_only)
// strings[2] = str(num blocked)
// strings[3] = str(num trusted)
// strings[4] = str(num allowed)
// strings[8] = bin(uuid) ...
// ...
bool LLDispatchSetEstateExperience::operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences();
if (!panel) return true;
sparam_t::const_iterator it = strings.begin();
++it; // U32 estate_id = strtol((*it).c_str(), NULL, 10);
++it; // U32 send_to_agent_only = strtoul((*(++it)).c_str(), NULL, 10);
LLUUID id;
S32 num_blocked = strtol((*(it++)).c_str(), NULL, 10);
S32 num_trusted = strtol((*(it++)).c_str(), NULL, 10);
S32 num_allowed = strtol((*(it++)).c_str(), NULL, 10);
LLSD ids = LLSD::emptyMap()
.with("blocked", getIDs(it, strings.end(), num_blocked))
.with("trusted", getIDs(it + (num_blocked), strings.end(), num_trusted))
.with("allowed", getIDs(it + (num_blocked+num_trusted), strings.end(), num_allowed));
panel->processResponse(ids);
return true;
}
LLPanelEnvironmentInfo::LLPanelEnvironmentInfo()
: mEnableEditing(false),
mRegionSettingsRadioGroup(NULL),
@ -3672,3 +3762,284 @@ void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok)
LLEnvManagerNew::instance().requestRegionSettings();
}
}
BOOL LLPanelRegionExperiences::postBuild()
{
mAllowed = setupList("panel_allowed", ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE);
mTrusted = setupList("panel_trusted", ESTATE_EXPERIENCE_TRUSTED_ADD, ESTATE_EXPERIENCE_TRUSTED_REMOVE);
mBlocked = setupList("panel_blocked", ESTATE_EXPERIENCE_BLOCKED_ADD, ESTATE_EXPERIENCE_BLOCKED_REMOVE);
getChild<LLLayoutPanel>("trusted_layout_panel")->setVisible(TRUE);
getChild<LLTextBox>("experiences_help_text")->setText(getString("estate_caption"));
getChild<LLTextBox>("trusted_text_help")->setText(getString("trusted_estate_text"));
getChild<LLTextBox>("allowed_text_help")->setText(getString("allowed_estate_text"));
getChild<LLTextBox>("blocked_text_help")->setText(getString("blocked_estate_text"));
return LLPanelRegionInfo::postBuild();
}
LLPanelExperienceListEditor* LLPanelRegionExperiences::setupList( const char* control_name, U32 add_id, U32 remove_id )
{
LLPanelExperienceListEditor* child = findChild<LLPanelExperienceListEditor>(control_name);
if(child)
{
child->getChild<LLTextBox>("text_name")->setText(child->getString(control_name));
child->setMaxExperienceIDs(ESTATE_MAX_EXPERIENCE_IDS);
child->setAddedCallback( boost::bind(&LLPanelRegionExperiences::itemChanged, this, add_id, _1));
child->setRemovedCallback(boost::bind(&LLPanelRegionExperiences::itemChanged, this, remove_id, _1));
}
return child;
}
void LLPanelRegionExperiences::processResponse( const LLSD& content )
{
if(content.has("default"))
{
mDefaultExperience = content["default"].asUUID();
}
mAllowed->setExperienceIds(content["allowed"]);
mBlocked->setExperienceIds(content["blocked"]);
LLSD trusted = content["trusted"];
if(mDefaultExperience.notNull())
{
mTrusted->setStickyFunction(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience));
trusted.append(mDefaultExperience);
}
mTrusted->setExperienceIds(trusted);
mAllowed->refreshExperienceCounter();
mBlocked->refreshExperienceCounter();
mTrusted->refreshExperienceCounter();
}
class LLRegionExperienceResponder : public LLHTTPClient::Responder
{
public:
typedef boost::function<void (const LLSD&)> callback_t;
callback_t mCallback;
LLRegionExperienceResponder(callback_t callback) : mCallback(callback) { }
protected:
/*virtual*/ void httpSuccess()
{
mCallback(getContent());
}
/*virtual*/ void httpFailure()
{
LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
}
};
// Used for both access add and remove operations, depending on the flag
// passed in (ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE, etc.)
// static
bool LLPanelRegionExperiences::experienceCoreConfirm(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger();
LLViewerRegion* region = gAgent.getRegion();
LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray();
for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray();
iter != end_it;
iter++)
{
U32 flags = originalFlags;
if (iter + 1 != end_it)
flags |= ESTATE_ACCESS_NO_REPLY;
const LLUUID id = iter->asUUID();
switch(option)
{
case 0:
// This estate
sendEstateExperienceDelta(flags, id);
break;
case 1:
{
// All estates, either than I own or manage for this owner.
// This will be verified on simulator. JC
if (!region) break;
if (region->getOwner() == gAgent.getID()
|| gAgent.isGodlike())
{
flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES;
sendEstateExperienceDelta(flags, id);
}
else if (region->isEstateManager())
{
flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES;
sendEstateExperienceDelta(flags, id);
}
break;
}
case 2:
default:
break;
}
}
return false;
}
// Send the actual "estateexperiencedelta" message
void LLPanelRegionExperiences::sendEstateExperienceDelta(U32 flags, const LLUUID& experience_id)
{
strings_t str(3, std::string());
gAgent.getID().toString(str[0]);
str[1] = llformat("%u", flags);
experience_id.toString(str[2]);
LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences();
if (panel)
{
panel->sendEstateOwnerMessage(gMessageSystem, "estateexperiencedelta", LLFloaterRegionInfo::getLastInvoice(), str);
}
}
void LLPanelRegionExperiences::infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content)
{
if(handle.isDead())
return;
LLPanelRegionExperiences* floater = handle.get();
if (floater)
{
floater->processResponse(content);
}
}
bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
{
BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
mAllowed->loading();
mAllowed->setReadonly(!allow_modify);
// remove grid-wide experiences
mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID));
// remove default experience
mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience));
mBlocked->loading();
mBlocked->setReadonly(!allow_modify);
// only grid-wide experiences
mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithoutProperty, _1, LLExperienceCache::PROPERTY_GRID));
// but not privileged ones
mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_PRIVILEGED));
// remove default experience
mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience));
mTrusted->loading();
mTrusted->setReadonly(!allow_modify);
std::string url = region->getCapability("RegionExperiences");
if (!url.empty())
{
LLHTTPClient::get(url, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
getDerivedHandle<LLPanelRegionExperiences>(), _1)));
}
return LLPanelRegionInfo::refreshFromRegion(region);
}
LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
{
LLSD ids;
const uuid_list_t& id_list = panel->getExperienceIds();
for(uuid_list_t::const_iterator it = id_list.begin(); it != id_list.end(); ++it)
{
ids.append(*it);
}
return ids;
}
BOOL LLPanelRegionExperiences::sendUpdate()
{
LLViewerRegion* region = gAgent.getRegion();
std::string url = region->getCapability("RegionExperiences");
if (!url.empty())
{
LLSD content;
content["allowed"]=addIds(mAllowed);
content["blocked"]=addIds(mBlocked);
content["trusted"]=addIds(mTrusted);
LLHTTPClient::post(url, content, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
getDerivedHandle<LLPanelRegionExperiences>(), _1)));
}
return TRUE;
}
void LLPanelRegionExperiences::itemChanged( U32 event_type, const LLUUID& id )
{
std::string dialog_name;
switch (event_type)
{
case ESTATE_EXPERIENCE_ALLOWED_ADD:
dialog_name = "EstateAllowedExperienceAdd";
break;
case ESTATE_EXPERIENCE_ALLOWED_REMOVE:
dialog_name = "EstateAllowedExperienceRemove";
break;
case ESTATE_EXPERIENCE_TRUSTED_ADD:
dialog_name = "EstateTrustedExperienceAdd";
break;
case ESTATE_EXPERIENCE_TRUSTED_REMOVE:
dialog_name = "EstateTrustedExperienceRemove";
break;
case ESTATE_EXPERIENCE_BLOCKED_ADD:
dialog_name = "EstateBlockedExperienceAdd";
break;
case ESTATE_EXPERIENCE_BLOCKED_REMOVE:
dialog_name = "EstateBlockedExperienceRemove";
break;
default:
return;
}
LLSD payload;
payload["operation"] = (S32)event_type;
payload["dialog_name"] = dialog_name;
payload["allowed_ids"].append(id);
LLSD args;
args["ALL_ESTATES"] = all_estates_text();
LLNotification::Params params(dialog_name);
params.payload(payload)
.substitutions(args)
.functor.function(LLPanelRegionExperiences::experienceCoreConfirm);
if (LLPanelEstateInfo::isLindenEstate())
{
LLNotifications::instance().forceResponse(params, 0);
}
else
{
LLNotifications::instance().add(params);
}
onChangeAnything();
}

View File

@ -63,6 +63,9 @@ class LLPanelRegionDebugInfo;
class LLPanelRegionTerrainInfo;
class LLPanelEstateInfo;
class LLPanelEstateCovenant;
class LLPanelExperienceListEditor;
class LLPanelExperiences;
class LLPanelRegionExperiences;
class LLEventTimer;
class LLEnvironmentSettings;
@ -93,6 +96,7 @@ public:
static LLPanelEstateInfo* getPanelEstate();
static LLPanelEstateCovenant* getPanelCovenant();
static LLPanelRegionTerrainInfo* getPanelRegionTerrain();
static LLPanelRegionExperiences* getPanelExperiences();
// <FS:CR> Aurora Sim - Region Settings Panel
static LLPanelRegionOpenSettingsInfo* getPanelOpenSettings();
// </FS:CR> Aurora Sim - Region Settings Panel
@ -479,4 +483,34 @@ private:
LLComboBox* mDayCyclePresetCombo;
};
class LLPanelRegionExperiences : public LLPanelRegionInfo
{
LOG_CLASS(LLPanelEnvironmentInfo);
public:
LLPanelRegionExperiences(){}
/*virtual*/ BOOL postBuild();
virtual BOOL sendUpdate();
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
static void infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content);
bool refreshFromRegion(LLViewerRegion* region);
void sendPurchaseRequest()const;
void processResponse( const LLSD& content );
private:
void refreshRegionExperiences();
LLPanelExperienceListEditor* setupList(const char* control_name, U32 add_id, U32 remove_id);
static LLSD addIds( LLPanelExperienceListEditor* panel );
void itemChanged(U32 event_type, const LLUUID& id);
LLPanelExperienceListEditor* mTrusted;
LLPanelExperienceListEditor* mAllowed;
LLPanelExperienceListEditor* mBlocked;
LLUUID mDefaultExperience;
};
#endif

View File

@ -81,6 +81,7 @@
#include "llagentui.h"
#include "lltrans.h"
#include "llexperiencecache.h"
//-----------------------------------------------------------------------------
// Globals
@ -210,6 +211,30 @@ void LLFloaterReporter::enableControls(BOOL enable)
getChildView("cancel_btn")->setEnabled(enable);
}
void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
{
mExperienceID = experience_id;
if (LLUUID::null != mExperienceID)
{
const LLSD& experience = LLExperienceCache::get(mExperienceID);
std::stringstream desc;
if(experience.isDefined())
{
setFromAvatarID(experience[LLExperienceCache::AGENT_ID]);
desc << "Experience id: " << mExperienceID;
}
else
{
desc << "Unable to retrieve details for id: "<< mExperienceID;
}
LLUICtrl* details = getChild<LLUICtrl>("details_edit");
details->setValue(desc.str());
}
}
void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
{
// TODO --
@ -463,7 +488,7 @@ void LLFloaterReporter::showFromMenu(EReportType report_type)
}
// static
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name)
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name, const LLUUID& experience_id)
{
LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
@ -476,6 +501,23 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
{
f->setFromAvatarID(object_id);
}
if(experience_id.notNull())
{
f->getExperienceInfo(experience_id);
}
// Need to deselect on close
f->mDeselectOnClose = TRUE;
f->openFloater();
}
void LLFloaterReporter::showFromExperience( const LLUUID& experience_id )
{
LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
f->getExperienceInfo(experience_id);
// Need to deselect on close
f->mDeselectOnClose = TRUE;
@ -485,9 +527,9 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
// static
void LLFloaterReporter::showFromObject(const LLUUID& object_id)
void LLFloaterReporter::showFromObject(const LLUUID& object_id, const LLUUID& experience_id)
{
show(object_id);
show(object_id, LLStringUtil::null, experience_id);
}
// static

View File

@ -88,8 +88,9 @@ public:
// Enables all buttons
static void showFromMenu(EReportType report_type);
static void showFromObject(const LLUUID& object_id);
static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null);
static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name);
static void showFromExperience(const LLUUID& experience_id);
static void onClickSend (void *userdata);
static void onClickCancel (void *userdata);
@ -103,7 +104,7 @@ public:
void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id);
private:
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null);
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null);
void takeScreenshot();
void sendReportViaCaps(std::string url);
@ -115,6 +116,7 @@ private:
void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report);
void setPosBox(const LLVector3d &pos);
void enableControls(BOOL own_avatar);
void getExperienceInfo(const LLUUID& object_id);
void getObjectInfo(const LLUUID& object_id);
void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
void setFromAvatarID(const LLUUID& avatar_id);
@ -127,6 +129,7 @@ private:
LLUUID mObjectID;
LLUUID mScreenID;
LLUUID mAbuserID;
LLUUID mExperienceID;
// Store the real name, not the link, for upstream reporting
std::string mOwnerName;
BOOL mDeselectOnClose;

View File

@ -538,6 +538,7 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&
mHasOfflineMessage(has_offline_msg),
// [SL:KB] - Patch: Chat-GroupSnooze | Checked: 2012-08-01 (Catznip-3.3)
mCloseAction(CLOSE_DEFAULT),
mSnoozeTime(-1),
// [/SL:KB]
mParticipantUnreadMessageCount(0),
mNumUnread(0),
@ -3415,6 +3416,11 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)
static LLCachedControl<S32> s_nSnoozeTime(gSavedSettings, "GroupSnoozeTime", 900);
snoozed_sessions_t::iterator itSession = mSnoozedSessions.find(session_id);
F64 expirationTime = LLTimer::getTotalSeconds() + F64(s_nSnoozeTime);
if (im_session->mSnoozeTime > -1)
{
expirationTime = LLTimer::getTotalSeconds() + F64(im_session->mSnoozeTime);
im_session->mSnoozeTime = -1;
}
if (mSnoozedSessions.end() != itSession)
itSession->second = expirationTime;

View File

@ -116,9 +116,12 @@ public:
SType mSessionType;
// [SL:KB] - Patch: Chat-GroupSnooze | Checked: 2014-03-01 (Catznip-3.6)
SCloseAction mCloseAction;
S32 mSnoozeTime;
// [/SL:KB]
LLUUID mOtherParticipantID;
uuid_vec_t mInitialTargetIDs;
// <FS:Ansariel> Needed to store IDs of initially invited agents; required for FS Communication UI, as original IM floater gets destroyed
uuid_vec_t mInitialInvitedIDs;
std::string mHistoryFileName;
// connection to voice channel state change signal

View File

@ -174,7 +174,9 @@ public:
virtual ~LLScriptHandler();
virtual void onDelete(LLNotificationPtr p);
virtual void onChange(LLNotificationPtr p);
virtual bool processNotification(const LLNotificationPtr& p);
virtual void addToastWithNotification(const LLNotificationPtr& p);
protected:
virtual void onDeleteToast(LLToast* toast);

View File

@ -67,6 +67,30 @@ void LLScriptHandler::initChannel()
mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
}
//--------------------------------------------------------------------------
void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notification)
{
LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
LLToast::Params p;
p.notif_id = notification->getID();
p.notification = notification;
p.panel = notify_box;
p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1);
if(gAgent.isDoNotDisturb())
{
p.force_show = notification->getName() == "SystemMessage"
|| notification->getName() == "GodMessage"
|| notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH;
}
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
if(channel)
{
channel->addToast(p);
}
}
//--------------------------------------------------------------------------
bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
{
@ -92,42 +116,33 @@ bool LLScriptHandler::processNotification(const LLNotificationPtr& notification)
}
else if (notification->canShowToast())
{
LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification);
LLToast::Params p;
p.notif_id = notification->getID();
p.notification = notification;
p.panel = notify_box;
p.on_delete_toast = boost::bind(&LLScriptHandler::onDeleteToast, this, _1);
if(gAgent.isDoNotDisturb())
{
p.force_show = notification->getName() == "SystemMessage"
|| notification->getName() == "GodMessage"
|| notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH;
}
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
if(channel)
{
channel->addToast(p);
}
addToastWithNotification(notification);
}
return false;
}
void LLScriptHandler::onChange( LLNotificationPtr notification )
{
LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel.get());
if (channel)
{
channel->removeToastByNotificationID(notification->getID());
addToastWithNotification(notification);
}
}
void LLScriptHandler::onDelete( LLNotificationPtr notification )
{
{
if(notification->hasFormElements() && !notification->canShowToast())
{
LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
}
else
{
mChannel.get()->removeToastByNotificationID(notification->getID());
}
{
LLScriptFloaterManager::getInstance()->onRemoveNotification(notification->getID());
}
else
{
mChannel.get()->removeToastByNotificationID(notification->getID());
}
}
//--------------------------------------------------------------------------

View File

@ -0,0 +1,262 @@
/**
* @file llpanelexperiencelisteditor.cpp
* @brief Editor for building a list of experiences
*
* $LicenseInfo:firstyear=2014&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 "llviewerprecompiledheaders.h"
#include "llpanelexperiencelisteditor.h"
#include "llbutton.h"
#include "llexperiencecache.h"
#include "llfloaterexperiencepicker.h"
#include "llfloaterreg.h"
#include "llhandle.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "lltextbox.h"
#include "lltrans.h"
static LLPanelInjector<LLPanelExperienceListEditor> t_panel_experience_list_editor("panel_experience_list_editor");
LLPanelExperienceListEditor::LLPanelExperienceListEditor()
:mItems(NULL)
,mProfile(NULL)
,mRemove(NULL)
,mReadonly(false)
,mMaxExperienceIDs(0)
{
}
BOOL LLPanelExperienceListEditor::postBuild()
{
mItems = getChild<LLScrollListCtrl>("experience_list");
mAdd = getChild<LLButton>("btn_add");
mRemove = getChild<LLButton>("btn_remove");
mProfile = getChild<LLButton>("btn_profile");
childSetAction("btn_add", boost::bind(&LLPanelExperienceListEditor::onAdd, this));
childSetAction("btn_remove", boost::bind(&LLPanelExperienceListEditor::onRemove, this));
childSetAction("btn_profile", boost::bind(&LLPanelExperienceListEditor::onProfile, this));
mItems->setCommitCallback(boost::bind(&LLPanelExperienceListEditor::checkButtonsEnabled, this));
checkButtonsEnabled();
return TRUE;
}
const uuid_list_t& LLPanelExperienceListEditor::getExperienceIds() const
{
return mExperienceIds;
}
void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience_ids )
{
// the commented out code in this function is handled by the callback and no longer necessary!
//mExperienceIds.insert(experience_ids.begin(), experience_ids.end());
//onItems();
if(!mAddedCallback.empty())
{
for(uuid_vec_t::const_iterator it = experience_ids.begin(); it != experience_ids.end(); ++it)
{
mAddedCallback(*it);
}
}
}
void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids )
{
mExperienceIds.clear();
mExperienceIds.insert(experience_ids.beginArray(), experience_ids.endArray());
onItems();
}
void LLPanelExperienceListEditor::addExperience( const LLUUID& id )
{
mExperienceIds.insert(id);
onItems();
}
void LLPanelExperienceListEditor::onAdd()
{
if(!mPicker.isDead())
{
mPicker.markDead();
}
mKey.generateNewID();
LLFloaterExperiencePicker* picker=LLFloaterExperiencePicker::show(boost::bind(&LLPanelExperienceListEditor::addExperienceIds, this, _1), mKey, FALSE, TRUE, mFilters, mAdd);
mPicker = picker->getDerivedHandle<LLFloaterExperiencePicker>();
}
void LLPanelExperienceListEditor::onRemove()
{
// the commented out code in this function is handled by the callback and no longer necessary!
std::vector<LLScrollListItem*> items= mItems->getAllSelected();
std::vector<LLScrollListItem*>::iterator it = items.begin();
for(/**/; it != items.end(); ++it)
{
if((*it) != NULL)
{
//mExperienceIds.erase((*it)->getValue());
mRemovedCallback((*it)->getValue());
}
}
mItems->selectFirstItem();
checkButtonsEnabled();
//onItems();
}
void LLPanelExperienceListEditor::onProfile()
{
LLScrollListItem* item = mItems->getFirstSelected();
if(item)
{
LLFloaterReg::showInstance("experience_profile", item->getUUID(), true);
}
}
void LLPanelExperienceListEditor::checkButtonsEnabled()
{
mAdd->setEnabled(!mReadonly);
int selected = mItems->getNumSelected();
bool remove_enabled = !mReadonly && selected>0;
if(remove_enabled && mSticky)
{
std::vector<LLScrollListItem*> items= mItems->getAllSelected();
std::vector<LLScrollListItem*>::iterator it = items.begin();
for(/**/; it != items.end() && remove_enabled; ++it)
{
if((*it) != NULL)
{
remove_enabled = !mSticky((*it)->getValue());
}
}
}
mRemove->setEnabled(remove_enabled);
mProfile->setEnabled(selected==1);
}
void LLPanelExperienceListEditor::onItems()
{
mItems->deleteAllItems();
LLSD item;
uuid_list_t::iterator it = mExperienceIds.begin();
for(/**/; it != mExperienceIds.end(); ++it)
{
const LLUUID& experience = *it;
item["id"]=experience;
LLSD& columns = item["columns"];
columns[0]["column"] = "experience_name";
columns[0]["value"] = getString("loading");
mItems->addElement(item);
LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
if(mItems->getItemCount() == 0)
{
mItems->setCommentText(getString("no_results"));
}
checkButtonsEnabled();
}
void LLPanelExperienceListEditor::experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience )
{
if(!panel.isDead())
{
panel.get()->onExperienceDetails(experience);
}
}
void LLPanelExperienceListEditor::onExperienceDetails( const LLSD& experience )
{
LLScrollListItem* item = mItems->getItem(experience[LLExperienceCache::EXPERIENCE_ID]);
if(!item)
return;
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
item->getColumn(0)->setValue(experience_name_string);
}
LLPanelExperienceListEditor::~LLPanelExperienceListEditor()
{
if(!mPicker.isDead())
{
mPicker.get()->closeFloater();
}
}
void LLPanelExperienceListEditor::loading()
{
mItems->clear();
mItems->setCommentText( getString("loading"));
}
void LLPanelExperienceListEditor::setReadonly( bool val )
{
mReadonly = val;
checkButtonsEnabled();
}
void LLPanelExperienceListEditor::refreshExperienceCounter()
{
if(mMaxExperienceIDs > 0)
{
LLStringUtil::format_map_t args;
args["[EXPERIENCES]"] = llformat("%d", mItems->getItemCount());
args["[MAXEXPERIENCES]"] = llformat("%d", mMaxExperienceIDs);
getChild<LLTextBox>("text_count")->setText(LLTrans::getString("ExperiencesCounter", args));
}
}
boost::signals2::connection LLPanelExperienceListEditor::setAddedCallback( list_changed_signal_t::slot_type cb )
{
return mAddedCallback.connect(cb);
}
boost::signals2::connection LLPanelExperienceListEditor::setRemovedCallback( list_changed_signal_t::slot_type cb )
{
return mRemovedCallback.connect(cb);
}

View File

@ -0,0 +1,100 @@
/**
* @file llpanelexperiencelisteditor.cpp
* @brief Editor for building a list of experiences
*
* $LicenseInfo:firstyear=2014&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_LLPANELEXPERIENCELISTEDITOR_H
#define LL_LLPANELEXPERIENCELISTEDITOR_H
#include "llpanel.h"
#include "lluuid.h"
#include <set>
class LLScrollListCtrl;
class LLButton;
class LLFloaterExperiencePicker;
class LLPanelExperienceListEditor : public LLPanel
{
public:
typedef boost::signals2::signal<void (const LLUUID&) > list_changed_signal_t;
// filter function for experiences, return true if the experience should be hidden.
typedef boost::function<bool (const LLSD&)> experience_function;
typedef std::vector<experience_function> filter_list;
typedef LLHandle<LLFloaterExperiencePicker> PickerHandle;
LLPanelExperienceListEditor();
~LLPanelExperienceListEditor();
BOOL postBuild();
void loading();
const uuid_list_t& getExperienceIds()const;
void setExperienceIds(const LLSD& experience_ids);
void addExperienceIds(const uuid_vec_t& experience_ids);
void addExperience(const LLUUID& id);
boost::signals2::connection setAddedCallback(list_changed_signal_t::slot_type cb );
boost::signals2::connection setRemovedCallback(list_changed_signal_t::slot_type cb );
bool getReadonly() const { return mReadonly; }
void setReadonly(bool val);
void refreshExperienceCounter();
void addFilter(experience_function func){mFilters.push_back(func);}
void setStickyFunction(experience_function func){mSticky = func;}
U32 getMaxExperienceIDs() const { return mMaxExperienceIDs; }
void setMaxExperienceIDs(U32 val) { mMaxExperienceIDs = val; }
private:
void onItems();
void onRemove();
void onAdd();
void onProfile();
void checkButtonsEnabled();
static void experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience );
void onExperienceDetails( const LLSD& experience );
void processResponse( const LLSD& content );
uuid_list_t mExperienceIds;
LLScrollListCtrl* mItems;
filter_list mFilters;
LLButton* mAdd;
LLButton* mRemove;
LLButton* mProfile;
PickerHandle mPicker;
list_changed_signal_t mAddedCallback;
list_changed_signal_t mRemovedCallback;
LLUUID mKey;
bool mReadonly;
experience_function mSticky;
U32 mMaxExperienceIDs;
};
#endif //LL_LLPANELEXPERIENCELISTEDITOR_H

View File

@ -0,0 +1,264 @@
/**
* @file llpanelexperiencelog.cpp
* @brief llpanelexperiencelog
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llviewerprecompiledheaders.h"
#include "llpanelexperiencelog.h"
#include "llexperiencelog.h"
#include "llexperiencecache.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llcombobox.h"
#include "llspinctrl.h"
#include "llcheckboxctrl.h"
#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llinventoryfunctions.h"
#define BTN_PROFILE_XP "btn_profile_xp"
#define BTN_REPORT_XP "btn_report_xp"
static LLPanelInjector<LLPanelExperienceLog> register_experiences_panel("experience_log");
LLPanelExperienceLog::LLPanelExperienceLog( )
: mEventList(NULL)
, mPageSize(25)
, mCurrentPage(0)
{
buildFromFile("panel_experience_log.xml");
}
BOOL LLPanelExperienceLog::postBuild( void )
{
LLExperienceLog* log = LLExperienceLog::getInstance();
mEventList = getChild<LLScrollListCtrl>("experience_log_list");
mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this));
mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this));
getChild<LLButton>(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
getChild<LLButton>(BTN_REPORT_XP )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this));
getChild<LLButton>("btn_notify" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this));
getChild<LLButton>("btn_next" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this));
getChild<LLButton>("btn_prev" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this));
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("notify_all");
check->set(log->getNotifyNewEvent());
check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this));
LLSpinCtrl* spin = getChild<LLSpinCtrl>("logsizespinner");
spin->set(log->getMaxDays());
spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this));
mPageSize = log->getPageSize();
refresh();
mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this));
return TRUE;
}
LLPanelExperienceLog* LLPanelExperienceLog::create()
{
return new LLPanelExperienceLog();
}
void LLPanelExperienceLog::refresh()
{
S32 selected = mEventList->getFirstSelectedIndex();
mEventList->deleteAllItems();
const LLSD events = LLExperienceLog::instance().getEvents();
if(events.size() == 0)
{
mEventList->setCommentText(getString("no_events"));
return;
}
setAllChildrenEnabled(FALSE);
LLSD item;
bool waiting = false;
LLUUID waiting_id;
int itemsToSkip = mPageSize*mCurrentPage;
int items = 0;
bool moreItems = false;
if (!events.emptyMap())
{
LLSD::map_const_iterator day = events.endMap();
do
{
--day;
const LLSD& dayArray = day->second;
int size = dayArray.size();
if(itemsToSkip > size)
{
itemsToSkip -= size;
continue;
}
if(items >= mPageSize && size > 0)
{
moreItems = true;
break;
}
for(int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--)
{
if(items >= mPageSize)
{
moreItems = true;
break;
}
const LLSD event = dayArray[i];
LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
const LLSD& experience = LLExperienceCache::get(id);
if(experience.isUndefined()){
waiting = true;
waiting_id = id;
}
if(!waiting)
{
item["id"] = event;
LLSD& columns = item["columns"];
columns[0]["column"] = "time";
columns[0]["value"] = day->first+event["Time"].asString();
columns[1]["column"] = "event";
columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
columns[2]["column"] = "experience_name";
columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
columns[3]["column"] = "object_name";
columns[3]["value"] = event["ObjectName"].asString();
mEventList->addElement(item);
}
++items;
}
} while (day != events.beginMap());
}
if(waiting)
{
mEventList->deleteAllItems();
mEventList->setCommentText(getString("loading"));
LLExperienceCache::get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
}
else
{
setAllChildrenEnabled(TRUE);
mEventList->setEnabled(TRUE);
getChild<LLButton>("btn_next")->setEnabled(moreItems);
getChild<LLButton>("btn_prev")->setEnabled(mCurrentPage>0);
getChild<LLButton>("btn_clear")->setEnabled(mEventList->getItemCount()>0);
if(selected<0)
{
selected = 0;
}
mEventList->selectNthItem(selected);
onSelectionChanged();
}
}
void LLPanelExperienceLog::onProfileExperience()
{
LLSD event = getSelectedEvent();
if(event.isDefined())
{
LLFloaterReg::showInstance("experience_profile", event[LLExperienceCache::EXPERIENCE_ID].asUUID(), true);
}
}
void LLPanelExperienceLog::onReportExperience()
{
LLSD event = getSelectedEvent();
if(event.isDefined())
{
LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID());
}
}
void LLPanelExperienceLog::onNotify()
{
LLSD event = getSelectedEvent();
if(event.isDefined())
{
LLExperienceLog::instance().notify(event);
}
}
void LLPanelExperienceLog::onNext()
{
mCurrentPage++;
refresh();
}
void LLPanelExperienceLog::onPrev()
{
if(mCurrentPage>0)
{
mCurrentPage--;
refresh();
}
}
void LLPanelExperienceLog::notifyChanged()
{
LLExperienceLog::instance().setNotifyNewEvent(getChild<LLCheckBoxCtrl>("notify_all")->get());
}
void LLPanelExperienceLog::logSizeChanged()
{
int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get());
bool dirty = value > 0 && value < LLExperienceLog::instance().getMaxDays();
LLExperienceLog::instance().setMaxDays(value);
if(dirty)
{
refresh();
}
}
void LLPanelExperienceLog::onSelectionChanged()
{
bool enabled = (1 == mEventList->getNumSelected());
getChild<LLButton>(BTN_REPORT_XP)->setEnabled(enabled);
getChild<LLButton>(BTN_PROFILE_XP)->setEnabled(enabled);
getChild<LLButton>("btn_notify")->setEnabled(enabled);
}
LLSD LLPanelExperienceLog::getSelectedEvent()
{
LLScrollListItem* item = mEventList->getFirstSelected();
if(item)
{
return item->getValue();
}
return LLSD();
}

View File

@ -0,0 +1,64 @@
/**
* @file llpanelexperiencelog.h
* @brief llpanelexperiencelog and related class definitions
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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_LLPANELEXPERIENCELOG_H
#define LL_LLPANELEXPERIENCELOG_H
#include "llpanel.h"
class LLScrollListCtrl;
class LLPanelExperienceLog
: public LLPanel
{
public:
LLPanelExperienceLog();
static LLPanelExperienceLog* create();
/*virtual*/ BOOL postBuild(void);
void refresh();
protected:
void logSizeChanged();
void notifyChanged();
void onNext();
void onNotify();
void onPrev();
void onProfileExperience();
void onReportExperience();
void onSelectionChanged();
LLSD getSelectedEvent();
private:
LLScrollListCtrl* mEventList;
U32 mPageSize;
U32 mCurrentPage;
boost::signals2::scoped_connection mNewEvent;
};
#endif // LL_LLPANELEXPERIENCELOG_H

View File

@ -0,0 +1,444 @@
/**
* @file llpanelexperiencepicker.cpp
* @brief Implementation of llpanelexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llviewerprecompiledheaders.h"
#include "llpanelexperiencepicker.h"
#include "lllineeditor.h"
#include "llfloaterreg.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "llexperiencecache.h"
#include "llslurl.h"
#include "llavatarnamecache.h"
#include "llcombobox.h"
#include "llviewercontrol.h"
#include "llfloater.h"
#include "lltrans.h"
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
#define BTN_CANCEL "cancel_btn"
#define BTN_PROFILE "profile_btn"
#define BTN_LEFT "left_btn"
#define BTN_RIGHT "right_btn"
#define TEXT_EDIT "edit"
#define TEXT_MATURITY "maturity"
#define LIST_RESULTS "search_results"
#define PANEL_SEARCH "search_panel"
const static std::string columnSpace = " ";
static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker");
class LLExperienceSearchResponder : public LLHTTPClient::Responder
{
public:
LLUUID mQueryID;
LLHandle<LLPanelExperiencePicker> mParent;
LLExperienceSearchResponder(const LLUUID& id, const LLHandle<LLPanelExperiencePicker>& parent) : mQueryID(id), mParent(parent) { }
protected:
/*virtual*/ void httpSuccess()
{
if(mParent.isDead())
return;
LLPanelExperiencePicker* panel =mParent.get();
if (panel)
{
panel->processResponse(mQueryID, getContent());
}
}
/*virtual*/ void httpFailure()
{
if(mParent.isDead())
return;
LLPanelExperiencePicker* panel =mParent.get();
if (panel)
{
panel->processResponse(mQueryID, LLSD());
}
LL_WARNS() << "experience picker failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
}
};
LLPanelExperiencePicker::LLPanelExperiencePicker()
:LLPanel()
{
buildFromFile("panel_experience_search.xml");
setDefaultFilters();
}
LLPanelExperiencePicker::~LLPanelExperiencePicker()
{
}
BOOL LLPanelExperiencePicker::postBuild()
{
getChild<LLLineEditor>(TEXT_EDIT)->setKeystrokeCallback( boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1, _2),NULL);
childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
getChildView(BTN_FIND)->setEnabled(TRUE);
LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>(LIST_RESULTS);
searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this));
getChildView(LIST_RESULTS)->setEnabled(FALSE);
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
childSetAction(BTN_OK, boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
getChildView(BTN_OK)->setEnabled(FALSE);
childSetAction(BTN_CANCEL, boost::bind(&LLPanelExperiencePicker::onBtnClose, this));
childSetAction(BTN_PROFILE, boost::bind(&LLPanelExperiencePicker::onBtnProfile, this));
getChildView(BTN_PROFILE)->setEnabled(FALSE);
// <FS:Ansariel> Remember maturity level
//getChild<LLComboBox>(TEXT_MATURITY)->setCurrentByIndex(2);
getChild<LLComboBox>(TEXT_MATURITY)->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onMaturity, this));
getChild<LLUICtrl>(TEXT_EDIT)->setFocus(TRUE);
childSetAction(BTN_LEFT, boost::bind(&LLPanelExperiencePicker::onPage, this, -1));
childSetAction(BTN_RIGHT, boost::bind(&LLPanelExperiencePicker::onPage, this, 1));
LLPanel* search_panel = getChild<LLPanel>(PANEL_SEARCH);
if (search_panel)
{
// Start searching when Return is pressed in the line editor.
search_panel->setDefaultBtn(BTN_FIND);
}
return TRUE;
}
void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* user_data )
{
getChildView(BTN_FIND)->setEnabled(true);
}
void LLPanelExperiencePicker::onBtnFind()
{
mCurrentPage=1;
find();
}
void LLPanelExperiencePicker::onList()
{
bool enabled = isSelectButtonEnabled();
getChildView(BTN_OK)->setEnabled(enabled);
enabled = enabled && getChild<LLScrollListCtrl>(LIST_RESULTS)->getNumSelected() == 1;
getChildView(BTN_PROFILE)->setEnabled(enabled);
}
void LLPanelExperiencePicker::find()
{
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
mQueryID.generate();
std::ostringstream url;
LLViewerRegion* region = gAgent.getRegion();
std::string cap = region->getCapability("FindExperienceByName");
if (!cap.empty())
{
url << cap << "?page=" << mCurrentPage << "&page_size=30&query=" << LLURI::escape(text);
LLHTTPClient::get(url.str(), new LLExperienceSearchResponder(mQueryID, getDerivedHandle<LLPanelExperiencePicker>()));
}
getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
getChildView(BTN_OK)->setEnabled(FALSE);
getChildView(BTN_PROFILE)->setEnabled(FALSE);
getChildView(BTN_RIGHT)->setEnabled(FALSE);
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
return list->getFirstSelectedIndex() >=0;
}
void LLPanelExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids )
{
std::vector<LLScrollListItem*> items = results->getAllSelected();
for(std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); ++it)
{
LLScrollListItem* item = *it;
if (item->getUUID().notNull())
{
experience_ids.push_back(item->getUUID());
}
}
}
void LLPanelExperiencePicker::setAllowMultiple( bool allow_multiple )
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setAllowMultipleSelection(allow_multiple);
}
void name_callback(const LLHandle<LLPanelExperiencePicker>& floater, const LLUUID& experience_id, const LLUUID& agent_id, const LLAvatarName& av_name)
{
if(floater.isDead())
return;
LLPanelExperiencePicker* picker = floater.get();
LLScrollListCtrl* search_results = picker->getChild<LLScrollListCtrl>(LIST_RESULTS);
LLScrollListItem* item = search_results->getItem(experience_id);
if(!item)
return;
item->getColumn(2)->setValue(columnSpace+av_name.getDisplayName());
}
void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content )
{
if(query_id != mQueryID)
{
return;
}
mResponse = content;
const LLSD& experiences=mResponse["experience_keys"];
LLSD::array_const_iterator it = experiences.beginArray();
for ( ; it != experiences.endArray(); ++it)
{
LLExperienceCache::insert(*it);
}
getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url"));
filterContent();
}
void LLPanelExperiencePicker::onBtnSelect()
{
if(!isSelectButtonEnabled())
{
return;
}
if(mSelectionCallback)
{
const LLScrollListCtrl* results = getChild<LLScrollListCtrl>(LIST_RESULTS);
uuid_vec_t experience_ids;
getSelectedExperienceIds(results, experience_ids);
mSelectionCallback(experience_ids);
getChild<LLScrollListCtrl>(LIST_RESULTS)->deselectAllItems(TRUE);
if(mCloseOnSelect)
{
mCloseOnSelect = FALSE;
onBtnClose();
}
}
else
{
onBtnProfile();
}
}
void LLPanelExperiencePicker::onBtnClose()
{
LLFloater* floater = getParentByType<LLFloater>();
if (floater)
{
floater->closeFloater();
}
}
void LLPanelExperiencePicker::onBtnProfile()
{
LLScrollListItem* item = getChild<LLScrollListCtrl>(LIST_RESULTS)->getFirstSelected();
if(item)
{
LLFloaterReg::showInstance("experience_profile", item->getUUID(), true);
}
}
std::string LLPanelExperiencePicker::getMaturityString(int maturity)
{
if(maturity <= SIM_ACCESS_PG)
{
return getString("maturity_icon_general");
}
else if(maturity <= SIM_ACCESS_MATURE)
{
return getString("maturity_icon_moderate");
}
return getString("maturity_icon_adult");
}
void LLPanelExperiencePicker::filterContent()
{
LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>(LIST_RESULTS);
const LLSD& experiences=mResponse["experience_keys"];
search_results->deleteAllItems();
LLSD item;
LLSD::array_const_iterator it = experiences.beginArray();
for ( ; it != experiences.endArray(); ++it)
{
const LLSD& experience = *it;
if(isExperienceHidden(experience))
continue;
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
item["id"]=experience[LLExperienceCache::EXPERIENCE_ID];
LLSD& columns = item["columns"];
columns[0]["column"] = "maturity";
columns[0]["value"] = getMaturityString(experience[LLExperienceCache::MATURITY].asInteger());
columns[0]["type"]="icon";
columns[0]["halign"]="right";
columns[1]["column"] = "experience_name";
columns[1]["value"] = columnSpace+experience_name_string;
columns[2]["column"] = "owner";
columns[2]["value"] = columnSpace+getString("loading");
search_results->addElement(item);
LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID], boost::bind(name_callback, getDerivedHandle<LLPanelExperiencePicker>(), experience[LLExperienceCache::EXPERIENCE_ID], _1, _2));
}
if (search_results->isEmpty())
{
LLStringUtil::format_map_t map;
std::string search_text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
map["[TEXT]"] = search_text;
if (search_text.empty())
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
}
else
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("not_found", map));
}
search_results->setEnabled(false);
getChildView(BTN_OK)->setEnabled(false);
getChildView(BTN_PROFILE)->setEnabled(false);
}
else
{
getChildView(BTN_OK)->setEnabled(true);
search_results->setEnabled(true);
search_results->sortByColumnIndex(1, TRUE);
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
if (!search_results->selectItemByLabel(text, TRUE, 1))
{
search_results->selectFirstItem();
}
onList();
search_results->setFocus(TRUE);
}
}
void LLPanelExperiencePicker::onMaturity()
{
if(mResponse.has("experience_keys") && mResponse["experience_keys"].beginArray() != mResponse["experience_keys"].endArray())
{
filterContent();
}
}
bool LLPanelExperiencePicker::isExperienceHidden( const LLSD& experience) const
{
bool hide=false;
filter_list::const_iterator it = mFilters.begin();
for(/**/;it != mFilters.end(); ++it)
{
if((*it)(experience)){
return true;
}
}
return hide;
}
bool LLPanelExperiencePicker::FilterOverRating( const LLSD& experience )
{
int maturity = getChild<LLComboBox>(TEXT_MATURITY)->getSelectedValue().asInteger();
return experience[LLExperienceCache::MATURITY].asInteger() > maturity;
}
bool LLPanelExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop)
{
return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0;
}
bool LLPanelExperiencePicker::FilterWithoutProperties( const LLSD& experience, S32 prop)
{
return ((experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == prop);
}
bool LLPanelExperiencePicker::FilterWithoutProperty( const LLSD& experience, S32 prop )
{
return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == 0;
}
void LLPanelExperiencePicker::setDefaultFilters()
{
mFilters.clear();
addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating, this, _1));
}
bool LLPanelExperiencePicker::FilterMatching( const LLSD& experience, const LLUUID& id )
{
if(experience.isUUID())
{
return experience.asUUID() == id;
}
return experience[LLExperienceCache::EXPERIENCE_ID].asUUID() == id;
}
void LLPanelExperiencePicker::onPage( S32 direction )
{
mCurrentPage += direction;
if(mCurrentPage < 1)
{
mCurrentPage = 1;
}
find();
}

View File

@ -0,0 +1,95 @@
/**
* @file llpanelexperiencepicker.h
* @brief Header file for llpanelexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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_LLPANELEXPERIENCEPICKER_H
#define LL_LLPANELEXPERIENCEPICKER_H
#include "llpanel.h"
class LLScrollListCtrl;
class LLLineEditor;
class LLPanelExperiencePicker : public LLPanel
{
public:
friend class LLExperienceSearchResponder;
friend class LLFloaterExperiencePicker;
typedef boost::function<void (const uuid_vec_t&)> select_callback_t;
// filter function for experiences, return true if the experience should be hidden.
typedef boost::function<bool (const LLSD&)> filter_function;
typedef std::vector<filter_function> filter_list;
LLPanelExperiencePicker();
virtual ~LLPanelExperiencePicker();
BOOL postBuild();
void addFilter(filter_function func){mFilters.push_back(func);}
template <class IT>
void addFilters(IT begin, IT end){mFilters.insert(mFilters.end(), begin, end);}
void setDefaultFilters();
static bool FilterWithProperty(const LLSD& experience, S32 prop);
static bool FilterWithoutProperties(const LLSD& experience, S32 prop);
static bool FilterWithoutProperty(const LLSD& experience, S32 prop);
static bool FilterMatching(const LLSD& experience, const LLUUID& id);
bool FilterOverRating(const LLSD& experience);
private:
void editKeystroke(LLLineEditor* caller, void* user_data);
void onBtnFind();
void onBtnSelect();
void onBtnClose();
void onBtnProfile();
void onList();
void onMaturity();
void onPage(S32 direction);
void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids );
void setAllowMultiple(bool allow_multiple);
void find();
bool isSelectButtonEnabled();
void processResponse( const LLUUID& query_id, const LLSD& content );
void filterContent();
bool isExperienceHidden(const LLSD& experience) const ;
std::string getMaturityString(int maturity);
select_callback_t mSelectionCallback;
filter_list mFilters;
LLUUID mQueryID;
LLSD mResponse;
bool mCloseOnSelect;
S32 mCurrentPage;
};
#endif // LL_LLPANELEXPERIENCEPICKER_H

View File

@ -0,0 +1,218 @@
/**
* @file llpanelexperiences.cpp
* @brief LLPanelExperiences class implementation
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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 "llviewerprecompiledheaders.h"
#include "llpanelprofile.h"
#include "lluictrlfactory.h"
#include "llexperiencecache.h"
#include "llagent.h"
#include "llpanelexperiences.h"
#include "llslurl.h"
#include "lllayoutstack.h"
static LLPanelInjector<LLPanelExperiences> register_experiences_panel("experiences_panel");
//comparators
static const LLExperienceItemComparator NAME_COMPARATOR;
LLPanelExperiences::LLPanelExperiences( )
: mExperiencesList(NULL)
{
buildFromFile("panel_experiences.xml");
}
BOOL LLPanelExperiences::postBuild( void )
{
mExperiencesList = getChild<LLFlatListView>("experiences_list");
if (hasString("loading_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("loading_experiences"));
}
else if (hasString("no_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("no_experiences"));
}
mExperiencesList->setComparator(&NAME_COMPARATOR);
return TRUE;
}
LLExperienceItem* LLPanelExperiences::getSelectedExperienceItem()
{
LLPanel* selected_item = mExperiencesList->getSelectedItem();
if (!selected_item) return NULL;
return dynamic_cast<LLExperienceItem*>(selected_item);
}
void LLPanelExperiences::setExperienceList( const LLSD& experiences )
{
if (hasString("no_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("no_experiences"));
}
mExperiencesList->clear();
LLSD::array_const_iterator it = experiences.beginArray();
for( /**/ ; it != experiences.endArray(); ++it)
{
LLUUID public_key = it->asUUID();
LLExperienceItem* item = new LLExperienceItem();
item->init(public_key);
mExperiencesList->addItem(item, public_key);
}
mExperiencesList->sort();
}
LLPanelExperiences* LLPanelExperiences::create(const std::string& name)
{
LLPanelExperiences* panel= new LLPanelExperiences();
panel->setName(name);
return panel;
}
void LLPanelExperiences::removeExperiences( const LLSD& ids )
{
LLSD::array_const_iterator it = ids.beginArray();
for( /**/ ; it != ids.endArray(); ++it)
{
removeExperience(it->asUUID());
}
}
void LLPanelExperiences::removeExperience( const LLUUID& id )
{
mExperiencesList->removeItemByUUID(id);
}
void LLPanelExperiences::addExperience( const LLUUID& id )
{
if(!mExperiencesList->getItemByValue(id))
{
LLExperienceItem* item = new LLExperienceItem();
item->init(id);
mExperiencesList->addItem(item, id);
mExperiencesList->sort();
}
}
void LLPanelExperiences::setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb )
{
if(label.empty())
{
getChild<LLLayoutPanel>("button_panel")->setVisible(false);
}
else
{
getChild<LLLayoutPanel>("button_panel")->setVisible(true);
LLButton* child = getChild<LLButton>("btn_action");
child->setCommitCallback(cb);
child->setLabel(getString(label));
}
}
void LLPanelExperiences::enableButton( bool enable )
{
getChild<LLButton>("btn_action")->setEnabled(enable);
}
LLExperienceItem::LLExperienceItem()
: mName(NULL)
{
buildFromFile("panel_experience_list_item.xml");
}
void LLExperienceItem::init( const LLUUID& id)
{
mName = getChild<LLUICtrl>("experience_name");
mName->setValue(LLSLURL("experience", id, "profile").getSLURLString());
}
LLExperienceItem::~LLExperienceItem()
{
}
std::string LLExperienceItem::getExperienceName() const
{
if (mName)
{
return mName->getValue();
}
return "";
}
void LLPanelSearchExperiences::doSearch()
{
}
LLPanelSearchExperiences* LLPanelSearchExperiences::create( const std::string& name )
{
LLPanelSearchExperiences* panel= new LLPanelSearchExperiences();
panel->getChild<LLPanel>("results")->addChild(LLPanelExperiences::create(name));
return panel;
}
BOOL LLPanelSearchExperiences::postBuild( void )
{
childSetAction("search_button", boost::bind(&LLPanelSearchExperiences::doSearch, this));
return TRUE;
}
bool LLExperienceItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
{
const LLExperienceItem* experience_item1 = dynamic_cast<const LLExperienceItem*>(item1);
const LLExperienceItem* experience_item2 = dynamic_cast<const LLExperienceItem*>(item2);
if (!experience_item1 || !experience_item2)
{
LL_ERRS() << "item1 and item2 cannot be null" << LL_ENDL;
return true;
}
std::string name1 = experience_item1->getExperienceName();
std::string name2 = experience_item2->getExperienceName();
LLStringUtil::toUpper(name1);
LLStringUtil::toUpper(name2);
return name1 < name2;
}

View File

@ -0,0 +1,97 @@
/**
* @file llpanelexperiences.h
* @brief LLPanelExperiences class definition
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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_LLPANELEXPERIENCES_H
#define LL_LLPANELEXPERIENCES_H
#include "llaccordionctrltab.h"
#include "llflatlistview.h"
#include "llpanelavatar.h"
class LLExperienceItem;
class LLPanelProfile;
class LLPanelSearchExperiences
: public LLPanel
{
public:
LLPanelSearchExperiences(){}
static LLPanelSearchExperiences* create(const std::string& name);
/*virtual*/ BOOL postBuild(void);
void doSearch();
};
class LLPanelExperiences
: public LLPanel
{
public:
LLPanelExperiences();
static LLPanelExperiences* create(const std::string& name);
/*virtual*/ BOOL postBuild(void);
/*virtual*/ void onClosePanel();
void setExperienceList(const LLSD& experiences);
LLExperienceItem* getSelectedExperienceItem();
void removeExperiences( const LLSD& ids );
void removeExperience( const LLUUID& id);
void addExperience( const LLUUID& id);
void setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb);
void enableButton(bool enable);
protected:
private:
LLFlatListView* mExperiencesList;
};
class LLExperienceItemComparator : public LLFlatListView::ItemComparator
{
LOG_CLASS(LLExperienceItemComparator);
public:
LLExperienceItemComparator() {};
virtual ~LLExperienceItemComparator() {};
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const;
};
class LLExperienceItem
: public LLPanel
{
public:
LLExperienceItem();
~LLExperienceItem();
void init(const LLUUID& experience_id);
std::string getExperienceName() const;
protected:
LLUICtrl* mName;
};
#endif // LL_LLPANELEXPERIENCES_H

View File

@ -190,11 +190,13 @@ BOOL LLPanelGroup::postBuild()
LLPanelGroupTab* panel_roles = findChild<LLPanelGroupTab>("group_roles_tab_panel");
LLPanelGroupTab* panel_notices = findChild<LLPanelGroupTab>("group_notices_tab_panel");
LLPanelGroupTab* panel_land = findChild<LLPanelGroupTab>("group_land_tab_panel");
LLPanelGroupTab* panel_experiences = findChild<LLPanelGroupTab>("group_experiences_tab_panel");
if(panel_general) mTabs.push_back(panel_general);
if(panel_roles) mTabs.push_back(panel_roles);
if(panel_notices) mTabs.push_back(panel_notices);
if(panel_land) mTabs.push_back(panel_land);
if(panel_experiences) mTabs.push_back(panel_experiences);
if(panel_general)
{
@ -447,6 +449,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
LLAccordionCtrlTab* tab_roles = getChild<LLAccordionCtrlTab>("group_roles_tab");
LLAccordionCtrlTab* tab_notices = getChild<LLAccordionCtrlTab>("group_notices_tab");
LLAccordionCtrlTab* tab_land = getChild<LLAccordionCtrlTab>("group_land_tab");
LLAccordionCtrlTab* tab_experiences = getChild<LLAccordionCtrlTab>("group_experiences_tab");
if(mButtonJoin)
mButtonJoin->setVisible(false);
@ -463,10 +466,13 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
tab_notices->changeOpenClose(tab_notices->getDisplayChildren());
if(tab_land->getDisplayChildren())
tab_land->changeOpenClose(tab_land->getDisplayChildren());
if(tab_experiences->getDisplayChildren())
tab_experiences->changeOpenClose(tab_land->getDisplayChildren());
tab_roles->setVisible(false);
tab_notices->setVisible(false);
tab_land->setVisible(false);
tab_experiences->setVisible(false);
getChild<LLUICtrl>("group_name")->setVisible(false);
getChild<LLUICtrl>("group_name_editor")->setVisible(true);
@ -488,6 +494,8 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
tab_notices->changeOpenClose(tab_notices->getDisplayChildren());
if(tab_land->getDisplayChildren())
tab_land->changeOpenClose(tab_land->getDisplayChildren());
if(tab_experiences->getDisplayChildren())
tab_experiences->changeOpenClose(tab_land->getDisplayChildren());
}
LLGroupData agent_gdatap;
@ -496,6 +504,7 @@ void LLPanelGroup::setGroupID(const LLUUID& group_id)
tab_roles->setVisible(is_member);
tab_notices->setVisible(is_member);
tab_land->setVisible(is_member);
tab_experiences->setVisible(is_member);
getChild<LLUICtrl>("group_name")->setVisible(true);
getChild<LLUICtrl>("group_name_editor")->setVisible(false);
@ -563,6 +572,7 @@ bool LLPanelGroup::apply()
&& apply(findChild<LLPanelGroupTab>("group_roles_tab_panel"))
&& apply(findChild<LLPanelGroupTab>("group_notices_tab_panel"))
&& apply(findChild<LLPanelGroupTab>("group_land_tab_panel"))
&& apply(findChild<LLPanelGroupTab>("group_experiences_tab_panel"))
;
}

View File

@ -0,0 +1,143 @@
/**
* @file llpanelgroupexperiences.cpp
* @brief List of experiences owned by a group.
*
* $LicenseInfo:firstyear=2006&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 "llviewerprecompiledheaders.h"
#include "llpanelgroupexperiences.h"
#include "lluictrlfactory.h"
#include "roles_constants.h"
#include "llhttpclient.h"
#include "llagent.h"
#include "llviewerregion.h"
#include "llflatlistview.h"
#include "llpanelexperiences.h"
#include "llsd.h"
static LLPanelInjector<LLPanelGroupExperiences> t_panel_group_experiences("panel_group_experiences");
class LLGroupExperienceResponder : public LLHTTPClient::Responder
{
public:
LLHandle<LLPanelGroupExperiences> mHandle;
LLGroupExperienceResponder(LLHandle<LLPanelGroupExperiences> handle) : mHandle(handle) { }
protected:
/*virtual*/ void httpSuccess()
{
if (mHandle.isDead())
{
return;
}
LLPanelGroupExperiences* panel = mHandle.get();
if (panel)
{
panel->setExperienceList(getContent().get("experience_ids"));
}
}
/*virtual*/ void httpFailure()
{
LL_WARNS() << "experience responder failed [status:" << getStatus() << "]: " << getContent() << LL_ENDL;
}
};
LLPanelGroupExperiences::LLPanelGroupExperiences()
: LLPanelGroupTab(), mExperiencesList(NULL)
{
}
LLPanelGroupExperiences::~LLPanelGroupExperiences()
{
}
BOOL LLPanelGroupExperiences::postBuild()
{
mExperiencesList = getChild<LLFlatListView>("experiences_list");
if (hasString("loading_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("loading_experiences"));
}
else if (hasString("no_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("no_experiences"));
}
return LLPanelGroupTab::postBuild();
}
void LLPanelGroupExperiences::activate()
{
if (getGroupID() == LLUUID::null)
{
return;
}
// search for experiences owned by the current group
std::string url = gAgent.getRegion()->getCapability("GroupExperiences");
if (!url.empty())
{
url += "?" + getGroupID().asString();
LLHTTPClient::get(url, new LLGroupExperienceResponder(getDerivedHandle<LLPanelGroupExperiences>()));
}
}
void LLPanelGroupExperiences::setGroupID(const LLUUID& id)
{
LLPanelGroupTab::setGroupID(id);
if(id == LLUUID::null)
{
return;
}
activate();
}
void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences)
{
if (hasString("no_experiences"))
{
mExperiencesList->setNoItemsCommentText(getString("no_experiences"));
}
mExperiencesList->clear();
LLSD::array_const_iterator it = experiences.beginArray();
for ( /**/ ; it != experiences.endArray(); ++it)
{
LLUUID public_key = it->asUUID();
LLExperienceItem* item = new LLExperienceItem();
item->init(public_key);
mExperiencesList->addItem(item, public_key);
}
}

View File

@ -0,0 +1,53 @@
/**
* @file llpanelgroupexperiences.h
* @brief List of experiences owned by a group.
*
* $LicenseInfo:firstyear=2006&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_LLPANELGROUPEXPERIENCES_H
#define LL_LLPANELGROUPEXPERIENCES_H
#include "llpanelgroup.h"
class LLFlatListView;
class LLPanelGroupExperiences : public LLPanelGroupTab
{
public:
LLPanelGroupExperiences();
virtual ~LLPanelGroupExperiences();
// LLPanelGroupTab
virtual void activate();
virtual BOOL postBuild();
virtual void setGroupID(const LLUUID& id);
void setExperienceList(const LLSD& experiences);
protected:
LLFlatListView* mExperiencesList;
};
#endif

View File

@ -131,6 +131,14 @@ public:
void createPick()
{
// <FS:Ansariel> FIRE-7694 / BUG-932 / MAINT-1999
if (LLAgentPicksInfo::getInstance()->isPickLimitReached())
{
LLNotificationsUtil::add("PickLimitReached");
return;
}
// </FS:Ansariel>
// open the new pick panel on the Picks floater
LLFloater* picks_floater = LLFloaterReg::showInstance("picks");

View File

@ -90,6 +90,9 @@
#include "llviewercontrol.h"
#include "llappviewer.h"
#include "llfloatergotoline.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
#include "llexperienceassociationresponder.h"
#include "llloadingindicator.h" // <FS:Kadah> Compile indicator
#include "lliconctrl.h" // <FS:Kadah> Compile indicator
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
@ -107,15 +110,15 @@
const std::string HELLO_LSL =
"default\n"
"{\n"
" state_entry()\n"
" {\n"
" llSay(0, \"Hello, Avatar!\");\n"
" }\n"
" state_entry()\n"
" {\n"
" llSay(0, \"Hello, Avatar!\");\n"
" }\n"
"\n"
" touch_start(integer total_number)\n"
" {\n"
" llSay(0, \"Touched.\");\n"
" }\n"
" touch_start(integer total_number)\n"
" {\n"
" llSay(0, \"Touched.\");\n"
" }\n"
"}\n";
const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal";
@ -132,6 +135,26 @@ static bool have_script_upload_cap(LLUUID& object_id)
return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty());
}
class ExperienceResponder : public LLHTTPClient::Responder
{
public:
ExperienceResponder(const LLHandle<LLLiveLSLEditor>& parent):mParent(parent)
{
}
LLHandle<LLLiveLSLEditor> mParent;
/*virtual*/ void httpSuccess()
{
LLLiveLSLEditor* parent = mParent.get();
if(!parent)
return;
parent->setExperienceIds(getContent()["experience_ids"]);
}
};
// [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2.0) | Added: Catznip-3.2.0
#include "lleventtimer.h"
@ -235,7 +258,7 @@ private:
protected:
LLLineEditor* mSearchBox;
LLLineEditor* mReplaceBox;
void onSearchBoxCommit();
void onSearchBoxCommit();
};
LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL;
@ -470,6 +493,54 @@ LLScriptEdCore::~LLScriptEdCore()
}
}
void LLLiveLSLEditor::experienceChanged()
{
if(mScriptEd->getAssociatedExperience() != mExperiences->getSelectedValue().asUUID())
{
mScriptEd->enableSave(getIsModifiable());
//getChildView("Save_btn")->setEnabled(TRUE);
mScriptEd->setAssociatedExperience(mExperiences->getSelectedValue().asUUID());
updateExperiencePanel();
}
}
void LLLiveLSLEditor::onViewProfile( LLUICtrl *ui, void* userdata )
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
LLUUID id;
if(self->mExperienceEnabled->get())
{
id=self->mScriptEd->getAssociatedExperience();
if(id.notNull())
{
LLFloaterReg::showInstance("experience_profile", id, true);
}
}
}
void LLLiveLSLEditor::onToggleExperience( LLUICtrl *ui, void* userdata )
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
LLUUID id;
if(self->mExperienceEnabled->get())
{
if(self->mScriptEd->getAssociatedExperience().isNull())
{
id=self->mExperienceIds.beginArray()->asUUID();
}
}
if(id != self->mScriptEd->getAssociatedExperience())
{
self->mScriptEd->enableSave(self->getIsModifiable());
}
self->mScriptEd->setAssociatedExperience(id);
self->updateExperiencePanel();
}
BOOL LLScriptEdCore::postBuild()
{
@ -1120,7 +1191,7 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS
case 2: // "Cancel"
default:
// If we were quitting, we didn't really mean it.
LLAppViewer::instance()->abortQuit();
LLAppViewer::instance()->abortQuit();
break;
}
return false;
@ -1155,8 +1226,8 @@ void LLScriptEdCore::onBtnDynamicHelp()
LLKeywordToken *token;
LLKeywords::keyword_iterator_t token_it;
for (token_it = mEditor->keywordsBegin();
token_it != mEditor->keywordsEnd();
++token_it)
token_it != mEditor->keywordsEnd();
++token_it)
{
token = token_it->second;
help_combo->add(wstring_to_utf8str(token->getToken()));
@ -1577,6 +1648,141 @@ bool LLScriptEdCore::enableLoadFromFileMenu(void* userdata)
return (self && self->mEditor) ? self->mEditor->canLoadOrSaveToFile() : FALSE;
}
LLUUID LLScriptEdCore::getAssociatedExperience()const
{
return mAssociatedExperience;
}
void LLLiveLSLEditor::setExperienceIds( const LLSD& experience_ids )
{
mExperienceIds=experience_ids;
updateExperiencePanel();
}
void LLLiveLSLEditor::updateExperiencePanel()
{
if(mScriptEd->getAssociatedExperience().isNull())
{
mExperienceEnabled->set(FALSE);
mExperiences->setVisible(FALSE);
if(mExperienceIds.size()>0)
{
mExperienceEnabled->setEnabled(TRUE);
mExperienceEnabled->setToolTip(getString("add_experiences"));
}
else
{
mExperienceEnabled->setEnabled(FALSE);
mExperienceEnabled->setToolTip(getString("no_experiences"));
}
getChild<LLButton>("view_profile")->setVisible(FALSE);
}
else
{
mExperienceEnabled->setToolTip(getString("experience_enabled"));
mExperienceEnabled->setEnabled(getIsModifiable());
mExperiences->setVisible(TRUE);
mExperienceEnabled->set(TRUE);
getChild<LLButton>("view_profile")->setToolTip(getString("show_experience_profile"));
buildExperienceList();
}
}
void LLLiveLSLEditor::buildExperienceList()
{
mExperiences->clearRows();
bool foundAssociated=false;
const LLUUID& associated = mScriptEd->getAssociatedExperience();
LLUUID last;
LLScrollListItem* item;
for(LLSD::array_const_iterator it = mExperienceIds.beginArray(); it != mExperienceIds.endArray(); ++it)
{
LLUUID id = it->asUUID();
EAddPosition position = ADD_BOTTOM;
if(id == associated)
{
foundAssociated = true;
position = ADD_TOP;
}
const LLSD& experience = LLExperienceCache::get(id);
if(experience.isUndefined())
{
mExperiences->add(getString("loading"), id, position);
last = id;
}
else
{
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
mExperiences->add(experience_name_string, id, position);
}
}
if(!foundAssociated )
{
const LLSD& experience = LLExperienceCache::get(associated);
if(experience.isDefined())
{
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
item=mExperiences->add(experience_name_string, associated, ADD_TOP);
}
else
{
item=mExperiences->add(getString("loading"), associated, ADD_TOP);
last = associated;
}
item->setEnabled(FALSE);
}
if(last.notNull())
{
mExperiences->setEnabled(FALSE);
LLExperienceCache::get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this));
}
else
{
mExperiences->setEnabled(TRUE);
getChild<LLButton>("view_profile")->setVisible(TRUE);
}
}
void LLScriptEdCore::setAssociatedExperience( const LLUUID& experience_id )
{
mAssociatedExperience = experience_id;
}
void LLLiveLSLEditor::requestExperiences()
{
if (!getIsModifiable())
{
return;
}
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
{
LLHTTPClient::get(lookup_url, new ExperienceResponder(getDerivedHandle<LLLiveLSLEditor>()));
}
}
}
/// ---------------------------------------------------------------------------
/// LLScriptEdContainer
/// ---------------------------------------------------------------------------
@ -1659,7 +1865,7 @@ std::string LLScriptEdContainer::getTmpFileName()
std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString();
// Use MD5 sum to make the file name shorter and not exceed maximum path length.
char script_id_hash_str[33]; /* Flawfinder: ignore */
char script_id_hash_str[33]; /* Flawfinder: ignore */
LLMD5 script_id_hash((const U8 *)script_id.c_str());
script_id_hash.hex_digest(script_id_hash_str);
@ -2288,6 +2494,16 @@ BOOL LLLiveLSLEditor::postBuild()
mScriptEd->mEditor->makePristine();
mScriptEd->mEditor->setFocus(TRUE);
mExperiences = getChild<LLComboBox>("Experiences...");
mExperiences->setCommitCallback(boost::bind(&LLLiveLSLEditor::experienceChanged, this));
mExperienceEnabled = getChild<LLCheckBoxCtrl>("enable_xp");
childSetCommitCallback("enable_xp", onToggleExperience, this);
childSetCommitCallback("view_profile", onViewProfile, this);
return LLPreview::postBuild();
}
@ -2359,61 +2575,60 @@ void LLLiveLSLEditor::loadAsset()
if(object)
{
LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(object->getInventoryObject(mItemUUID));
if(item
&& (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
|| gAgent.isGodlike()))
{
mItem = new LLViewerInventoryItem(item);
//LL_INFOS() << "asset id " << mItem->getAssetUUID() << LL_ENDL;
}
if(!gAgent.isGodlike()
&& (item
&& (!gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE)
|| !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))))
if(item)
{
mItem = new LLViewerInventoryItem(item);
mScriptEd->setScriptText(getString("not_allowed"), FALSE);
mScriptEd->mEditor->makePristine();
mScriptEd->enableSave(FALSE);
mAssetStatus = PREVIEW_ASSET_LOADED;
}
else if(item && mItem.notNull())
{
// request the text from the object
ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle<LLLiveLSLEditor>(), _1));
bool isGodlike = gAgent.isGodlike();
bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE);
mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE);
if(!isGodlike && (!copyManipulate || !mIsModifiable))
{
mItem = new LLViewerInventoryItem(item);
mScriptEd->setScriptText(getString("not_allowed"), FALSE);
mScriptEd->mEditor->makePristine();
mScriptEd->enableSave(FALSE);
mAssetStatus = PREVIEW_ASSET_LOADED;
}
else if(copyManipulate || isGodlike)
{
mItem = new LLViewerInventoryItem(item);
// request the text from the object
LLSD* user_data = new LLSD();
user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);
gAssetStorage->getInvItemAsset(object->getRegion()->getHost(),
gAgent.getID(),
gAgent.getSessionID(),
item->getPermissions().getOwner(),
object->getID(),
item->getUUID(),
item->getAssetUUID(),
item->getType(),
&LLLiveLSLEditor::onLoadComplete,
(void*)user_data,
TRUE);
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_GetScriptRunning);
msg->nextBlockFast(_PREHASH_Script);
msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID);
msg->addUUIDFast(_PREHASH_ItemID, mItemUUID);
msg->sendReliable(object->getRegion()->getHost());
mAskedForRunningInfo = TRUE;
mAssetStatus = PREVIEW_ASSET_LOADING;
gAssetStorage->getInvItemAsset(object->getRegion()->getHost(),
gAgent.getID(),
gAgent.getSessionID(),
item->getPermissions().getOwner(),
object->getID(),
item->getUUID(),
item->getAssetUUID(),
item->getType(),
&LLLiveLSLEditor::onLoadComplete,
(void*)user_data,
TRUE);
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_GetScriptRunning);
msg->nextBlockFast(_PREHASH_Script);
msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID);
msg->addUUIDFast(_PREHASH_ItemID, mItemUUID);
msg->sendReliable(object->getRegion()->getHost());
mAskedForRunningInfo = TRUE;
mAssetStatus = PREVIEW_ASSET_LOADING;
}
}
else
if(mItem.isNull())
{
mScriptEd->setScriptText(LLStringUtil::null, FALSE);
mScriptEd->mEditor->makePristine();
mAssetStatus = PREVIEW_ASSET_LOADED;
mIsModifiable = FALSE;
}
mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY,
item->getPermissions(),
GP_OBJECT_MANIPULATE);
refreshFromItem();
// This is commented out, because we don't completely
// handle script exports yet.
/*
@ -2450,6 +2665,8 @@ void LLLiveLSLEditor::loadAsset()
time_corrected());
mAssetStatus = PREVIEW_ASSET_LOADED;
}
requestExperiences();
}
// static
@ -2761,7 +2978,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/)
BOOL is_running = getChild<LLCheckBoxCtrl>( "running")->get();
if (!url.empty())
{
uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running);
uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running, mScriptEd->getAssociatedExperience());
}
else if (gAssetStorage)
{
@ -2790,7 +3007,8 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const LLUUID& task_id,
const LLUUID& item_id,
BOOL is_running)
BOOL is_running,
const LLUUID& experience_public_id )
{
LL_INFOS() << "Update Task Inventory via capability " << url << LL_ENDL;
LLSD body;
@ -2798,6 +3016,7 @@ void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
body["item_id"] = item_id;
body["is_script_running"] = is_running;
body["target"] = monoChecked() ? "mono" : "lsl2";
body["experience"] = experience_public_id;
LLHTTPClient::post(url, body,
new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT));
}
@ -3076,3 +3295,18 @@ BOOL LLLiveLSLEditor::monoChecked() const
}
return FALSE;
}
void LLLiveLSLEditor::setAssociatedExperience( LLHandle<LLLiveLSLEditor> editor, const LLSD& experience )
{
LLLiveLSLEditor* scriptEd = editor.get();
if(scriptEd)
{
LLUUID id;
if(experience.has(LLExperienceCache::EXPERIENCE_ID))
{
id=experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
scriptEd->mScriptEd->setAssociatedExperience(id);
scriptEd->updateExperiencePanel();
}
}

View File

@ -52,6 +52,7 @@ class LLVFS;
class LLViewerInventoryItem;
class LLScriptEdContainer;
class LLFloaterGotoLine;
class LLFloaterExperienceProfile;
// [SL:KB] - Patch: Build-ScriptRecover | Checked: 2011-11-23 (Catznip-3.2.0)
class LLEventTimer;
// [/SL:KB]
@ -127,13 +128,15 @@ public:
static void onBtnInsertSample(void*);
static void onBtnInsertFunction(LLUICtrl*, void*);
static void onBtnLoadFromFile(void*);
static void onBtnSaveToFile(void*);
static void onBtnSaveToFile(void*);
static void onBtnPrefs(void*); // <FS:CR> Advanced Script Editor
static bool enableSaveToFileMenu(void* userdata);
static bool enableLoadFromFileMenu(void* userdata);
virtual bool hasAccelerators() const { return true; }
virtual bool hasAccelerators() const { return true; }
LLUUID getAssociatedExperience()const;
void setAssociatedExperience( const LLUUID& experience_id );
void setScriptName(const std::string& name){mScriptName = name;};
@ -182,8 +185,8 @@ private:
void (*mSaveCallback)(void* userdata, BOOL close_after_save, bool sync);
// </FS:Ansariel>
void (*mSearchReplaceCallback) (void* userdata);
void* mUserdata;
LLComboBox *mFunctions;
void* mUserdata;
LLComboBox *mFunctions;
BOOL mForceClose;
LLPanel* mCodePanel;
LLScrollListCtrl* mErrorList;
@ -195,6 +198,7 @@ private:
BOOL mEnableSave;
BOOL mHasScriptData;
LLLiveLSLFile* mLiveFile;
LLUUID mAssociatedExperience;
LLTextBox* mLineCol;
// <FS:CR> Advanced Script Editor
//LLView* mSaveBtn;
@ -324,7 +328,7 @@ public:
/*virtual*/ BOOL postBuild();
void setIsNew() { mIsNew = TRUE; }
void setIsNew() { mIsNew = TRUE; }
// <FS:TT> Client LSL Bridge
static void uploadAssetViaCapsStatic(const std::string& url,
const std::string& filename,
@ -338,6 +342,17 @@ public:
LLScriptEditor* getEditor() { return (mScriptEd) ? mScriptEd->mEditor : NULL; }
// [/SL:KB]
static void setAssociatedExperience( LLHandle<LLLiveLSLEditor> editor, const LLSD& experience );
static void onToggleExperience(LLUICtrl *ui, void* userdata);
static void onViewProfile(LLUICtrl *ui, void* userdata);
void setExperienceIds(const LLSD& experience_ids);
void buildExperienceList();
void updateExperiencePanel();
void requestExperiences();
void experienceChanged();
void addAssociatedExperience(const LLSD& experience);
private:
virtual BOOL canClose();
void closeIfNeeded();
@ -347,10 +362,11 @@ private:
void loadAsset(BOOL is_new);
/*virtual*/ void saveIfNeeded(bool sync = true);
void uploadAssetViaCaps(const std::string& url,
const std::string& filename,
const std::string& filename,
const LLUUID& task_id,
const LLUUID& item_id,
BOOL is_running);
BOOL is_running,
const LLUUID& experience_public_id);
void uploadAssetLegacy(const std::string& filename,
LLViewerObject* object,
const LLTransactionID& tid,
@ -394,9 +410,16 @@ private:
S32 mPendingUploads;
BOOL getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert
LLCheckBoxCtrl* mMonoCheckbox;
BOOL mIsModifiable;
LLComboBox* mExperiences;
LLCheckBoxCtrl* mExperienceEnabled;
LLSD mExperienceIds;
LLHandle<LLFloater> mExperienceProfile;
};
#endif // LL_LLPREVIEWSCRIPT_H

View File

@ -66,6 +66,22 @@ const F32 SECONDS_TO_SHOW_FILE_SAVED_MSG = 8.f;
const F32 PREVIEW_TEXTURE_MAX_ASPECT = 200.f;
const F32 PREVIEW_TEXTURE_MIN_ASPECT = 0.005f;
// <FS:Ansariel> FIRE-14111: File extension missing on Linux when saving a texture
std::string checkFileExtension(const std::string& filename, LLPreviewTexture::EFileformatType format)
{
std::string tmp_name = filename;
std::string extension = (format == LLPreviewTexture::FORMAT_TGA ? ".tga" : ".png");
LLStringUtil::toLower(tmp_name);
size_t result = tmp_name.rfind(extension);
if (result == std::string::npos || result != tmp_name.length() - extension.size())
{
return (filename + extension);
}
return filename;
}
// </FS:Ansariel>
LLPreviewTexture::LLPreviewTexture(const LLSD& key)
: LLPreview((key.has("uuid") ? key.get("uuid") : key)), // Changed for texture preview mode
@ -390,7 +406,10 @@ void LLPreviewTexture::saveAs(EFileformatType format)
break;
}
if( !file_picker.getSaveFile( saveFilter, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) )
// <FS:Ansariel> FIRE-14111: File extension missing on Linux when saving a texture
//if( !file_picker.getSaveFile( saveFilter, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) )
if( !file_picker.getSaveFile( saveFilter, item ? checkFileExtension(LLDir::getScrubbedFileName(item->getName()), format) : LLStringUtil::null) )
// </FS:Ansariel>
{
// User canceled or we failed to acquire save file.
return;
@ -402,7 +421,10 @@ void LLPreviewTexture::saveAs(EFileformatType format)
}
// remember the user-approved/edited file name.
mSaveFileName = file_picker.getFirstFile();
// <FS:Ansariel> FIRE-14111: File extension missing on Linux when saving a texture
//mSaveFileName = file_picker.getFirstFile();
mSaveFileName = checkFileExtension(file_picker.getFirstFile(), format);
// </FS:Ansariel>
mLoadingFullImage = TRUE;
getWindow()->incBusyCount();

View File

@ -582,19 +582,23 @@ void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel)
{
std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), id);
LLPanel* panel_to_delete = panel;
if( it != mToastList.end() && panel)
{
LLToast* toast = it->getToast();
if (toast)
{
LLPanel* old_panel = toast->getPanel();
toast->removeChild(old_panel);
delete old_panel;
toast->insertPanel(panel);
toast->startTimer();
LLPanel* old_panel = toast->getPanel();
toast->removeChild(old_panel);
panel_to_delete = old_panel;
toast->insertPanel(panel);
toast->startTimer();
}
redrawToasts();
}
delete panel_to_delete;
}
//--------------------------------------------------------------------------

View File

@ -44,6 +44,9 @@
#include "llviewercontrol.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
#include "llexperienceassociationresponder.h"
#include "llexperiencecache.h"
#include "lltrans.h"
// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a)
#include "rlvhandler.h"
// [/RLVa:KB]
@ -321,6 +324,15 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
is_obj_modify = object->permOwnerModify();
}
if(item->getInventoryType() == LLInventoryType::IT_LSL)
{
getChildView("LabelItemExperienceTitle")->setVisible(TRUE);
LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience");
tb->setText(getString("loading_experience"));
tb->setVisible(TRUE);
ExperienceAssociationResponder::fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), boost::bind(&LLSidepanelItemInfo::setAssociatedExperience, getDerivedHandle<LLSidepanelItemInfo>(), _1));
}
//////////////////////
// ITEM NAME & DESC //
//////////////////////
@ -691,6 +703,29 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
}
}
void LLSidepanelItemInfo::setAssociatedExperience( LLHandle<LLSidepanelItemInfo> hInfo, const LLSD& experience )
{
LLSidepanelItemInfo* info = hInfo.get();
if(info)
{
LLUUID id;
if(experience.has(LLExperienceCache::EXPERIENCE_ID))
{
id=experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
if(id.notNull())
{
info->getChild<LLTextBox>("LabelItemExperience")->setText(LLSLURL("experience", id, "profile").getSLURLString());
}
else
{
info->getChild<LLTextBox>("LabelItemExperience")->setText(LLTrans::getString("ExperienceNameNull"));
}
}
}
void LLSidepanelItemInfo::startObjectInventoryObserver()
{
if (!mObjectInventoryObserver)

View File

@ -67,6 +67,8 @@ protected:
void refreshFromItem(LLViewerInventoryItem* item);
private:
static void setAssociatedExperience( LLHandle<LLSidepanelItemInfo> hInfo, const LLSD& experience );
void startObjectInventoryObserver();
void stopObjectInventoryObserver();

View File

@ -48,6 +48,7 @@
#include "llares.h"
#include "llavatarnamecache.h"
#include "llexperiencecache.h"
#include "lllandmark.h"
#include "llcachename.h"
#include "lldir.h"
@ -201,6 +202,7 @@
#include "llevents.h"
#include "llstartuplistener.h"
#include "lltoolbarview.h"
#include "llexperiencelog.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@ -1779,6 +1781,9 @@ LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim, first_sim_size_x,
// object is created. I think this must be done after setting the region. JC
gAgent.setPositionAgent(agent_start_position_region);
display_startup();
LLStartUp::initExperiences();
display_startup();
LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
@ -3539,6 +3544,14 @@ void LLStartUp::initNameCache()
LLAvatarName::setTrimResidentSurname(gSavedSettings.getBOOL("FSTrimLegacyNames"));
}
void LLStartUp::initExperiences()
{
LLAppViewer::instance()->loadExperienceCache();
LLExperienceCache::initClass();
LLExperienceLog::instance().initialize();
}
void LLStartUp::cleanupNameCache()
{
LLAvatarNameCache::cleanupClass();
@ -4429,3 +4442,4 @@ void transition_back_to_login_panel(const std::string& emsg)
reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW );
gSavedSettings.setBOOL("AutoLogin", FALSE);
}

View File

@ -110,6 +110,7 @@ public:
static void fontInit();
static void initNameCache();
static void initExperiences();
static void cleanupNameCache();

View File

@ -50,7 +50,7 @@
const S32 BOTTOM_PAD = VPAD * 3;
const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding
S32 BUTTON_WIDTH = 90;
// *TODO: magic numbers(?) - copied from llnotify.cpp(250)
// *TODO: magic numbers - copied from llnotify.cpp(250)
const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE;

View File

@ -61,6 +61,9 @@
#include "llfloatereditsky.h"
#include "llfloatereditwater.h"
#include "llfloaterenvironmentsettings.h"
#include "llfloaterexperienceprofile.h"
#include "llfloaterexperiences.h"
#include "llfloaterexperiencepicker.h"
#include "llfloaterevent.h"
#include "llfloaterfacebook.h"
#include "llfloaterflickr.h"
@ -262,8 +265,11 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("env_edit_water", "floater_edit_water_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditWater>);
LLFloaterReg::add("env_edit_day_cycle", "floater_edit_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditDayCycle>);
LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>);
LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>);
LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>);
LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>);
LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>);
LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>);
LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>);

View File

@ -196,7 +196,7 @@ private:
// 500 means "Internal Server error" but we decided it's okay to
// accept this and go past it in the MIME type probe
// 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com
// 499 is a code specifc to join.secondlife.com (?) apparently safe to ignore
// 499 is a code specifc to join.secondlife.com apparently safe to ignore
// if( ((status >= 200) && (status < 300)) ||
// ((status >= 400) && (status < 499)) ||
// (status == 500) ||

View File

@ -119,8 +119,13 @@
#include "llviewerregion.h"
#include "llfloaterregionrestarting.h"
#include <boost/algorithm/string/split.hpp> //
#include <boost/regex.hpp>
#include "llnotificationmanager.h" //
#include "llexperiencecache.h"
// Firestorm inclues
#include <boost/algorithm/string/split.hpp>
#include "animationexplorer.h" // <FS:Zi> Animation Explorer
#include "fsareasearch.h"
#include "fscommon.h"
@ -134,7 +139,6 @@
#include "llfloaterbump.h"
#include "llfloaterreg.h"
#include "llgiveinventory.h"
#include "llnotificationmanager.h"
#include "lltexturefetch.h"
#include "rlvactions.h"
#include "rlvhandler.h"
@ -168,6 +172,7 @@ extern bool gShiftFrame;
bool check_offer_throttle(const std::string& from_name, bool check_only);
bool check_asset_previewable(const LLAssetType::EType asset_type);
static void process_money_balance_reply_extended(LLMessageSystem* msg);
bool handle_trusted_experiences_notification(const LLSD&);
//inventory offer throttle globals
LLFrameTimer gThrottleTimer;
@ -7158,108 +7163,33 @@ bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD&
// some of the server notifications need special handling. This is where we do that.
bool handle_special_notification(std::string notificationID, LLSD& llsdBlock)
{
U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger());
std::string regionMaturity = LLViewerRegion::accessToString(regionAccess);
LLStringUtil::toLower(regionMaturity);
llsdBlock["REGIONMATURITY"] = regionMaturity;
bool returnValue = false;
LLNotificationPtr maturityLevelNotification;
std::string notifySuffix = "_Notify";
if (regionAccess == SIM_ACCESS_MATURE)
if(llsdBlock.has("_region_access"))
{
if (gAgent.isTeen())
{
gAgent.clearTeleportRequest();
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG())
{
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0)
{
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock);
returnValue = true;
}
}
else if (regionAccess == SIM_ACCESS_ADULT)
{
if (!gAgent.isAdult())
{
gAgent.clearTeleportRequest();
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG() || gAgent.prefersMature())
{
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0)
{
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock);
returnValue = true;
}
}
if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored())
{
// Given a simple notification if no maturityLevelNotification is set or it is ignore
LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock);
}
return returnValue;
}
// some of the server notifications need special handling. This is where we do that.
bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage)
{
U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger());
std::string regionMaturity = LLViewerRegion::accessToString(regionAccess);
LLStringUtil::toLower(regionMaturity);
llsdBlock["REGIONMATURITY"] = regionMaturity;
bool returnValue = false;
LLNotificationPtr tp_failure_notification;
std::string notifySuffix;
if (notificationID == std::string("TeleportEntryAccessBlocked"))
{
notifySuffix = "_Notify";
U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger());
std::string regionMaturity = LLViewerRegion::accessToString(regionAccess);
LLStringUtil::toLower(regionMaturity);
llsdBlock["REGIONMATURITY"] = regionMaturity;
LLNotificationPtr maturityLevelNotification;
std::string notifySuffix = "_Notify";
if (regionAccess == SIM_ACCESS_MATURE)
{
if (gAgent.isTeen())
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG())
{
if (gAgent.hasRestartableFailedTeleportRequest())
{
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback);
returnValue = true;
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
else
else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0)
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock);
returnValue = true;
}
}
@ -7268,54 +7198,157 @@ bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notific
if (!gAgent.isAdult())
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG() || gAgent.prefersMature())
{
if (gAgent.hasRestartableFailedTeleportRequest())
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0)
{
maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock);
returnValue = true;
}
}
if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored())
{
// Given a simple notification if no maturityLevelNotification is set or it is ignore
LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock);
}
}
return returnValue;
}
bool handle_trusted_experiences_notification(const LLSD& llsdBlock)
{
if(llsdBlock.has("trusted_experiences"))
{
std::ostringstream str;
const LLSD& experiences = llsdBlock["trusted_experiences"];
LLSD::array_const_iterator it = experiences.beginArray();
for(/**/; it != experiences.endArray(); ++it)
{
str<<LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n";
}
std::string str_list = str.str();
if(!str_list.empty())
{
LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list));
return true;
}
}
return false;
}
// some of the server notifications need special handling. This is where we do that.
bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string & notificationID, const std::string & defaultMessage)
{
bool returnValue = false;
if(llsdBlock.has("_region_access"))
{
U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger());
std::string regionMaturity = LLViewerRegion::accessToString(regionAccess);
LLStringUtil::toLower(regionMaturity);
llsdBlock["REGIONMATURITY"] = regionMaturity;
LLNotificationPtr tp_failure_notification;
std::string notifySuffix;
if (notificationID == std::string("TeleportEntryAccessBlocked"))
{
notifySuffix = "_Notify";
if (regionAccess == SIM_ACCESS_MATURE)
{
if (gAgent.isTeen())
{
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback);
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG())
{
if (gAgent.hasRestartableFailedTeleportRequest())
{
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback);
returnValue = true;
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
}
else if (regionAccess == SIM_ACCESS_ADULT)
{
if (!gAgent.isAdult())
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock);
returnValue = true;
notifySuffix = "_NotifyAdultsOnly";
}
else if (gAgent.prefersPG() || gAgent.prefersMature())
{
if (gAgent.hasRestartableFailedTeleportRequest())
{
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback);
returnValue = true;
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
}
}
} // End of special handling for "TeleportEntryAccessBlocked"
else
{ // Normal case, no message munging
gAgent.clearTeleportRequest();
if (LLNotifications::getInstance()->templateExists(notificationID))
{
tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock);
}
else
{
gAgent.clearTeleportRequest();
tp_failure_notification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback);
returnValue = true;
llsdBlock["MESSAGE"] = defaultMessage;
tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock);
}
}
} // End of special handling for "TeleportEntryAccessBlocked"
else
{ // Normal case, no message munging
gAgent.clearTeleportRequest();
if (LLNotifications::getInstance()->templateExists(notificationID))
{
tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock);
returnValue = true;
}
else
if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored())
{
llsdBlock["MESSAGE"] = defaultMessage;
tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock);
// Given a simple notification if no tp_failure_notification is set or it is ignore
LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock);
}
returnValue = true;
}
if ((tp_failure_notification == NULL) || tp_failure_notification->isIgnored())
{
// Given a simple notification if no tp_failure_notification is set or it is ignore
LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock);
}
handle_trusted_experiences_notification(llsdBlock);
return returnValue;
}
@ -7346,6 +7379,9 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)
}
}
handle_trusted_experiences_notification(llsdBlock);
if (
(notificationID == "RegionEntryAccessBlocked") ||
(notificationID == "LandClaimAccessBlocked") ||
@ -7565,8 +7601,8 @@ void process_alert_core(const std::string& message, BOOL modal)
std::string alert_name(message.substr(ALERT_PREFIX.length()));
if (!handle_special_alerts(alert_name))
{
LLNotificationsUtil::add(alert_name);
}
LLNotificationsUtil::add(alert_name);
}
}
else if (message.find(NOTIFY_PREFIX) == 0)
{
@ -7655,7 +7691,7 @@ void process_alert_core(const std::string& message, BOOL modal)
LLFloaterRegionRestarting::close();
}
std::string new_msg =LLNotifications::instance().getGlobalString(text);
std::string new_msg =LLNotifications::instance().getGlobalString(text);
// [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5
if ( (new_msg == text) && (rlv_handler_t::isEnabled()) )
{
@ -7665,9 +7701,9 @@ void process_alert_core(const std::string& message, BOOL modal)
RlvUtil::filterNames(new_msg);
}
// [/RLVa:KB]
args["MESSAGE"] = new_msg;
LLNotificationsUtil::add("SystemMessage", args);
}
args["MESSAGE"] = new_msg;
LLNotificationsUtil::add("SystemMessage", args);
}
else if (modal)
{
LLSD args;
@ -8067,6 +8103,12 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
return false;
}
LLUUID experience;
if(notification["payload"].has("experience"))
{
experience = notification["payload"]["experience"].asUUID();
}
// check whether permissions were granted or denied
BOOL allowed = TRUE;
// the "yes/accept" button is the first button in the template, making it button 0
@ -8076,6 +8118,16 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
new_questions = 0;
allowed = FALSE;
}
else if(experience.notNull())
{
LLSD permission;
LLSD data;
permission["permission"]="Allow";
data[experience.asString()]=permission;
data["experience"]=experience;
LLEventPumps::instance().obtain("experience_permission").post(data);
}
LLUUID task_id = notification["payload"]["task_id"].asUUID();
LLUUID item_id = notification["payload"]["item_id"].asUUID();
@ -8112,7 +8164,27 @@ bool script_question_cb(const LLSD& notification, const LLSD& response)
{
script_question_mute(task_id,notification["payload"]["object_name"].asString());
}
if ( response["BlockExperience"] )
{
if(experience.notNull())
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return false;
std::string lookup_url=region->getCapability("ExperiencePreferences");
if(lookup_url.empty())
return false;
LLSD permission;
LLSD data;
permission["permission"]="Block";
data[experience.asString()]=permission;
LLHTTPClient::put(lookup_url, data, NULL);
data["experience"]=experience;
LLEventPumps::instance().obtain("experience_permission").post(data);
}
}
return false;
}
@ -8145,8 +8217,24 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name)
static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb);
static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb);
static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestionExperience", script_question_cb);
static LLNotificationFunctorRegistration unknown_script_question_cb_reg("UnknownScriptQuestion", unknown_script_question_cb);
void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload)
{
if(experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID)
{
args["GRID_WIDE"] = LLTrans::getString("Grid-Scope");
}
else
{
args["GRID_WIDE"] = LLTrans::getString("Land-Scope");
}
args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString();
LLNotificationsUtil::add("ScriptQuestionExperience", args, payload);
}
void process_script_question(LLMessageSystem *msg, void **user_data)
{
// *TODO: Translate owner name -> [FIRST] [LAST]
@ -8158,6 +8246,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
S32 questions;
std::string object_name;
std::string owner_name;
LLUUID experienceid;
// taskid -> object key of object requesting permissions
msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid );
@ -8175,6 +8264,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name);
msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions );
if(msg->has(_PREHASH_Experience))
{
msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid);
}
// Special case. If the objects are owned by this agent, throttle per-object instead
// of per-owner. It's common for residents to reset a ton of scripts that re-request
// permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa,
@ -8261,6 +8355,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
payload["owner_name"] = owner_name;
// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7)
const char* notification = "ScriptQuestion";
if (rlv_handler_t::isEnabled())
{
RlvUtil::filterScriptQuestions(questions, payload);
@ -8289,23 +8384,24 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
LLNotifications::instance().forceResponse(
LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/);
}
else if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
else if (caution && gSavedSettings.getBOOL("PermissionsCautionEnabled"))
// [/RLVa:KB]
// check whether cautions are even enabled or not
// if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
//const char* notification = "ScriptQuestion";
//if(caution && gSavedSettings.getBOOL("PermissionsCautionEnabled"))
{
if (caution)
{
args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : "";
}
// display the caution permissions prompt
LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload);
args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + "\n\n" + script_question : "";
notification = "ScriptQuestionCaution";
}
else
else if(experienceid.notNull())
{
// fall back to default behavior if cautions are entirely disabled
LLNotificationsUtil::add("ScriptQuestion", args, payload);
payload["experience"]=experienceid;
LLExperienceCache::get(experienceid, boost::bind(process_script_experience_details, _1, args, payload));
return;
}
LLNotificationsUtil::add(notification, args, payload);
}
}
}

View File

@ -236,8 +236,8 @@ void LLViewerParcelMgr::dump()
mCurrentParcel->dump();
LL_INFOS() << "banning " << mCurrentParcel->mBanList.size() << LL_ENDL;
access_map_const_iterator cit = mCurrentParcel->mBanList.begin();
access_map_const_iterator end = mCurrentParcel->mBanList.end();
LLAccessEntry::map::const_iterator cit = mCurrentParcel->mBanList.begin();
LLAccessEntry::map::const_iterator end = mCurrentParcel->mBanList.end();
for ( ; cit != end; ++cit)
{
LL_INFOS() << "ban id " << (*cit).first << LL_ENDL;
@ -754,7 +754,8 @@ bool LLViewerParcelMgr::allowAgentScripts(const LLViewerRegion* region, const LL
bool LLViewerParcelMgr::allowAgentDamage(const LLViewerRegion* region, const LLParcel* parcel) const
{
return (region && region->getAllowDamage())
&& (parcel && parcel->getAllowDamage());
//&& (parcel && parcel->getAllowDamage());
|| (parcel && parcel->getAllowDamage()); // <FS:LO> FIRE-16112 fix
}
BOOL LLViewerParcelMgr::isOwnedAt(const LLVector3d& pos_global) const
@ -941,7 +942,7 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
if (!region) return;
LLMessageSystem *msg = gMessageSystem;
if (flags & AL_BAN)
{
@ -951,6 +952,14 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
{
mCurrentParcel->mAccessList.clear();
}
if (flags & AL_ALLOW_EXPERIENCE)
{
mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED);
}
if (flags & AL_BLOCK_EXPERIENCE)
{
mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED);
}
// Only the headers differ
msg->newMessageFast(_PREHASH_ParcelAccessListRequest);
@ -1735,7 +1744,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
}
// Request access list information for this land
parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN);
parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_ALLOW_EXPERIENCE | AL_BLOCK_EXPERIENCE);
// Request dwell for this land, if it's not public land.
parcel_mgr.mSelectedDwell = DWELL_NAN;
@ -1925,6 +1934,14 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void
{
parcel->unpackAccessEntries(msg, &(parcel->mBanList) );
}
else if (message_flags & AL_ALLOW_EXPERIENCE)
{
parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_ALLOWED);
}
else if (message_flags & AL_BLOCK_EXPERIENCE)
{
parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_BLOCKED);
}
/*else if (message_flags & AL_RENTER)
{
parcel->unpackAccessEntries(msg, &(parcel->mRenterList) );
@ -1959,10 +1976,6 @@ void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**)
void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which)
{
LLUUID transactionUUID;
transactionUUID.generate();
if (!mSelected)
{
return;
@ -1971,125 +1984,92 @@ void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which)
LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth );
if (!region) return;
LLMessageSystem* msg = gMessageSystem;
LLParcel* parcel = mCurrentParcel;
if (!parcel) return;
if (which & AL_ACCESS)
{
S32 count = parcel->mAccessList.size();
S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
S32 sequence_id = 1;
BOOL start_message = TRUE;
BOOL initial = TRUE;
access_map_const_iterator cit = parcel->mAccessList.begin();
access_map_const_iterator end = parcel->mAccessList.end();
while ( (cit != end) || initial )
{
if (start_message)
{
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, AL_ACCESS);
msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
msg->addS32Fast(_PREHASH_Sections, num_sections);
start_message = FALSE;
if (initial && (cit == end))
{
// pack an empty block if there will be no data
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
msg->addS32Fast(_PREHASH_Time, 0 );
msg->addU32Fast(_PREHASH_Flags, 0 );
}
initial = FALSE;
sequence_id++;
}
while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
{
const LLAccessEntry& entry = (*cit).second;
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, entry.mID );
msg->addS32Fast(_PREHASH_Time, entry.mTime );
msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
++cit;
}
start_message = TRUE;
msg->sendReliable( region->getHost() );
}
sendParcelAccessListUpdate(AL_ACCESS, parcel->mAccessList, region, parcel->getLocalID());
}
if (which & AL_BAN)
{
S32 count = parcel->mBanList.size();
S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
S32 sequence_id = 1;
BOOL start_message = TRUE;
BOOL initial = TRUE;
sendParcelAccessListUpdate(AL_BAN, parcel->mBanList, region, parcel->getLocalID());
}
access_map_const_iterator cit = parcel->mBanList.begin();
access_map_const_iterator end = parcel->mBanList.end();
while ( (cit != end) || initial )
{
if (start_message)
{
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, AL_BAN);
msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
msg->addS32Fast(_PREHASH_Sections, num_sections);
start_message = FALSE;
if (initial && (cit == end))
{
// pack an empty block if there will be no data
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
msg->addS32Fast(_PREHASH_Time, 0 );
msg->addU32Fast(_PREHASH_Flags, 0 );
}
initial = FALSE;
sequence_id++;
}
while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
{
const LLAccessEntry& entry = (*cit).second;
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, entry.mID );
msg->addS32Fast(_PREHASH_Time, entry.mTime );
msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
++cit;
}
start_message = TRUE;
msg->sendReliable( region->getHost() );
}
if(which & AL_ALLOW_EXPERIENCE)
{
sendParcelAccessListUpdate(AL_ALLOW_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED), region, parcel->getLocalID());
}
if(which & AL_BLOCK_EXPERIENCE)
{
sendParcelAccessListUpdate(AL_BLOCK_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED), region, parcel->getLocalID());
}
}
void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 flags, const LLAccessEntry::map& entries, LLViewerRegion* region, S32 parcel_local_id)
{
S32 count = entries.size();
S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET);
S32 sequence_id = 1;
BOOL start_message = TRUE;
BOOL initial = TRUE;
LLUUID transactionUUID;
transactionUUID.generate();
LLMessageSystem* msg = gMessageSystem;
LLAccessEntry::map::const_iterator cit = entries.begin();
LLAccessEntry::map::const_iterator end = entries.end();
while ( (cit != end) || initial )
{
if (start_message)
{
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, flags);
msg->addS32(_PREHASH_LocalID, parcel_local_id);
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, sequence_id);
msg->addS32Fast(_PREHASH_Sections, num_sections);
start_message = FALSE;
if (initial && (cit == end))
{
// pack an empty block if there will be no data
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
msg->addS32Fast(_PREHASH_Time, 0 );
msg->addU32Fast(_PREHASH_Flags, 0 );
}
initial = FALSE;
sequence_id++;
}
while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES))
{
const LLAccessEntry& entry = (*cit).second;
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, entry.mID );
msg->addS32Fast(_PREHASH_Time, entry.mTime );
msg->addU32Fast(_PREHASH_Flags, entry.mFlags );
++cit;
}
start_message = TRUE;
msg->sendReliable( region->getHost() );
}
}
void LLViewerParcelMgr::deedLandToGroup()
{
std::string group_name;

View File

@ -229,7 +229,7 @@ public:
// Takes an Access List flag, like AL_ACCESS or AL_BAN
void sendParcelAccessListUpdate(U32 which);
// Takes an Access List flag, like AL_ACCESS or AL_BAN
void sendParcelAccessListRequest(U32 flags);
@ -302,6 +302,8 @@ public:
static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power);
private:
static void sendParcelAccessListUpdate(U32 flags, const std::map<LLUUID, class LLAccessEntry>& entries, LLViewerRegion* region, S32 parcel_local_id);
static void sendParcelExperienceUpdate( const U32 flags, uuid_vec_t experience_ids, LLViewerRegion* region, S32 parcel_local_id );
static bool releaseAlertCB(const LLSD& notification, const LLSD& response);
// If the user is claiming land and the current selection

View File

@ -2902,8 +2902,21 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
} //</FS:Ansariel>
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetExperiences");
capabilityNames.append("AgentExperiences");
capabilityNames.append("FindExperienceByName");
capabilityNames.append("GetExperienceInfo");
capabilityNames.append("GetAdminExperiences");
capabilityNames.append("GetCreatorExperiences");
capabilityNames.append("ExperiencePreferences");
capabilityNames.append("GroupExperiences");
capabilityNames.append("UpdateExperience");
capabilityNames.append("IsExperienceAdmin");
capabilityNames.append("IsExperienceContributor");
capabilityNames.append("RegionExperiences");
capabilityNames.append("GetMesh");
capabilityNames.append("GetMesh2");
capabilityNames.append("GetMetadata");
capabilityNames.append("GetObjectCost");
capabilityNames.append("GetObjectPhysicsData");
capabilityNames.append("GetTexture");

View File

@ -44,6 +44,7 @@
#include "llanimationstates.h"
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
#include "llcallingcard.h" // IDEVO for LLAvatarTracker
@ -1420,7 +1421,10 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getValid())
// <FS:Ansariel> Possible crash fix
//if (attachment->getValid())
if (attachment && attachment->getValid())
// </FS:Ansariel>
{
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
@ -1640,6 +1644,13 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@ -1705,6 +1716,13 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@ -1854,7 +1872,10 @@ void LLVOAvatar::releaseMeshData()
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (!attachment->getIsHUDAttachment())
// <FS:Ansariel> Possible crash fix
//if (!attachment->getIsHUDAttachment())
if (attachment && !attachment->getIsHUDAttachment())
// </FS:Ansariel>
{
attachment->setAttachmentVisibility(FALSE);
}
@ -2241,7 +2262,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateBelowWater(); // wind effect uses this
idleUpdateWindEffect();
}
idleUpdateNameTag( root_pos_last );
idleUpdateRenderCost();
}
@ -2395,6 +2416,13 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@ -4332,6 +4360,13 @@ void LLVOAvatar::updateVisibility()
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@ -6373,6 +6408,12 @@ U32 LLVOAvatar::getNumAttachments() const
++iter)
{
const LLViewerJointAttachment *attachment_pt = (*iter).second;
// <FS:Ansariel> Possible crash fix
if (!attachment_pt)
{
continue;
}
// </FS:Ansariel>
num_attachments += attachment_pt->getNumObjects();
}
return num_attachments;
@ -6458,6 +6499,14 @@ void LLVOAvatar::rebuildRiggedAttachments( void )
for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
{
LLViewerJointAttachment* pAttachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!pAttachment)
{
continue;
}
// </FS:Ansariel>
LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end();
for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin();
@ -6501,7 +6550,10 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->isObjectAttached(viewer_object))
// <FS:Ansariel> Possible crash fix
//if (attachment->isObjectAttached(viewer_object))
if (attachment && attachment->isObjectAttached(viewer_object))
// </FS:Ansariel>
{
mVisualComplexityStale = TRUE;
cleanupAttachedMesh( viewer_object );
@ -6770,6 +6822,14 @@ LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons
++attachment_points_iter)
{
LLViewerJointAttachment* attachment = attachment_points_iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)
@ -7596,6 +7656,14 @@ BOOL LLVOAvatar::hasHUDAttachment() const
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
if (attachment->getIsHUDAttachment() && attachment->getNumObjects() > 0)
{
return TRUE;
@ -7612,7 +7680,10 @@ LLBBox LLVOAvatar::getHUDBBox() const
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getIsHUDAttachment())
// <FS:Ansariel> Possible crash fix
//if (attachment->getIsHUDAttachment())
if (attachment && attachment->getIsHUDAttachment())
// </FS:Ansariel>
{
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
@ -8978,6 +9049,14 @@ void LLVOAvatar::calculateUpdateRenderCost()
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
// <FS:Ansariel> Possible crash fix
if (!attachment)
{
continue;
}
// </FS:Ansariel>
for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
attachment_iter != attachment->mAttachedObjects.end();
++attachment_iter)

Some files were not shown because too many files have changed in this diff Show More