master
Rider Linden 2015-07-01 08:47:50 -07:00
commit 9f2302bdff
524 changed files with 16797 additions and 3629 deletions

View File

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

View File

@ -503,3 +503,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

@ -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;
@ -848,7 +869,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;
@ -1191,3 +1212,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

@ -44,6 +44,7 @@ set(llmessage_SOURCE_FILES
llcurl.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
llhttpassetstorage.cpp
@ -134,6 +135,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,3 +1385,5 @@ 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");

View File

@ -1385,4 +1385,6 @@ 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;
#endif

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

@ -678,7 +678,7 @@ void LLNotification::respond(const LLSD& response)
// and then call it
functor(asLLSD(), response);
}
else
else if (mCombinedNotifications.empty())
{
// no registered responder
return;
@ -700,6 +700,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();
}
@ -1322,6 +1330,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

@ -414,6 +414,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);
@ -560,6 +563,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

@ -2094,3 +2094,8 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y)
}
}
}
S32 LLTabContainer::getTotalTabWidth() const
{
return mTotalTabWidth;
}

View File

@ -182,7 +182,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();
@ -287,7 +288,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"
#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
@ -1399,3 +1400,57 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url)
LLStringUtil::trim(mIcon);
return mIcon;
}
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

@ -308,6 +308,20 @@ private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name);
};
///
/// 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

@ -70,6 +70,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntryInventory());
registerUrl(new LLUrlEntryObjectIM());
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); }
@ -393,7 +395,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); }
@ -419,7 +420,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); }
@ -737,6 +737,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

@ -196,6 +196,8 @@ set(viewer_SOURCE_FILES
lleventnotifier.cpp
lleventpoll.cpp
llexpandabletextbox.cpp
llexperienceassociationresponder.cpp
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
llfacebookconnect.cpp
@ -236,6 +238,9 @@ set(viewer_SOURCE_FILES
llfloatereditwater.cpp
llfloaterenvironmentsettings.cpp
llfloaterevent.cpp
llfloaterexperiencepicker.cpp
llfloaterexperienceprofile.cpp
llfloaterexperiences.cpp
llfloaterfacebook.cpp
llfloaterflickr.cpp
llfloaterfonttest.cpp
@ -415,11 +420,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
@ -798,6 +808,8 @@ set(viewer_HEADER_FILES
lleventnotifier.h
lleventpoll.h
llexpandabletextbox.h
llexperienceassociationresponder.h
llexperiencelog.h
llexternaleditor.h
llface.h
llfacebookconnect.h
@ -838,6 +850,9 @@ set(viewer_HEADER_FILES
llfloatereditwater.h
llfloaterenvironmentsettings.h
llfloaterevent.h
llfloaterexperiencepicker.h
llfloaterexperienceprofile.h
llfloaterexperiences.h
llfloaterfacebook.h
llfloaterflickr.h
llfloaterfonttest.h
@ -1010,12 +1025,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

@ -1 +1 @@
3.7.31
3.8.1

View File

@ -52,6 +52,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
@ -714,6 +715,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

@ -47,7 +47,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>300</real>
<real>300.0</real>
</map>
<key>AckCollectTime</key>
<map>
@ -80,7 +80,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1</real>
<real>1.0</real>
</map>
<key>AdvanceSnapshot</key>
<map>
@ -1651,7 +1651,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>100</real>
<integer>100</integer>
</map>
<key>ChatLoadGroupTimeout</key>
<map>
@ -4271,7 +4271,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>3</real>
<real>3.0</real>
</map>
<key>FullScreenAutoDetectAspectRatio</key>
<map>
@ -6286,7 +6286,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>MeshEnabled</key>
<map>
@ -6297,7 +6297,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>1</real>
<integer>1</integer>
</map>
<key>MeshImportUseSLM</key>
<map>
@ -6308,7 +6308,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>1</real>
<integer>1</integer>
</map>
<key>MeshUploadLogXML</key>
<map>
@ -6319,7 +6319,7 @@
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>MeshUploadFakeErrors</key>
<map>
@ -6330,7 +6330,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>MeshUploadTimeOut</key>
<map>
@ -6341,7 +6341,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>600</real>
<integer>600</integer>
</map>
<key>MigrateCacheDirectory</key>
<map>
@ -8565,7 +8565,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>64</real>
<real>64.0</real>
</map>
<key>RenderCubeMap</key>
<map>
@ -8701,7 +8701,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>RenderEdgeDepthCutoff</key>
@ -8747,7 +8747,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>4</real>
<real>4.0</real>
</map>
<key>RenderDeferredSpotShadowBias</key>
<map>
@ -8814,7 +8814,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0</real>
<real>0.0</real>
</map>
<key>RenderDepthPrePass</key>
@ -9008,7 +9008,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>RenderSpecularResX</key>
@ -9020,7 +9020,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>1024</real>
<integer>1024</integer>
</map>
<key>RenderSpecularResY</key>
@ -9032,7 +9032,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>256</real>
<integer>256</integer>
</map>
<key>RenderSpecularExponent</key>
@ -9188,7 +9188,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
</map>
<key>RenderShadowBlurDistFactor</key>
<map>
@ -9355,9 +9355,9 @@
<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>
@ -9958,7 +9958,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>0</real>
<integer>0</integer>
</map>
<key>RenderAutoMuteLogging</key>
<map>
@ -10180,7 +10180,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>250000</real>
<integer>250000</integer>
</map>
<key>MeshMetaDataDiscount</key>
<map>
@ -10191,7 +10191,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>384</real>
<integer>384</integer>
</map>
<key>MeshMinimumByteSize</key>
<map>
@ -10202,7 +10202,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>MeshBytesPerTriangle</key>
<map>
@ -10213,7 +10213,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>Mesh2MaxConcurrentRequests</key>
<map>
@ -10345,7 +10345,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>1024</real>
<integer>1024</integer>
</map>
<key>SceneLoadLowMemoryBound</key>
<map>
@ -10356,7 +10356,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
<real>750</real>
<integer>750</integer>
</map>
<key>SceneLoadMinRadius</key>
<map>
@ -12149,7 +12149,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>6</real>
<integer>6</integer>
</map>
<key>UICheckboxctrlBtnSize</key>
<map>
@ -12160,7 +12160,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>13</real>
<integer>13</integer>
</map>
<key>UICheckboxctrlHeight</key>
<map>
@ -12171,7 +12171,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>UICheckboxctrlHPad</key>
<map>
@ -12182,7 +12182,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>2</real>
<integer>2</integer>
</map>
<key>UICheckboxctrlSpacing</key>
<map>
@ -12193,7 +12193,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>5</real>
<integer>5</integer>
</map>
<key>UICheckboxctrlVPad</key>
<map>
@ -12204,7 +12204,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>2</real>
<integer>2</integer>
</map>
<key>UICloseBoxFromTop</key>
<map>
@ -12215,7 +12215,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>5</real>
<integer>5</integer>
</map>
<key>UIExtraTriangleHeight</key>
<map>
@ -12226,7 +12226,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>-1</real>
<integer>-1</integer>
</map>
<key>UIExtraTriangleWidth</key>
<map>
@ -12237,7 +12237,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
</map>
<key>UIFloaterCloseBoxSize</key>
<map>
@ -12248,7 +12248,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>16</real>
<integer>16</integer>
</map>
<key>UIFloaterHPad</key>
<map>
@ -12259,7 +12259,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>6</real>
<integer>6</integer>
</map>
<key>UIFloaterTestBool</key>
<map>
@ -12479,7 +12479,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>500</real>
<integer>500</integer>
</map>
<key>UIMinimizedWidth</key>
<map>
@ -12490,7 +12490,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>160</real>
<integer>160</integer>
</map>
<key>UIMultiSliderctrlSpacing</key>
<map>
@ -12501,7 +12501,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>4</real>
<integer>4</integer>
</map>
<key>UIMultiTrackHeight</key>
<map>
@ -13161,7 +13161,7 @@
<key>Type</key>
<string>S32</string>
<key>Value</key>
<real>3</real>
<integer>3</integer>
</map>
<key>UseCircuitCodeTimeout</key>
<map>
@ -15169,9 +15169,9 @@
<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>
@ -15488,7 +15488,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>2</real>
<real>2.0</real>
</map>
<key>TeleportLocalDelay</key>
<map>
@ -15499,7 +15499,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1</real>
<real>1.0</real>
</map>
<key>FMODExProfilerEnable</key>
<map>

View File

@ -105,6 +105,7 @@
// Linden library includes
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llexperiencecache.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
@ -4698,6 +4699,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.
@ -4893,7 +4920,7 @@ void LLAppViewer::idle()
// floating throughout the various object lists.
//
idleNameCache();
idleExperienceCache();
idleNetwork();
@ -5323,6 +5350,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
//
@ -5485,6 +5528,7 @@ void LLAppViewer::disconnectViewer()
}
saveNameCache();
saveExperienceCache();
// close inventory interface, close all windows
LLFloaterInventory::cleanup();

View File

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

View File

@ -168,6 +168,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);
@ -191,7 +192,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;
@ -203,6 +205,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

@ -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
@ -167,7 +172,7 @@ BOOL LLFloaterScriptQueue::start()
getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
return nextObject();
return startQueue();
}
BOOL LLFloaterScriptQueue::isDone() const
@ -232,6 +237,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
@ -284,6 +323,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)
{
@ -324,25 +378,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,
@ -382,12 +463,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();
}
}
}
@ -399,7 +480,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)
{
@ -407,15 +488,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))
{
@ -564,6 +645,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

@ -81,13 +81,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;
@ -131,6 +133,9 @@ public:
LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; }
void experienceIdsReceived( const LLSD& content );
BOOL hasExperience(const LLUUID& id)const;
protected:
LLFloaterCompileQueue(const LLSD& key);
virtual ~LLFloaterCompileQueue();
@ -139,16 +144,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

@ -380,13 +380,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;
@ -395,15 +398,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
@ -416,27 +416,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"
@ -110,6 +113,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]
@ -248,6 +273,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 );
@ -288,6 +314,7 @@ void LLFloaterLand::refresh()
mPanelMedia->refresh();
mPanelAccess->refresh();
mPanelCovenant->refresh();
mPanelExperiences->refresh();
}
@ -348,6 +375,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
//---------------------------------------------------------------------------
@ -2404,7 +2440,7 @@ void LLPanelLandAccess::refresh()
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
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;
@ -2450,7 +2486,7 @@ void LLPanelLandAccess::refresh()
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count));
getChild<LLUICtrl>("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST));
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;
@ -3039,3 +3075,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

@ -66,6 +66,7 @@ class LLPanelLandBan;
class LLPanelLandRenters;
class LLPanelLandCovenant;
class LLParcel;
class LLPanelLandExperiences;
class LLFloaterLand
: public LLFloater
@ -101,6 +102,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);
@ -116,6 +118,7 @@ protected:
LLPanelLandMedia* mPanelMedia;
LLPanelLandAccess* mPanelAccess;
LLPanelLandCovenant* mPanelCovenant;
LLPanelLandExperiences* mPanelExperiences;
LLSafeHandle<LLParcelSelection> mParcel;

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"
#include "llcorehttputil.h"
const S32 TERRAIN_TEXTURE_COUNT = 4;
@ -127,6 +132,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(
@ -216,6 +233,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);
@ -446,6 +471,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");
}
void LLFloaterRegionInfo::onTabSelected(const LLSD& param)
{
LLPanel* active_panel = getChild<LLPanel>(param.asString());
@ -1370,6 +1405,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;
}
@ -2849,6 +2889,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),
@ -3440,3 +3530,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

@ -61,6 +61,9 @@ class LLPanelRegionDebugInfo;
class LLPanelRegionTerrainInfo;
class LLPanelEstateInfo;
class LLPanelEstateCovenant;
class LLPanelExperienceListEditor;
class LLPanelExperiences;
class LLPanelRegionExperiences;
class LLEventTimer;
class LLEnvironmentSettings;
@ -91,6 +94,7 @@ public:
static LLPanelEstateInfo* getPanelEstate();
static LLPanelEstateCovenant* getPanelCovenant();
static LLPanelRegionTerrainInfo* getPanelRegionTerrain();
static LLPanelRegionExperiences* getPanelExperiences();
// from LLPanel
virtual void refresh();
@ -456,4 +460,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
@ -225,6 +226,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 --
@ -470,7 +495,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");
@ -483,6 +508,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;
@ -492,9 +534,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
@ -854,6 +896,7 @@ void LLFloaterReporter::setPosBox(const LLVector3d &pos)
getChild<LLUICtrl>("pos_field")->setValue(pos_string);
}
// void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd)
// {
// LLFloaterReporter *self = LLFloaterReg::findTypedInstance<LLFloaterReporter>("reporter");

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);
@ -106,7 +107,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);
@ -118,6 +119,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);
@ -128,6 +130,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

@ -169,7 +169,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,443 @@
/**
* @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);
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

@ -177,11 +177,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)
{
@ -418,6 +420,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);
@ -434,10 +437,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);
@ -459,6 +465,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;
@ -467,6 +475,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);
@ -534,6 +543,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

@ -86,19 +86,22 @@
#include "llviewercontrol.h"
#include "llappviewer.h"
#include "llfloatergotoline.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
#include "llexperienceassociationresponder.h"
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";
@ -115,6 +118,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"]);
}
};
/// ---------------------------------------------------------------------------
/// LLLiveLSLFile
/// ---------------------------------------------------------------------------
@ -193,7 +216,7 @@ private:
protected:
LLLineEditor* mSearchBox;
LLLineEditor* mReplaceBox;
void onSearchBoxCommit();
void onSearchBoxCommit();
};
LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL;
@ -402,6 +425,55 @@ 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()
{
mErrorList = getChild<LLScrollListCtrl>("lsl errors");
@ -828,7 +900,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;
@ -863,8 +935,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()));
@ -1216,6 +1288,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
/// ---------------------------------------------------------------------------
@ -1234,7 +1441,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);
@ -1772,6 +1979,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();
}
@ -1815,61 +2032,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.
/*
@ -1906,6 +2122,8 @@ void LLLiveLSLEditor::loadAsset()
time_corrected());
mAssetStatus = PREVIEW_ASSET_LOADED;
}
requestExperiences();
}
// static
@ -2169,7 +2387,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)
{
@ -2181,7 +2399,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;
@ -2189,6 +2408,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));
}
@ -2449,3 +2669,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

@ -51,6 +51,7 @@ class LLVFS;
class LLViewerInventoryItem;
class LLScriptEdContainer;
class LLFloaterGotoLine;
class LLFloaterExperienceProfile;
// Inner, implementation class. LLPreviewScript and LLLiveLSLEditor each own one of these.
class LLScriptEdCore : public LLPanel
@ -107,12 +108,14 @@ public:
static void onBtnInsertSample(void*);
static void onBtnInsertFunction(LLUICtrl*, void*);
static void onBtnLoadFromFile(void*);
static void onBtnSaveToFile(void*);
static void onBtnSaveToFile(void*);
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;};
@ -146,8 +149,8 @@ private:
void (*mLoadCallback)(void* userdata);
void (*mSaveCallback)(void* userdata, BOOL close_after_save);
void (*mSearchReplaceCallback) (void* userdata);
void* mUserdata;
LLComboBox *mFunctions;
void* mUserdata;
LLComboBox *mFunctions;
BOOL mForceClose;
LLPanel* mCodePanel;
LLScrollListCtrl* mErrorList;
@ -159,6 +162,7 @@ private:
BOOL mEnableSave;
BOOL mHasScriptData;
LLLiveLSLFile* mLiveFile;
LLUUID mAssociatedExperience;
LLScriptEdContainer* mContainer; // parent view
@ -245,7 +249,18 @@ public:
/*virtual*/ BOOL postBuild();
void setIsNew() { mIsNew = TRUE; }
void setIsNew() { mIsNew = TRUE; }
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();
@ -256,10 +271,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,
@ -300,9 +316,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

@ -541,19 +541,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"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -319,6 +322,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 //
//////////////////////
@ -674,6 +686,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"
@ -194,6 +195,7 @@
#include "llevents.h"
#include "llstartuplistener.h"
#include "lltoolbarview.h"
#include "llexperiencelog.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@ -1305,6 +1307,9 @@ bool idle_startup()
// 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 );
@ -2824,6 +2829,14 @@ void LLStartUp::initNameCache()
LLAvatarNameCache::setUseUsernames(gSavedSettings.getBOOL("NameTagShowUsernames"));
}
void LLStartUp::initExperiences()
{
LLAppViewer::instance()->loadExperienceCache();
LLExperienceCache::initClass();
LLExperienceLog::instance().initialize();
}
void LLStartUp::cleanupNameCache()
{
LLAvatarNameCache::cleanupClass();
@ -3525,3 +3538,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

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

View File

@ -46,7 +46,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

@ -60,6 +60,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"
@ -213,8 +216,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

@ -117,6 +117,7 @@
#include <boost/regex.hpp>
#include "llnotificationmanager.h" //
#include "llexperiencecache.h"
#if LL_MSVC
// disable boost::lexical_cast warning
@ -142,6 +143,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;
@ -5694,108 +5696,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;
}
}
@ -5804,54 +5731,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;
}
@ -5881,6 +5911,9 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)
}
}
handle_trusted_experiences_notification(llsdBlock);
if (
(notificationID == "RegionEntryAccessBlocked") ||
(notificationID == "LandClaimAccessBlocked") ||
@ -6064,8 +6097,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)
{
@ -6087,10 +6120,10 @@ void process_alert_core(const std::string& message, BOOL modal)
LLFloaterRegionRestarting::close();
}
std::string new_msg =LLNotifications::instance().getGlobalString(text);
args["MESSAGE"] = new_msg;
LLNotificationsUtil::add("SystemMessage", args);
}
std::string new_msg =LLNotifications::instance().getGlobalString(text);
args["MESSAGE"] = new_msg;
LLNotificationsUtil::add("SystemMessage", args);
}
else if (modal)
{
LLSD args;
@ -6345,6 +6378,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
@ -6354,6 +6393,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();
@ -6380,7 +6429,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;
}
@ -6413,8 +6482,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]
@ -6426,6 +6511,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 );
@ -6435,6 +6521,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,
@ -6521,20 +6612,21 @@ void process_script_question(LLMessageSystem *msg, void **user_data)
payload["owner_name"] = owner_name;
// 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

@ -206,8 +206,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;
@ -893,7 +893,7 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags)
if (!region) return;
LLMessageSystem *msg = gMessageSystem;
if (flags & AL_BAN)
{
@ -903,6 +903,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);
@ -1671,7 +1679,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;
@ -1836,6 +1844,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) );
@ -1870,10 +1886,6 @@ void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**)
void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which)
{
LLUUID transactionUUID;
transactionUUID.generate();
if (!mSelected)
{
return;
@ -1882,125 +1894,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

@ -218,7 +218,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);
@ -291,6 +291,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

@ -2824,8 +2824,21 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
AISCommand::getCapabilityNames(capabilityNames);
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

@ -43,6 +43,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
@ -2148,7 +2149,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time)
idleUpdateBelowWater(); // wind effect uses this
idleUpdateWindEffect();
}
idleUpdateNameTag( root_pos_last );
idleUpdateRenderCost();
}

View File

@ -145,6 +145,9 @@ const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session
const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk
const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session
const U64 GP_EXPERIENCE_ADMIN = 0x1LL << 49; // has admin rights to any experiences owned by this group
const U64 GP_EXPERIENCE_CREATOR = 0x1LL << 50; // can sign scripts for experiences owned by this group
// Group Banning
const U64 GP_GROUP_BAN_ACCESS = 0x1LL << 51; // Allows access to ban / un-ban agents from a group.

View File

@ -222,6 +222,7 @@ with the same filename but different name
<texture name="ForwardArrow_Off" file_name="icons/ForwardArrow_Off.png" preload="false" />
<texture name="ForwardArrow_Press" file_name="icons/ForwardArrow_Press.png" preload="false" />
<texture name="Generic_Experience" file_name="Blank.png" preload="false" />
<texture name="Generic_Group" file_name="icons/Generic_Group.png" preload="false" />
<texture name="Generic_Group_Large" file_name="icons/Generic_Group_Large.png" preload="false" />
<texture name="icon_group.tga" file_name="icons/Generic_Group.png" preload="false" />

View File

@ -309,9 +309,6 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<panel.string name="push_restrict_region_text">
Kein Stoßen (regional)
</panel.string>
<panel.string name="see_avs_text">
Avatare auf anderen Parzellen können
</panel.string>
<text name="allow_label">
Anderen Einwohnern gestatten:
</text>
@ -337,22 +334,6 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<check_box label="Sicher (kein Schaden)" name="check safe" tool_tip="Falls aktiviert, wird Land auf Option „Sicher“ eingestellt, Kampfschäden sind deaktiviert. Ansonsten sind Kampfschäden aktiviert."/>
<check_box label="Kein Stoßen" name="PushRestrictCheck" tool_tip="Verhindert Stoßen durch Skripte. Durch Aktivieren dieser Option verhindern Sie störendes Verhalten auf Ihrem Land."/>
<check_box label="Ort in Suche anzeigen (30 L$/Woche)" name="ShowDirectoryCheck" tool_tip="Diese Parzelle in Suchergebnissen anzeigen."/>
<combo_box name="land category with adult">
<combo_box.item label="Alle Kategorien" name="item0"/>
<combo_box.item label="Lindenort" name="item1"/>
<combo_box.item label="Adult" name="item2"/>
<combo_box.item label="Kunst &amp; Kultur" name="item3"/>
<combo_box.item label="Business" name="item4"/>
<combo_box.item label="Bildung" name="item5"/>
<combo_box.item label="Spielen" name="item6"/>
<combo_box.item label="Treffpunkt" name="item7"/>
<combo_box.item label="Anfängergerecht" name="item8"/>
<combo_box.item label="Parks und Natur" name="item9"/>
<combo_box.item label="Wohngebiet" name="item10"/>
<combo_box.item label="Shopping" name="item11"/>
<combo_box.item label="Vermietung" name="item13"/>
<combo_box.item label="Sonstige" name="item12"/>
</combo_box>
<combo_box name="land category">
<combo_box.item label="Alle Kategorien" name="item0"/>
<combo_box.item label="Lindenort" name="item1"/>
@ -449,15 +430,9 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<panel.string name="access_estate_defined">
(Durch Grundbesitz festgelegt)
</panel.string>
<panel.string name="allow_public_access">
Öffentlichen Zugang erlauben ([MATURITY]) (Hinweis: Bei Deaktivierung dieser Option werden Bannlinien generiert)
</panel.string>
<panel.string name="estate_override">
Eine oder mehrere dieser Optionen gelten auf Grundbesitzebene
</panel.string>
<text name="Limit access to this parcel to:">
Zugang zu dieser Parzelle
</text>
<check_box label="Öffentlichen Zugang gestatten (bei Deaktivierung dieser Option werden Bannlinien generiert)" name="public_access"/>
<text name="Only Allow" width="400">
Zugang nur Einwohnern gestatten, die:
@ -489,5 +464,6 @@ Nur große Parzellen können in der Suche aufgeführt werden.
<button label="Entfernen" label_selected="Entfernen" name="remove_banned"/>
</panel>
</panel>
<panel label="ERLEBNISSE" name="land_experiences_panel"/>
</tab_container>
</floater>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="experiencepicker" title="ERLEBNIS AUSWÄHLEN"/>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater title="EXPERIENCE PROFILE">
<floater.string name="empty_slurl">
(keines)
</floater.string>
<floater.string name="maturity_icon_general">
&quot;Parcel_PG_Light&quot;
</floater.string>
<floater.string name="maturity_icon_moderate">
&quot;Parcel_M_Light&quot;
</floater.string>
<floater.string name="maturity_icon_adult">
&quot;Parcel_R_Light&quot;
</floater.string>
<text name="edit_title" value="Erlebnisprofil"/>
<tab_container name="tab_container">
<panel name="panel_experience_info">
<scroll_container name="xp_scroll">
<panel name="scrolling_panel">
<layout_stack>
<layout_panel name="top panel">
<button label="Bearbeiten" name="edit_btn"/>
</layout_panel>
<layout_panel name="maturity panel">
<text name="ContentRating">
Einstufung:
</text>
</layout_panel>
<layout_panel name="location panel">
<text name="Location">
Standort:
</text>
</layout_panel>
<layout_panel>
<text name="Owner">
Eigentümer:
</text>
</layout_panel>
<layout_panel name="group_panel">
<text name="Group">
Gruppe:
</text>
</layout_panel>
<layout_panel name="perm panel">
<button label="Zulassen" name="allow_btn"/>
<button label="Vergessen" name="forget_btn"/>
<button label="Blockieren" name="block_btn"/>
<text name="privileged">
Dieses Erlebnis ist für alle Einwohner aktiviert.
</text>
<button label="Missbrauch melden" name="report_btn"/>
</layout_panel>
</layout_stack>
</panel>
</scroll_container>
</panel>
<panel name="edit_panel_experience_info">
<scroll_container name="edit_xp_scroll">
<panel name="edit_scrolling_panel">
<text name="edit_experience_title_label" value="Name:"/>
<text name="edit_experience_desc_label" value="Beschreibung:"/>
<button label="Gruppe" name="Group_btn"/>
<text name="edit_ContentRating">
Einstufung:
</text>
<icons_combo_box label="Moderat" name="edit_ContentRatingText" tool_tip="Bei Erhöhung der Inhaltseinstufung eines Erlebnisses wird die Berechtigung für alle Einwohner zurückgesetzt, die das Erlebnis zugelassen haben.">
<icons_combo_box.item label="Adult" name="Adult" value="42"/>
<icons_combo_box.item label="Moderat" name="Mature" value="21"/>
<icons_combo_box.item label="Allgemein" name="PG" value="13"/>
</icons_combo_box>
<text name="edit_Location">
Standort:
</text>
<button label="Aktuellen Standort verwenden" name="location_btn"/>
<button label="Standort löschen" name="clear_btn"/>
<check_box label="Erlebnis aktivieren" name="edit_enable_btn" tool_tip=""/>
<check_box label="Aus Suche ausschließen" name="edit_private_btn"/>
<text name="changes" value="Es kann mehrere Minuten dauern, bis Erlebnisänderungen in allen Regionen umgesetzt werden."/>
<button label="Zurück" name="cancel_btn"/>
<button label="Speichern" name="save_btn"/>
</panel>
</scroll_container>
</panel>
</tab_container>
</floater>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_experiences" title="ERLEBNISSE"/>

View File

@ -1,20 +1,15 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_facebook" title="AUF FACEBOOK POSTEN">
<panel name="background">
<tab_container name="tabs">
<panel label="STATUS" name="panel_facebook_status"/>
<panel label="FOTO" name="panel_facebook_photo"/>
<panel label="EINCHECKEN" name="panel_facebook_place"/>
<panel label="FREUNDE" name="panel_facebook_friends"/>
<panel label="KONTO" name="panel_facebook_account"/>
</tab_container>
<panel name="connection_status_panel">
<text name="connection_error_text">
Fehler
</text>
<text name="connection_loading_text">
Laden...
</text>
</panel>
</panel>
<tab_container name="tabs">
<panel label="STATUS" name="panel_facebook_status"/>
<panel label="FOTO" name="panel_facebook_photo"/>
<panel label="EINCHECKEN" name="panel_facebook_place"/>
<panel label="FREUNDE" name="panel_facebook_friends"/>
</tab_container>
<text name="connection_error_text">
Fehler
</text>
<text name="connection_loading_text">
Laden...
</text>
</floater>

View File

@ -5,8 +5,8 @@
<check_box label="Kleidung" name="check_clothing"/>
<check_box label="Gesten" name="check_gesture"/>
<check_box label="Landmarken" name="check_landmark"/>
<check_box label="Netze" name="check_mesh"/>
<check_box label="Notizkarten" name="check_notecard"/>
<check_box label="Netze" name="check_mesh"/>
<check_box label="Objekte" name="check_object"/>
<check_box label="Skripts" name="check_script"/>
<check_box label="Sounds" name="check_sound"/>
@ -19,6 +19,10 @@
<text name="- OR -">
- ODER -
</text>
<radio_group name="date_search_direction">
<radio_item label="Neuer als" name="newer"/>
<radio_item label="Älter als" name="older"/>
</radio_group>
<spinner label="Stunden zuvor" label_width="80" name="spin_hours_ago"/>
<spinner label="Tage zuvor" name="spin_days_ago"/>
<button label="Schließen" label_selected="Schließen" name="Close"/>

View File

@ -4,7 +4,7 @@
Lag-Anzeige
</floater.string>
<floater.string name="max_width_px">
350
360
</floater.string>
<floater.string name="min_title_msg">
Lag
@ -25,10 +25,10 @@
Normal, Fenster im Hintergrund
</floater.string>
<floater.string name="client_frame_time_critical_msg">
Client-Frame-Rate unter [CLIENT_FRAME_RATE_CRITICAL]
Client-Framerate unter [CLIENT_FRAME_RATE_CRITICAL]
</floater.string>
<floater.string name="client_frame_time_warning_msg">
Client-Frame-Rate zwischen [CLIENT_FRAME_RATE_CRITICAL] und [CLIENT_FRAME_RATE_WARNING]
Client-Framerate zwischen [CLIENT_FRAME_RATE_CRITICAL] und [CLIENT_FRAME_RATE_WARNING]
</floater.string>
<floater.string name="client_frame_time_normal_msg">
Normal
@ -55,10 +55,10 @@
5
</floater.string>
<floater.string name="network_packet_loss_critical_msg">
Paketverlust der Verbindung übersteigt [NETWORK_PACKET_LOSS_CRITICAL]%
Paketverlust der Verbindung übersteigt [NETWORK_PACKET_LOSS_CRITICAL] %
</floater.string>
<floater.string name="network_packet_loss_warning_msg">
Paketverlust der Verbindung liegt bei [NETWORK_PACKET_LOSS_WARNING]%-[NETWORK_PACKET_LOSS_CRITICAL]%
Paketverlust der Verbindung liegt bei [NETWORK_PACKET_LOSS_WARNING]%-[NETWORK_PACKET_LOSS_CRITICAL] %
</floater.string>
<floater.string name="network_performance_normal_msg">
Normal
@ -76,10 +76,10 @@
Ping-Zeit der Verbindung liegt bei [NETWORK_PING_WARNING]-[NETWORK_PING_CRITICAL] ms
</floater.string>
<floater.string name="network_packet_loss_cause_msg">
Möglicherweise schlechte Verbindung oder zu hoher Wert für „Bandbreite“.
Möglicherweise schlechte Verbindung oder zu hoher Bandbreitenwert.
</floater.string>
<floater.string name="network_ping_cause_msg">
Möglicherweise schlechte Verbindung oder File-Sharing-Anwendung.
Möglicherweise schlechte Verbindung oder Filesharing-Anwendung.
</floater.string>
<floater.string name="server_text_msg">
Server
@ -94,10 +94,10 @@
20
</floater.string>
<floater.string name="server_frame_time_critical_msg">
Simulator-Frame-Rate liegt unter [SERVER_FRAME_RATE_CRITICAL]
Simulator-Framerate liegt unter [SERVER_FRAME_RATE_CRITICAL]
</floater.string>
<floater.string name="server_frame_time_warning_msg">
Simulator-Frame-Rate liegt zwischen [SERVER_FRAME_RATE_CRITICAL] und [SERVER_FRAME_RATE_WARNING]
Simulator-Framerate liegt zwischen [SERVER_FRAME_RATE_CRITICAL] und [SERVER_FRAME_RATE_WARNING]
</floater.string>
<floater.string name="server_frame_time_normal_msg">
Normal
@ -112,13 +112,13 @@
Mögliche Ursache: Zu viel Netzwerktraffic
</floater.string>
<floater.string name="server_agent_cause_msg">
Mögliche Ursache: Zu viele Personen in Bewegung in der Region
Mögliche Ursache: Zu viele Personen in der Region in Bewegung
</floater.string>
<floater.string name="server_images_cause_msg">
Mögliche Ursache: Zu viele Bildberechnungen
</floater.string>
<floater.string name="server_generic_cause_msg">
Mögliche Ursache: Zu hohe Simulator-Last
Mögliche Ursache: Zu hohe Simulatorlast
</floater.string>
<floater.string name="smaller_label">
&gt;&gt;
@ -147,5 +147,5 @@
<text name="server_text">
Normal
</text>
<button label="&gt;&gt; " name="minimize" tool_tip="Fenstergröße ändern"/>
<button label="&gt;&gt;" name="minimize" tool_tip="Fenstergröße ändern"/>
</floater>

View File

@ -9,7 +9,24 @@
<floater.string name="Title">
SKRIPT: [NAME]
</floater.string>
<floater.string name="experience_enabled">
Markierung löschen, um aktuelles Erlebnis zu entfernen
</floater.string>
<floater.string name="no_experiences">
Sie sind zu keinen Erlebnissen berechtigt
</floater.string>
<floater.string name="add_experiences">
Auswählen, um Erlebnis hinzuzufügen
</floater.string>
<floater.string name="show_experience_profile">
Klicken, um Erlebnisprofil aufzurufen
</floater.string>
<floater.string name="loading">
Laden...
</floater.string>
<button label="Zurücksetzen" label_selected="Zurücksetzen" name="Reset"/>
<check_box initial_value="true" label="Läuft" name="running"/>
<check_box initial_value="true" label="Mono" name="mono"/>
<check_box label="Erlebnis verwenden:" name="enable_xp"/>
<button label="&gt;" name="view_profile"/>
</floater>

View File

@ -4,5 +4,5 @@
[DESC]:
</text>
<button label="In Inventar kopieren" label_selected="In Inventar kopieren" name="copy_to_inventory_button" width="120"/>
<button label="Kopieren und anziehen" label_selected="Kopieren und anziehen" left_pad="6" name="copy_and_wear_button" width="136"/>
<button label="Kopieren und zum Outfit hinzufügen" label_selected="Kopieren und zum Outfit hinzufügen" left_pad="6" name="copy_and_wear_button" width="136"/>
</floater>

View File

@ -77,7 +77,7 @@ Objekt:
<combo_box.item label="Land &gt; Unbefugte Nutzung &gt; Objekte oder Texturen" name="Land__Encroachment__Objects_textures"/>
<combo_box.item label="Land &gt; Unbefugte Nutzung &gt; Partikel" name="Land__Encroachment__Particles"/>
<combo_box.item label="Land &gt; Unbefugte Nutzung &gt; Bäume/Pflanzen" name="Land__Encroachment__Trees_plants"/>
<combo_box.item label="Wetten/Glücksspiel" name="Wagering_gambling"/>
<combo_box.item label="Verstoß gegen die Spielerichtlinie" name="Wagering_gambling"/>
<combo_box.item label="Sonstige" name="Other"/>
</combo_box>
<text name="abuser_name_title">

View File

@ -39,13 +39,7 @@
<string name="local_failed_str">
Fehler beim Speichern auf dem Computer.
</string>
<button name="advanced_options_btn" tool_tip="Erweiterte Optionen"/>
<text name="image_res_text">
[WIDTH]px (Breite) x [HEIGHT]px (Höhe)
</text>
<text name="file_size_label">
[SIZE] KB
</text>
<button label="AKTUALISIEREN" name="new_snapshot_btn"/>
<panel name="advanced_options_panel">
<text name="layer_type_label">
Aufnehmen:
@ -65,4 +59,10 @@
<combo_box.item label="Kein Filter" name="NoFilter"/>
</combo_box>
</panel>
<text name="image_res_text">
[WIDTH] px (Breite) x [HEIGHT] px (Höhe)
</text>
<text name="file_size_label">
[SIZE] KB
</text>
</floater>

View File

@ -21,6 +21,12 @@
<floater.string name="none_descriptor">
Nicht gefunden.
</floater.string>
<floater.string name="URLs">
URLs
</floater.string>
<floater.string name="memory">
Speicher (KB)
</floater.string>
<text name="title_text">
Wird geladen...
</text>
@ -30,7 +36,7 @@
<scroll_list.columns label="Eigentümer" name="owner"/>
<scroll_list.columns label="Position" name="location" width="125"/>
<scroll_list.columns label="Parzelle" name="parcel"/>
<scroll_list.columns label="Uhrzeit" name="time"/>
<scroll_list.columns label="Datum" name="time"/>
<scroll_list.columns label="URLs" name="URLs"/>
<scroll_list.columns label="Speicher (KB)" name="memory"/>
</scroll_list>

View File

@ -1,17 +1,13 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_twitter" title="TWITTER">
<panel name="background">
<tab_container name="tabs">
<panel label="ERSTELLEN" name="panel_twitter_photo"/>
<panel label="KONTO" name="panel_twitter_account"/>
</tab_container>
<panel name="connection_status_panel">
<text name="connection_error_text">
Fehler
</text>
<text name="connection_loading_text">
Laden...
</text>
</panel>
</panel>
<tab_container name="tabs">
<panel label="ERSTELLEN" name="panel_twitter_photo"/>
<panel label="KONTO" name="panel_twitter_account"/>
</tab_container>
<text name="connection_error_text">
Fehler
</text>
<text name="connection_loading_text">
Laden...
</text>
</floater>

View File

@ -5,7 +5,7 @@
<menu_item_check label="Nach aktuellesten Objekten sortieren" name="sort_by_recent"/>
<menu_item_check label="Ordner immer nach Namen sortieren" name="sort_folders_by_name"/>
<menu_item_check label="Systemordner nach oben" name="sort_system_folders_to_top"/>
<menu_item_call label="Filter anzeigen" name="show_filters"/>
<menu_item_call label="Filter anzeigen..." name="show_filters"/>
<menu_item_call label="Filter zurücksetzen" name="reset_filters"/>
<menu_item_call label="Alle Ordner schließen" name="close_folders"/>
<menu_item_call label="Fundbüro ausleeren" name="empty_lostnfound"/>

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