merge 3.5.0-release

master
Oz Linden 2013-06-19 13:59:52 -04:00
commit e23228fef2
512 changed files with 31946 additions and 24673 deletions

17
.hgtags
View File

@ -417,3 +417,20 @@ b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292
0a5d409161ef2a89b28c9a741051dd2dedc707d6 DRTVWR-297
852b69ef0b5fe6b13b69cc2217282cc64de6afab 3.4.5-beta5
a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release
37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282
6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284
092a9effbedd1a0276fa5ced520992ce00f96fbf CHUI-PV-0
279ef1dfc9b749a6cc499cf190fec0c090b6d682 DRTVWR-288
9b19edaf1d8ddf435f60fbbb444dd25db8f63953 3.5.0-beta1
c6b3561c7d7ad365eeba669db54eb57b5149ce75 3.5.0-beta2
6d91ffd77bf2a20f18a2175eb7579da880ae12ac DRTVWR-302
f6ca5bb75bca975ff0bc77e71e615f6478c4559c 3.5.0-beta3
910b5fad950e343b58229f5a0aefa7729b9308b3 DRTVWR-303
53cffdde0b3cc367ba9bb6abd5c83ae14df5e882 3.5.0-beta4
4d5f6234dc59a0fb6ead5e02c7d343a0610e0488 DRTVWR-304
dd058a6093c493120d67c8e02c812c0f7b2d3db0 3.5.0-beta5
fd6b510e83f56830e45670c428653134899d3e25 DRTVWR-305
55339537d99afc394d1bb7fdb7d074bf321ca62f 3.5.0-beta6
902caf2b9fdbdbc5c399c4d5ebcecaf9cb97bab8 DRTVWR-306
5c6098fd17d40ee3a38ca6b64f6be9db7f61f0a8 3.5.0-beta7
adc360e6bf21390d2665380951d85937cd29a604 3.5.0-release

View File

@ -129,6 +129,18 @@ viewer-pathfinding.build_viewer_update_version_manager = false
oz_project-1_Linux.build_docs = true
# ========================================
# viewer-chui
#
# ========================================
viewer-chui.viewer_channel = "Project Viewer - CHUI"
viewer-chui.login_channel = "Project Viewer - CHUI"
viewer-chui.viewer_grid = agni
viewer-chui.build_debug_release_separately = true
viewer-chui.build_CYGWIN_Debug = false
viewer-chui.build_viewer_update_version_manager = false
# =================================================================
# asset delivery 2010 projects
# =================================================================

View File

@ -744,10 +744,12 @@ Marc Claridge
Marc2 Sands
Marianne McCann
Marine Kelley
CHUIBUG-134
STORM-281
MartinRJ Fayray
STORM-1844
STORM-1845
STORM-1934
Matthew Anthony
Matthew Dowd
VWR-1344

View File

@ -839,6 +839,10 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i
asp->play(audio_uuid);
}
void LLAudioEngine::triggerSound(SoundData& soundData)
{
triggerSound(soundData.audio_uuid, soundData.owner_id, soundData.gain, soundData.type, soundData.pos_global);
}
void LLAudioEngine::setListenerPos(LLVector3 aVec)
{

View File

@ -66,6 +66,7 @@ class LLAudioChannel;
class LLAudioChannelOpenAL;
class LLAudioBuffer;
class LLStreamingAudioInterface;
struct SoundData;
//
@ -144,6 +145,8 @@ public:
void triggerSound(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain,
const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
const LLVector3d &pos_global = LLVector3d::zero);
void triggerSound(SoundData& soundData);
bool preloadSound(const LLUUID &id);
void addAudioSource(LLAudioSource *asp);
@ -456,6 +459,27 @@ protected:
LLFrameTimer mLastUseTimer;
};
struct SoundData
{
LLUUID audio_uuid;
LLUUID owner_id;
F32 gain;
S32 type;
LLVector3d pos_global;
SoundData(const LLUUID &audio_uuid,
const LLUUID& owner_id,
const F32 gain,
const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
const LLVector3d &pos_global = LLVector3d::zero)
{
this->audio_uuid = audio_uuid;
this->owner_id = owner_id;
this->gain = gain;
this->type = type;
this->pos_global = pos_global;
}
};
extern LLAudioEngine* gAudiop;

View File

@ -46,7 +46,7 @@ LLUUID const ANIM_AGENT_BLOW_KISS ("db84829b-462c-ee83-1e27-9bbee66b
LLUUID const ANIM_AGENT_BORED ("b906c4ba-703b-1940-32a3-0c7f7d791510");
LLUUID const ANIM_AGENT_BOW ("82e99230-c906-1403-4d9c-3889dd98daba");
LLUUID const ANIM_AGENT_BRUSH ("349a3801-54f9-bf2c-3bd0-1ac89772af01");
LLUUID const ANIM_AGENT_BUSY ("efcf670c-2d18-8128-973a-034ebc806b67");
LLUUID const ANIM_AGENT_DO_NOT_DISTURB ("efcf670c-2d18-8128-973a-034ebc806b67");
LLUUID const ANIM_AGENT_CLAP ("9b0c1c4e-8ac7-7969-1494-28c874c4f668");
LLUUID const ANIM_AGENT_COURTBOW ("9ba1c942-08be-e43a-fb29-16ad440efc50");
LLUUID const ANIM_AGENT_CROUCH ("201f3fdf-cb1f-dbec-201f-7333e328ae7c");
@ -211,7 +211,7 @@ LLAnimationLibrary::LLAnimationLibrary() :
mAnimMap[ANIM_AGENT_BORED]= mAnimStringTable.addString("express_bored");
mAnimMap[ANIM_AGENT_BOW]= mAnimStringTable.addString("bow");
mAnimMap[ANIM_AGENT_BRUSH]= mAnimStringTable.addString("brush");
mAnimMap[ANIM_AGENT_BUSY]= mAnimStringTable.addString("busy");
mAnimMap[ANIM_AGENT_DO_NOT_DISTURB]= mAnimStringTable.addString("busy");
mAnimMap[ANIM_AGENT_CLAP]= mAnimStringTable.addString("clap");
mAnimMap[ANIM_AGENT_COURTBOW]= mAnimStringTable.addString("courtbow");
mAnimMap[ANIM_AGENT_CROUCH]= mAnimStringTable.addString("crouch");

View File

@ -56,7 +56,7 @@ extern const LLUUID ANIM_AGENT_BLOW_KISS;
extern const LLUUID ANIM_AGENT_BORED;
extern const LLUUID ANIM_AGENT_BOW;
extern const LLUUID ANIM_AGENT_BRUSH;
extern const LLUUID ANIM_AGENT_BUSY;
extern const LLUUID ANIM_AGENT_DO_NOT_DISTURB;
extern const LLUUID ANIM_AGENT_CLAP;
extern const LLUUID ANIM_AGENT_COURTBOW;
extern const LLUUID ANIM_AGENT_CROUCH;

View File

@ -95,6 +95,7 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false));
addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false));
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE));
};

View File

@ -112,6 +112,9 @@ public:
AT_WIDGET = 40,
// UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...)
AT_PERSON = 45,
// A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop.
AT_MESH = 49,
// Mesh data in our proprietary SLM format

View File

@ -30,6 +30,7 @@
#include "llavatarname.h"
#include "lldate.h"
#include "llframetimer.h"
#include "llsd.h"
// Store these in pre-built std::strings to avoid memory allocations in
@ -42,6 +43,14 @@ static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");
static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");
static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update");
bool LLAvatarName::sUseDisplayNames = true;
// Minimum time-to-live (in seconds) for a name entry.
// Avatar name should always guarantee to expire reasonably soon by default
// so if the failure to get a valid expiration time was due to something temporary
// we will eventually request and get the right data.
const F64 MIN_ENTRY_LIFETIME = 60.0;
LLAvatarName::LLAvatarName()
: mUsername(),
mDisplayName(),
@ -61,6 +70,17 @@ bool LLAvatarName::operator<(const LLAvatarName& rhs) const
return mUsername < rhs.mUsername;
}
//static
void LLAvatarName::setUseDisplayNames(bool use)
{
sUseDisplayNames = use;
}
//static
bool LLAvatarName::useDisplayNames()
{
return sUseDisplayNames;
}
LLSD LLAvatarName::asLLSD() const
{
LLSD sd;
@ -85,36 +105,120 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
mExpires = expires.secondsSinceEpoch();
LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];
mNextUpdate = next_update.secondsSinceEpoch();
// Some avatars don't have explicit display names set. Force a legible display name here.
if (mDisplayName.empty())
{
mDisplayName = mUsername;
}
}
// Transform a string (typically provided by the legacy service) into a decent
// avatar name instance.
void LLAvatarName::fromString(const std::string& full_name)
{
mDisplayName = full_name;
std::string::size_type index = full_name.find(' ');
if (index != std::string::npos)
{
// The name is in 2 parts (first last)
mLegacyFirstName = full_name.substr(0, index);
mLegacyLastName = full_name.substr(index+1);
if (mLegacyLastName != "Resident")
{
mUsername = mLegacyFirstName + "." + mLegacyLastName;
mDisplayName = full_name;
LLStringUtil::toLower(mUsername);
}
else
{
// Very old names do have a dummy "Resident" last name
// that we choose to hide from users.
mUsername = mLegacyFirstName;
mDisplayName = mLegacyFirstName;
}
}
else
{
mLegacyFirstName = full_name;
mLegacyLastName = "";
mUsername = full_name;
mDisplayName = full_name;
}
mIsDisplayNameDefault = true;
mIsTemporaryName = true;
setExpires(MIN_ENTRY_LIFETIME);
}
void LLAvatarName::setExpires(F64 expires)
{
mExpires = LLFrameTimer::getTotalSeconds() + expires;
}
std::string LLAvatarName::getCompleteName() const
{
std::string name;
if (mUsername.empty() || mIsDisplayNameDefault)
// If the display name feature is off
// OR this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
if (sUseDisplayNames)
{
name = mDisplayName;
if (mUsername.empty() || mIsDisplayNameDefault)
{
// If this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
name = mDisplayName;
}
else
{
name = mDisplayName + " (" + mUsername + ")";
}
}
else
{
name = mDisplayName + " (" + mUsername + ")";
name = getUserName();
}
return name;
}
std::string LLAvatarName::getLegacyName() const
std::string LLAvatarName::getDisplayName() const
{
if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled?
if (sUseDisplayNames)
{
return mDisplayName;
}
else
{
return getUserName();
}
}
std::string LLAvatarName::getUserName() const
{
std::string name;
name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() );
name = mLegacyFirstName;
name += " ";
name += mLegacyLastName;
if (mLegacyLastName.empty() || (mLegacyLastName == "Resident"))
{
if (mLegacyFirstName.empty())
{
// If we cannot create a user name from the legacy strings, use the display name
name = mDisplayName;
}
else
{
// The last name might be empty if it defaulted to "Resident"
name = mLegacyFirstName;
}
}
else
{
name = mLegacyFirstName + " " + mLegacyLastName;
}
return name;
}
void LLAvatarName::dump() const
{
LL_DEBUGS("AvNameCache") << "LLAvatarName: "
<< "user '" << mUsername << "' "
<< "display '" << mDisplayName << "' "
<< "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
}

View File

@ -39,23 +39,62 @@ public:
bool operator<(const LLAvatarName& rhs) const;
// Conversion to and from LLSD (cache file or server response)
LLSD asLLSD() const;
void fromLLSD(const LLSD& sd);
// Used only in legacy mode when the display name capability is not provided server side
// or to otherwise create a temporary valid item.
void fromString(const std::string& full_name);
// Set the name object to become invalid in "expires" seconds from now
void setExpires(F64 expires);
// Set and get the display name flag set by the user in preferences.
static void setUseDisplayNames(bool use);
static bool useDisplayNames();
// A name object is valid if not temporary and not yet expired (default is expiration not checked)
bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); }
// Return true if the name is made up from legacy or temporary data
bool isDisplayNameDefault() const { return mIsDisplayNameDefault; }
// For normal names, returns "James Linden (james.linden)"
// When display names are disabled returns just "James Linden"
std::string getCompleteName() const;
// "José Sanchez" or "James Linden", UTF-8 encoded Unicode
// Takes the display name preference into account. This is truly the name that should
// be used for all UI where an avatar name has to be used unless we truly want something else (rare)
std::string getDisplayName() const;
// Returns "James Linden" or "bobsmith123 Resident"
// Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name
// Also used for backwards compatibility with systems like voice and muting
std::string getUserName() const;
// Returns "james.linden" or the legacy name for very old names
std::string getAccountName() const { return mUsername; }
// Returns "James Linden" or "bobsmith123 Resident" for backwards
// compatibility with systems like voice and muting
// *TODO: Eliminate this in favor of username only
std::string getLegacyName() const;
// Debug print of the object
void dump() const;
// Names can change, so need to keep track of when name was
// last checked.
// Unix time-from-epoch seconds for efficiency
F64 mExpires;
// You can only change your name every N hours, so record
// when the next update is allowed
// Unix time-from-epoch seconds
F64 mNextUpdate;
private:
// "bobsmith123" or "james.linden", US-ASCII only
std::string mUsername;
// "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode
// "José Sanchez" or "James Linden", UTF-8 encoded Unicode
// Contains data whether or not user has explicitly set
// a display name; may duplicate their username.
std::string mDisplayName;
@ -81,15 +120,9 @@ public:
// shown in UI, but are not serialized.
bool mIsTemporaryName;
// Names can change, so need to keep track of when name was
// last checked.
// Unix time-from-epoch seconds for efficiency
F64 mExpires;
// You can only change your name every N hours, so record
// when the next update is allowed
// Unix time-from-epoch seconds
F64 mNextUpdate;
// Global flag indicating if display name should be used or not
// This will affect the output of the high level "get" methods
static bool sUseDisplayNames;
};
#endif

0
indra/llcommon/llfoldertype.h Normal file → Executable file
View File

View File

@ -194,13 +194,6 @@ public:
return mHandle;
}
protected:
typedef LLHandle<T> handle_type_t;
LLHandleProvider()
{
// provided here to enforce T deriving from LLHandleProvider<T>
}
template <typename U>
LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const
{
@ -209,6 +202,12 @@ protected:
return downcast_handle;
}
protected:
typedef LLHandle<T> handle_type_t;
LLHandleProvider()
{
// provided here to enforce T deriving from LLHandleProvider<T>
}
private:
mutable LLRootHandle<T> mHandle;

View File

@ -40,7 +40,9 @@ namespace LLInitParam
{
const U8* my_addr = reinterpret_cast<const U8*>(this);
const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block);
mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr);
U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr);
mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff;
mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16;
}
//
@ -112,6 +114,35 @@ namespace LLInitParam
std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams));
}
void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name)
{
// create a copy of the param descriptor in mAllParams
// so other data structures can store a pointer to it
mAllParams.push_back(in_param);
ParamDescriptorPtr param(mAllParams.back());
std::string name(char_name);
if ((size_t)param->mParamHandle > mMaxParamOffset)
{
llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
}
if (name.empty())
{
mUnnamedParams.push_back(param);
}
else
{
// don't use insert, since we want to overwrite existing entries
mNamedParams[name] = param;
}
if (param->mValidationFunc)
{
mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
}
}
BlockDescriptor::BlockDescriptor()
: mMaxParamOffset(0),
mInitializationState(UNINITIALIZED),
@ -150,7 +181,8 @@ namespace LLInitParam
bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent)
{
if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true))
Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end());
if (!deserializeBlock(p, range, true))
{
if (!silent)
{
@ -196,12 +228,7 @@ namespace LLInitParam
if (serialize_func)
{
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
// each param descriptor remembers its serial number
// so we can inspect the same param under different names
// and see that it has the same number
name_stack.push_back(std::make_pair("", true));
serialize_func(*param, parser, name_stack, diff_param);
name_stack.pop_back();
}
}
@ -295,7 +322,7 @@ namespace LLInitParam
return true;
}
bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored)
bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored)
{
BlockDescriptor& block_data = mostDerivedBlockDescriptor();
bool names_left = name_stack_range.first != name_stack_range.second;
@ -308,15 +335,12 @@ namespace LLInitParam
{
const std::string& top_name = name_stack_range.first->first;
ParamDescriptor::deserialize_func_t deserialize_func = NULL;
Param* paramp = NULL;
BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name);
if (found_it != block_data.mNamedParams.end())
{
// find pointer to member parameter from offset table
paramp = getParamFromHandle(found_it->second->mParamHandle);
deserialize_func = found_it->second->mDeserializeFunc;
Param* paramp = getParamFromHandle(found_it->second->mParamHandle);
ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc;
Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second);
++new_name_stack.first;
@ -358,36 +382,6 @@ namespace LLInitParam
return false;
}
//static
void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
{
// create a copy of the param descriptor in mAllParams
// so other data structures can store a pointer to it
block_data.mAllParams.push_back(in_param);
ParamDescriptorPtr param(block_data.mAllParams.back());
std::string name(char_name);
if ((size_t)param->mParamHandle > block_data.mMaxParamOffset)
{
llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl;
}
if (name.empty())
{
block_data.mUnnamedParams.push_back(param);
}
else
{
// don't use insert, since we want to overwrite existing entries
block_data.mNamedParams[name] = param;
}
if (param->mValidationFunc)
{
block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc));
}
}
void BaseBlock::addSynonym(Param& param, const std::string& synonym)
{
BlockDescriptor& block_data = mostDerivedBlockDescriptor();
@ -460,7 +454,7 @@ namespace LLInitParam
if (merge_func)
{
Param* paramp = getParamFromHandle((*it)->mParamHandle);
llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle);
llassert(paramp->getEnclosingBlockOffset() == (*it)->mParamHandle);
some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@
* semantics: one instance per process, rather than one instance per module as
* sometimes happens with data simply declared static.
*/
class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
class LL_COMMON_API LLInstanceTrackerBase
{
protected:
/// Get a process-unique void* pointer slot for the specified type_info
@ -210,6 +210,9 @@ protected:
virtual const KEY& getKey() const { return mInstanceKey; }
private:
LLInstanceTracker( const LLInstanceTracker& );
const LLInstanceTracker& operator=( const LLInstanceTracker& );
void add_(KEY key)
{
mInstanceKey = key;

View File

@ -27,6 +27,7 @@
#define LLREFCOUNT_H
#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#define LL_REF_COUNT_DEBUG 0
#if LL_REF_COUNT_DEBUG
@ -86,4 +87,22 @@ private:
#endif
};
/**
* intrusive pointer support
* this allows you to use boost::intrusive_ptr with any LLRefCount-derived type
*/
namespace boost
{
inline void intrusive_ptr_add_ref(LLRefCount* p)
{
p->ref();
}
inline void intrusive_ptr_release(LLRefCount* p)
{
p->unref();
}
};
#endif

View File

@ -307,6 +307,10 @@ public:
virtual ~StaticRegistrar() {}
StaticRegistrar(ref_const_key_t key, ref_const_value_t value)
{
if (singleton_t::instance().exists(key))
{
llerrs << "Duplicate registry entry under key \"" << key << "\"" << llendl;
}
singleton_t::instance().mStaticScope->add(key, value);
}
};

View File

@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
{
bool new_traversal = it->second;
LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first];
if (child_sd->isArray())
LLSD* child_sd;
if (it->first.empty())
{
child_sd = sd_to_write;
if (child_sd->isUndefined())
{
*child_sd = LLSD::emptyArray();
}
if (new_traversal)
{
// write to new element at end
@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
}
else
{
if (new_traversal
&& child_sd->isDefined()
&& !child_sd->isArray())
{
// copy child contents into first element of an array
LLSD new_array = LLSD::emptyArray();
new_array.append(*child_sd);
// assign array to slot that previously held the single value
*child_sd = new_array;
// return next element in that array
sd_to_write = &((*child_sd)[1]);
}
else
{
sd_to_write = child_sd;
}
sd_to_write = &(*sd_to_write)[it->first];
}
it->second = false;
}
@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI
it != sd.endArray();
++it)
{
stack.back().second = true;
stack.push_back(make_pair(std::string(), true));
readSDValues(cb, *it, stack);
stack.pop_back();
}
}
else if (sd.isUndefined())
@ -313,8 +303,14 @@ namespace LLInitParam
{
// LLSD specialization
// block param interface
bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name)
bool ParamValue<LLSD, NOT_BLOCK>::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name)
{
if (name_stack.first == name_stack.second
&& p.readValue<LLSD>(mValue))
{
return true;
}
LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);
LLSD::String string;
@ -328,15 +324,18 @@ namespace LLInitParam
}
//static
void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)
void ParamValue<LLSD, NOT_BLOCK>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)
{
p.writeValue<LLSD::String>(sd.asString(), name_stack);
}
void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
{
// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
Parser::name_stack_t stack;
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack);
// attempt to write LLSD out directly
if (!p.writeValue<LLSD>(mValue, name_stack))
{
// otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack);
}
}
}

View File

@ -30,6 +30,7 @@
#include "llapp.h"
#include "llapr.h"
#include "apr_thread_cond.h"
#include "boost/intrusive_ptr.hpp"
class LLThread;
class LLMutex;
@ -284,6 +285,22 @@ private:
S32 mRef;
};
/**
* intrusive pointer support for LLThreadSafeRefCount
* this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type
*/
namespace boost
{
inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)
{
p->ref();
}
inline void intrusive_ptr_release(LLThreadSafeRefCount* p)
{
p->unref();
}
};
//============================================================================
// Simple responder for self destructing callbacks

View File

@ -28,8 +28,8 @@
#define LL_LLVERSIONVIEWER_H
const S32 LL_VERSION_MAJOR = 3;
const S32 LL_VERSION_MINOR = 4;
const S32 LL_VERSION_PATCH = 5;
const S32 LL_VERSION_MINOR = 5;
const S32 LL_VERSION_PATCH = 0;
const S32 LL_VERSION_BUILD = 0;
const char * const LL_CHANNEL = "Second Life Developer";

View File

@ -51,7 +51,8 @@ enum EDragAndDropType
DAD_LINK = 14,
DAD_MESH = 15,
DAD_WIDGET = 16,
DAD_COUNT = 17, // number of types in this enum
DAD_PERSON = 17,
DAD_COUNT = 18, // number of types in this enum
};
// Reasons for drags to be denied.

View File

@ -580,8 +580,13 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void
const size_t body_size(op->mReqBody->size());
if (body_size <= op->mCurlBodyPos)
{
LL_WARNS("HttpCore") << "Request body position beyond body size. Aborting request."
<< LL_ENDL;
if (body_size < op->mCurlBodyPos)
{
// Warn but continue if the read position moves beyond end-of-body
// for some reason.
LL_WARNS("HttpCore") << "Request body position beyond body size. Truncating request body."
<< LL_ENDL;
}
return 0;
}

View File

@ -75,13 +75,15 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid,
mUUID(uuid),
mParentUUID(parent_uuid),
mType(type),
mName(name)
mName(name),
mCreationDate(0)
{
correctInventoryName(mName);
}
LLInventoryObject::LLInventoryObject() :
mType(LLAssetType::AT_NONE)
mType(LLAssetType::AT_NONE),
mCreationDate(0)
{
}
@ -275,6 +277,18 @@ void LLInventoryObject::correctInventoryName(std::string& name)
LLStringUtil::truncate(name, DB_INV_ITEM_NAME_STR_LEN);
}
time_t LLInventoryObject::getCreationDate() const
{
return mCreationDate;
}
void LLInventoryObject::setCreationDate(time_t creation_date_utc)
{
mCreationDate = creation_date_utc;
}
///----------------------------------------------------------------------------
/// Class LLInventoryItem
@ -297,9 +311,10 @@ LLInventoryItem::LLInventoryItem(const LLUUID& uuid,
mDescription(desc),
mSaleInfo(sale_info),
mInventoryType(inv_type),
mFlags(flags),
mCreationDate(creation_date_utc)
mFlags(flags)
{
mCreationDate = creation_date_utc;
LLStringUtil::replaceNonstandardASCII(mDescription, ' ');
LLStringUtil::replaceChar(mDescription, '|', ' ');
mPermissions.initMasks(inv_type);
@ -312,9 +327,9 @@ LLInventoryItem::LLInventoryItem() :
mDescription(),
mSaleInfo(),
mInventoryType(LLInventoryType::IT_NONE),
mFlags(0),
mCreationDate(0)
mFlags(0)
{
mCreationDate = 0;
}
LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) :
@ -379,11 +394,6 @@ const std::string& LLInventoryItem::getDescription() const
return mDescription;
}
time_t LLInventoryItem::getCreationDate() const
{
return mCreationDate;
}
U32 LLInventoryItem::getCRC32() const
{
// *FIX: Not a real crc - more of a checksum.
@ -440,11 +450,6 @@ void LLInventoryItem::setFlags(U32 flags)
mFlags = flags;
}
void LLInventoryItem::setCreationDate(time_t creation_date_utc)
{
mCreationDate = creation_date_utc;
}
// Currently only used in the Viewer to handle calling cards
// where the creator is actually used to store the target.
void LLInventoryItem::setCreator(const LLUUID& creator)
@ -506,6 +511,12 @@ U32 LLInventoryItem::getFlags() const
return mFlags;
}
time_t LLInventoryItem::getCreationDate() const
{
return mCreationDate;
}
// virtual
void LLInventoryItem::packMessage(LLMessageSystem* msg) const
{

View File

@ -73,6 +73,7 @@ public:
virtual LLAssetType::EType getType() const;
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
BOOL getIsLinkType() const;
virtual time_t getCreationDate() const;
//--------------------------------------------------------------------
// Mutators
@ -83,6 +84,7 @@ public:
virtual void rename(const std::string& new_name);
void setParent(const LLUUID& new_parent);
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
private:
// in place correction for inventory name string
@ -111,6 +113,7 @@ protected:
LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL.
LLAssetType::EType mType;
std::string mName;
time_t mCreationDate; // seconds from 1/1/1970, UTC
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -175,7 +178,6 @@ public:
void setPermissions(const LLPermissions& perm);
void setInventoryType(LLInventoryType::EType inv_type);
void setFlags(U32 flags);
void setCreationDate(time_t creation_date_utc);
void setCreator(const LLUUID& creator); // only used for calling cards
// Check for changes in permissions masks and sale info
@ -221,7 +223,6 @@ protected:
LLSaleInfo mSaleInfo;
LLInventoryType::EType mInventoryType;
U32 mFlags;
time_t mCreationDate; // seconds from 1/1/1970, UTC
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -85,6 +85,7 @@ LLInventoryDictionary::LLInventoryDictionary()
addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE));
addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH));
addEntry(LLInventoryType::IT_WIDGET, new InventoryEntry("widget", "widget", 1, LLAssetType::AT_WIDGET));
addEntry(LLInventoryType::IT_PERSON, new InventoryEntry("person", "person", 1, LLAssetType::AT_PERSON));
}
@ -140,7 +141,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // 42 AT_NONE
LLInventoryType::IT_NONE, // 43 AT_NONE
LLInventoryType::IT_NONE, // 44 AT_NONE
LLInventoryType::IT_NONE, // 45 AT_NONE
LLInventoryType::IT_PERSON, // 45 AT_PERSON
LLInventoryType::IT_NONE, // 46 AT_NONE
LLInventoryType::IT_NONE, // 47 AT_NONE
LLInventoryType::IT_NONE, // 48 AT_NONE

View File

@ -63,7 +63,8 @@ public:
IT_GESTURE = 20,
IT_MESH = 22,
IT_WIDGET = 23,
IT_COUNT = 24,
IT_PERSON = 24,
IT_COUNT = 25,
IT_NONE = -1
};

View File

@ -43,26 +43,26 @@ namespace LLAvatarNameCache
{
use_display_name_signal_t mUseDisplayNamesSignal;
// Manual override for display names - can disable even if the region
// supports it.
bool sUseDisplayNames = true;
// Cache starts in a paused state until we can determine if the
// current region supports display names.
bool sRunning = false;
// Use the People API (modern) for fetching name if true. Use the old legacy protocol if false.
// For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer).
bool sUsePeopleAPI = true;
// Base lookup URL for name service.
// On simulator, loaded from indra.xml
// On viewer, usually a simulator capability (at People API team's request)
// Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/"
std::string sNameLookupURL;
// accumulated agent IDs for next query against service
// Accumulated agent IDs for next query against service
typedef std::set<LLUUID> ask_queue_t;
ask_queue_t sAskQueue;
// agent IDs that have been requested, but with no reply
// maps agent ID to frame time request was made
// Agent IDs that have been requested, but with no reply.
// Maps agent ID to frame time request was made.
typedef std::map<LLUUID, F64> pending_queue_t;
pending_queue_t sPendingQueue;
@ -73,21 +73,21 @@ namespace LLAvatarNameCache
typedef std::map<LLUUID, callback_signal_t*> signal_map_t;
signal_map_t sSignalMap;
// names we know about
// The cache at last, i.e. avatar names we know about.
typedef std::map<LLUUID, LLAvatarName> cache_t;
cache_t sCache;
// Send bulk lookup requests a few times a second at most
// only need per-frame timing resolution
// Send bulk lookup requests a few times a second at most.
// Only need per-frame timing resolution.
LLFrameTimer sRequestTimer;
/// Maximum time an unrefreshed cache entry is allowed
// Maximum time an unrefreshed cache entry is allowed.
const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0;
/// Time when unrefreshed cached names were checked last
// Time when unrefreshed cached names were checked last.
static F64 sLastExpireCheck;
/// Time-to-live for a temp cache entry.
// Time-to-live for a temp cache entry.
const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0;
//-----------------------------------------------------------------------
@ -95,26 +95,21 @@ namespace LLAvatarNameCache
//-----------------------------------------------------------------------
// Handle name response off network.
// Optionally skip adding to cache, used when this is a fallback to the
// legacy name system.
void processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache);
const LLAvatarName& av_name);
void requestNamesViaCapability();
// Legacy name system callback
// Legacy name system callbacks
void legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group
);
bool is_group);
void legacyNameFetch(const LLUUID& agent_id,
const std::string& full_name,
bool is_group);
void requestNamesViaLegacy();
// Fill in an LLAvatarName with the legacy name data
void buildLegacyName(const std::string& full_name,
LLAvatarName* av_name);
// Do a single callback to a given slot
void fireSignal(const LLUUID& agent_id,
const callback_slot_t& slot,
@ -209,20 +204,11 @@ public:
// Use expiration time from header
av_name.mExpires = expires;
// Some avatars don't have explicit display names set
if (av_name.mDisplayName.empty())
{
av_name.mDisplayName = av_name.mUsername;
}
LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " "
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << expires - now << " seconds"
<< LL_ENDL;
LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL;
av_name.dump();
// cache it and fire signals
LLAvatarNameCache::processName(agent_id, av_name, true);
LLAvatarNameCache::processName(agent_id, av_name);
}
// Same logic as error response case
@ -279,40 +265,34 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id)
LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent "
<< agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
boost::bind(&LLAvatarNameCache::legacyNameFetch, _1, _2, _3));
}
else
{
// we have a chached (but probably expired) entry - since that would have
// we have a cached (but probably expired) entry - since that would have
// been returned by the get method, there is no need to signal anyone
// Clear this agent from the pending list
LLAvatarNameCache::sPendingQueue.erase(agent_id);
LLAvatarName& av_name = existing->second;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent "
<< agent_id
<< "user '" << av_name.mUsername << "' "
<< "display '" << av_name.mDisplayName << "' "
<< "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds"
<< LL_ENDL;
av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest.
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << LL_ENDL;
av_name.dump();
// Reset expiry time so we don't constantly rerequest.
av_name.setExpires(TEMP_CACHE_ENTRY_LIFETIME);
}
}
void LLAvatarNameCache::processName(const LLUUID& agent_id,
const LLAvatarName& av_name,
bool add_to_cache)
void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (add_to_cache)
{
sCache[agent_id] = av_name;
}
// Add to the cache
sCache[agent_id] = av_name;
// Suppress request from the queue
sPendingQueue.erase(agent_id);
// signal everyone waiting on this name
// Signal everyone waiting on this name
signal_map_t::iterator sig_it = sSignalMap.find(agent_id);
if (sig_it != sSignalMap.end())
{
@ -389,22 +369,33 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id,
const std::string& full_name,
bool is_group)
{
// Construct a dummy record for this name. By convention, SLID is blank
// Never expires, but not written to disk, so lasts until end of session.
LLAvatarName av_name;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback "
<< "agent " << agent_id << " "
<< "full name '" << full_name << "'"
<< ( is_group ? " [group]" : "" )
<< LL_ENDL;
buildLegacyName(full_name, &av_name);
// Put the received data in the cache
legacyNameFetch(agent_id, full_name, is_group);
// Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy
// protocol, we do not get an expiration date for each name and there's no reason to ask the
// data again and again so we set the expiration time to the largest value admissible.
std::map<LLUUID,LLAvatarName>::iterator av_record = sCache.find(agent_id);
LLAvatarName& av_name = av_record->second;
av_name.setExpires(MAX_UNREFRESHED_TIME);
}
// Add to cache, because if we don't we'll keep rerequesting the
// same record forever. buildLegacyName should always guarantee
// that these records expire reasonably soon
// (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due
// to something temporary we will eventually request and get the right data.
processName(agent_id, av_name, true);
void LLAvatarNameCache::legacyNameFetch(const LLUUID& agent_id,
const std::string& full_name,
bool is_group)
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameFetch "
<< "agent " << agent_id << " "
<< "full name '" << full_name << "'"
<< ( is_group ? " [group]" : "" )
<< LL_ENDL;
// Construct an av_name record from this name.
LLAvatarName av_name;
av_name.fromString(full_name);
// Add to cache: we're still using the new cache even if we're using the old (legacy) protocol.
processName(agent_id, av_name);
}
void LLAvatarNameCache::requestNamesViaLegacy()
@ -426,18 +417,19 @@ void LLAvatarNameCache::requestNamesViaLegacy()
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL;
gCacheName->get(agent_id, false, // legacy compatibility
boost::bind(&LLAvatarNameCache::legacyNameCallback,
_1, _2, _3));
boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3));
}
}
void LLAvatarNameCache::initClass(bool running)
void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI)
{
sRunning = running;
sUsePeopleAPI = usePeopleAPI;
}
void LLAvatarNameCache::cleanupClass()
{
sCache.clear();
}
void LLAvatarNameCache::importFile(std::istream& istr)
@ -476,7 +468,7 @@ void LLAvatarNameCache::exportFile(std::ostream& ostr)
const LLUUID& agent_id = it->first;
const LLAvatarName& av_name = it->second;
// Do not write temporary or expired entries to the stored cache
if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed)
if (av_name.isValidName(max_unrefreshed))
{
// key must be a string
agents[agent_id.asString()] = av_name.asLLSD();
@ -497,6 +489,11 @@ bool LLAvatarNameCache::hasNameLookupURL()
return !sNameLookupURL.empty();
}
bool LLAvatarNameCache::usePeopleAPI()
{
return hasNameLookupURL() && sUsePeopleAPI;
}
void LLAvatarNameCache::idle()
{
// By convention, start running at first idle() call
@ -513,13 +510,12 @@ void LLAvatarNameCache::idle()
if (!sAskQueue.empty())
{
if (useDisplayNames())
if (usePeopleAPI())
{
requestNamesViaCapability();
}
else
{
// ...fall back to legacy name cache system
requestNamesViaLegacy();
}
}
@ -564,7 +560,7 @@ void LLAvatarNameCache::eraseUnrefreshed()
if (av_name.mExpires < max_unrefreshed)
{
LL_DEBUGS("AvNameCache") << it->first
<< " user '" << av_name.mUsername << "' "
<< " user '" << av_name.getAccountName() << "' "
<< "expired " << now - av_name.mExpires << " secs ago"
<< LL_ENDL;
sCache.erase(it++);
@ -578,20 +574,6 @@ void LLAvatarNameCache::eraseUnrefreshed()
}
}
void LLAvatarNameCache::buildLegacyName(const std::string& full_name,
LLAvatarName* av_name)
{
llassert(av_name);
av_name->mUsername = "";
av_name->mDisplayName = full_name;
av_name->mIsDisplayNameDefault = true;
av_name->mIsTemporaryName = true;
av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME;
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName "
<< full_name
<< LL_ENDL;
}
// fills in av_name if it has it in the cache, even if expired (can check expiry time)
// returns bool specifying if av_name was filled, false otherwise
bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
@ -599,38 +581,24 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name)
if (sRunning)
{
// ...only do immediate lookups when cache is running
if (useDisplayNames())
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
// ...use display names cache
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
*av_name = it->second;
*av_name = it->second;
// re-request name if entry is expired
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
{
if (!isRequestPending(agent_id))
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "refresh agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
}
return true;
}
}
else
{
// ...use legacy names cache
std::string full_name;
if (gCacheName->getFullName(agent_id, full_name))
// re-request name if entry is expired
if (av_name->mExpires < LLFrameTimer::getTotalSeconds())
{
buildLegacyName(full_name, av_name);
return true;
if (!isRequestPending(agent_id))
{
LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get "
<< "refresh agent " << agent_id
<< LL_ENDL;
sAskQueue.insert(agent_id);
}
}
return true;
}
}
@ -661,30 +629,14 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag
if (sRunning)
{
// ...only do immediate lookups when cache is running
if (useDisplayNames())
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
{
// ...use new cache
std::map<LLUUID,LLAvatarName>::iterator it = sCache.find(agent_id);
if (it != sCache.end())
const LLAvatarName& av_name = it->second;
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
{
const LLAvatarName& av_name = it->second;
if (av_name.mExpires > LLFrameTimer::getTotalSeconds())
{
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return connection;
}
}
}
else
{
// ...use old name system
std::string full_name;
if (gCacheName->getFullName(agent_id, full_name))
{
LLAvatarName av_name;
buildLegacyName(full_name, &av_name);
// ...name already exists in cache, fire callback now
fireSignal(agent_id, slot, av_name);
return connection;
}
@ -719,22 +671,13 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag
void LLAvatarNameCache::setUseDisplayNames(bool use)
{
if (use != sUseDisplayNames)
if (use != LLAvatarName::useDisplayNames())
{
sUseDisplayNames = use;
// flush our cache
sCache.clear();
LLAvatarName::setUseDisplayNames(use);
mUseDisplayNamesSignal();
}
}
bool LLAvatarNameCache::useDisplayNames()
{
// Must be both manually set on and able to look up names.
return sUseDisplayNames && !sNameLookupURL.empty();
}
void LLAvatarNameCache::erase(const LLUUID& agent_id)
{
sCache.erase(agent_id);

View File

@ -37,33 +37,33 @@ class LLUUID;
namespace LLAvatarNameCache
{
typedef boost::signals2::signal<void (void)> use_display_name_signal_t;
// Until the cache is set running, immediate lookups will fail and
// async lookups will be queued. This allows us to block requests
// until we know if the first region supports display names.
void initClass(bool running);
void initClass(bool running, bool usePeopleAPI);
void cleanupClass();
// Import/export the name cache to file.
void importFile(std::istream& istr);
void exportFile(std::ostream& ostr);
// On the viewer, usually a simulator capabilitity
// If empty, name cache will fall back to using legacy name
// lookup system
// On the viewer, usually a simulator capabilitity.
// If empty, name cache will fall back to using legacy name lookup system.
void setNameLookupURL(const std::string& name_lookup_url);
// Do we have a valid lookup URL, hence are we trying to use the
// new display name lookup system?
// Do we have a valid lookup URL, i.e. are we trying to use the
// more recent display name lookup system?
bool hasNameLookupURL();
bool usePeopleAPI();
// Periodically makes a batch request for display names not already in
// cache. Call once per frame.
// cache. Called once per frame.
void idle();
// If name is in cache, returns true and fills in provided LLAvatarName
// otherwise returns false
// otherwise returns false.
bool get(const LLUUID& agent_id, LLAvatarName *av_name);
// Callback types for get() below
@ -73,21 +73,19 @@ namespace LLAvatarNameCache
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
// Fetches name information and calls callback.
// If name information is in cache, callback will be called immediately.
// Fetches name information and calls callbacks.
// If name information is in cache, callbacks will be called immediately.
callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot);
// Allow display names to be explicitly disabled for testing.
// Set display name: flips the switch and triggers the callbacks.
void setUseDisplayNames(bool use);
bool useDisplayNames();
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
void erase(const LLUUID& agent_id);
/// Provide some fallback for agents that return errors
/// Provide some fallback for agents that return errors.
void handleAgentError(const LLUUID& agent_id);
void insert(const LLUUID& agent_id, const LLAvatarName& av_name);
// Compute name expiration time from HTTP Cache-Control header,
// or return default value, in seconds from epoch.
F64 nameExpirationFromHeaders(LLSD headers);

View File

@ -523,6 +523,7 @@ std::string LLCacheName::cleanFullName(const std::string& full_name)
}
//static
// Transform hard-coded name provided by server to a more legible username
std::string LLCacheName::buildUsername(const std::string& full_name)
{
// rare, but handle hard-coded error names returned from server
@ -548,8 +549,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name)
return username;
}
// if the input wasn't a correctly formatted legacy name just return it unchanged
return full_name;
// if the input wasn't a correctly formatted legacy name, just return it
// cleaned up from a potential terminal "Resident"
return cleanFullName(full_name);
}
//static

View File

@ -40,7 +40,7 @@ typedef boost::signals2::signal<void (const LLUUID& id,
bool is_group)> LLCacheNameSignal;
typedef LLCacheNameSignal::slot_type LLCacheNameCallback;
// Old callback with user data for compatability
// Old callback with user data for compatibility
typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*);
// Here's the theory:

View File

@ -156,18 +156,6 @@ const S32 DB_USER_SKILLS_BUF_SIZE = 255;
const S32 DB_NV_NAME_STR_LEN = 128;
const S32 DB_NV_NAME_BUF_SIZE = 129;
// votes.vote_text varchar(254)
const S32 DB_VOTE_TEXT_STR_LEN = 254;
const S32 DB_VOTE_TEXT_BUF_SIZE = 255;
// vpte type text varchar(9)
const S32 DB_VOTE_TYPE_STR_LEN = 9;
const S32 DB_VOTE_TYPE_BUF_SIZE = 10;
// vote result text
const S32 DB_VOTE_RESULT_BUF_LEN = 8;
const S32 DB_VOTE_RESULT_BUF_SIZE = 9;
// user_start_location.location_name varchar(254)
const S32 DB_START_LOCATION_STR_LEN = 254;
const S32 DB_START_LOCATION_BUF_SIZE = 255;

View File

@ -43,14 +43,6 @@
const U8 IM_ONLINE = 0;
const U8 IM_OFFLINE = 1;
const S32 VOTE_YES = 1;
const S32 VOTE_NO = 0;
const S32 VOTE_ABSTAIN = -1;
const S32 VOTE_MAJORITY = 0;
const S32 VOTE_SUPER_MAJORITY = 1;
const S32 VOTE_UNANIMOUS = 2;
const char EMPTY_BINARY_BUCKET[] = "";
const S32 EMPTY_BINARY_BUCKET_SIZE = 1;
const U32 NO_TIMESTAMP = 0;
@ -69,7 +61,6 @@ LLIMInfo::LLIMInfo() :
mViewerThinksToIsOnline(false),
mIMType(IM_NOTHING_SPECIAL),
mTimeStamp(0),
mSource(IM_FROM_SIM),
mTTL(IM_TTL)
{
}
@ -88,7 +79,6 @@ LLIMInfo::LLIMInfo(
LLSD data,
U8 offline,
U32 timestamp,
EIMSource source,
S32 ttl) :
mFromID(from_id),
mFromGroup(from_group),
@ -104,14 +94,12 @@ LLIMInfo::LLIMInfo(
mName(name),
mMessage(message),
mData(data),
mSource(source),
mTTL(ttl)
{
}
LLIMInfo::LLIMInfo(LLMessageSystem* msg, EIMSource source, S32 ttl) :
LLIMInfo::LLIMInfo(LLMessageSystem* msg, S32 ttl) :
mViewerThinksToIsOnline(false),
mSource(source),
mTTL(ttl)
{
unpackMessageBlock(msg);
@ -326,7 +314,6 @@ LLSD im_info_to_llsd(LLPointer<LLIMInfo> im_info)
param_message["region_id"] = im_info->mRegionID;
param_message["position"] = ll_sd_from_vector3(im_info->mPosition);
param_message["data"] = im_info->mData;
param_message["source"]= im_info->mSource;
param_message["ttl"] = im_info->mTTL;
LLSD param_agent;
@ -359,7 +346,6 @@ LLPointer<LLIMInfo> llsd_to_im_info(const LLSD& im_info_sd)
param_message["data"],
(U8) param_message["offline"].asInteger(),
(U32) param_message["timestamp"].asInteger(),
(EIMSource)param_message["source"].asInteger(),
param_message["ttl"].asInteger());
return im_info;
@ -381,7 +367,6 @@ LLPointer<LLIMInfo> LLIMInfo::clone()
mData,
mOffline,
mTimeStamp,
mSource,
mTTL);
}

View File

@ -115,8 +115,8 @@ enum EInstantMessage
// viewer, since you can't IM an object yet.
IM_FROM_TASK = 19,
// sent an IM to a busy user, this is the auto response
IM_BUSY_AUTO_RESPONSE = 20,
// sent an IM to a do not disturb user, this is the auto response
IM_DO_NOT_DISTURB_AUTO_RESPONSE = 20,
// Shows the message in the console and chat history
IM_CONSOLE_AND_CHAT_HISTORY = 21,
@ -164,57 +164,9 @@ enum EInstantMessage
};
// Hooks for quickly hacking in experimental admin debug messages
// without needing to recompile the viewer
// *NOTE: This functionality has been moved to be a string based
// operation so that we don't even have to do a full recompile. This
// enumeration will be phased out soon.
enum EGodlikeRequest
{
GOD_WANTS_NOTHING,
// for requesting physics information about an object
GOD_WANTS_PHYSICS_INFO,
// two unused requests that can be appropriated for debug
// purposes (no viewer recompile necessary)
GOD_WANTS_FOO,
GOD_WANTS_BAR,
// to dump simulator terrain data to terrain.raw file
GOD_WANTS_TERRAIN_SAVE,
// to load simulator terrain data from terrain.raw file
GOD_WANTS_TERRAIN_LOAD,
GOD_WANTS_TOGGLE_AVATAR_GEOMETRY, // HACK for testing new avatar geom
// real-time telehub operations
GOD_WANTS_TELEHUB_INFO,
GOD_WANTS_CONNECT_TELEHUB,
GOD_WANTS_DELETE_TELEHUB,
GOD_WANTS_ADD_TELEHUB_SPAWNPOINT,
GOD_WANTS_REMOVE_TELEHUB_SPAWNPOINT,
};
enum EIMSource
{
IM_FROM_VIEWER,
IM_FROM_DATASERVER,
IM_FROM_SIM
};
extern const U8 IM_ONLINE;
extern const U8 IM_OFFLINE;
extern const S32 VOTE_YES;
extern const S32 VOTE_NO;
extern const S32 VOTE_ABSTAIN;
extern const S32 VOTE_MAJORITY;
extern const S32 VOTE_SUPER_MAJORITY;
extern const S32 VOTE_UNANIMOUS;
extern const char EMPTY_BINARY_BUCKET[];
extern const S32 EMPTY_BINARY_BUCKET_SIZE;
@ -234,7 +186,6 @@ protected:
public:
LLIMInfo(LLMessageSystem* msg,
EIMSource source = IM_FROM_SIM,
S32 ttl = IM_TTL);
LLIMInfo(
@ -251,7 +202,6 @@ public:
LLSD data,
U8 offline,
U32 timestamp,
EIMSource source,
S32 ttl = IM_TTL);
void packInstantMessage(LLMessageSystem* msg) const;
@ -274,7 +224,6 @@ public:
std::string mMessage;
LLSD mData;
EIMSource mSource;
S32 mTTL;
};

View File

@ -599,6 +599,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
if(!fgi)
{
fgi = mFontFreetype->getGlyphInfo(wch);
if (NULL == fgi)
{
return 0;
}
}
// account for glyphs that run beyond the starting point for the next glyphs

View File

@ -597,11 +597,6 @@ bool LLGLManager::initGL()
if (mGLVendor.substr(0,4) == "ATI ")
{
mGLVendorShort = "ATI";
BOOL mobile = FALSE;
if (mGLRenderer.find("MOBILITY") != std::string::npos)
{
mobile = TRUE;
}
mIsATI = TRUE;
#if LL_WINDOWS && !LL_MESA_HEADLESS
@ -1489,9 +1484,7 @@ void assert_glerror()
void clear_glerror()
{
// Create or update texture to be used with this data
GLenum error;
error = glGetError();
glGetError();
}
///////////////////////////////////////////////////////////////

View File

@ -33,6 +33,7 @@ set(llui_SOURCE_FILES
llbadgeholder.cpp
llbadgeowner.cpp
llbutton.cpp
llchatentry.cpp
llcheckboxctrl.cpp
llclipboard.cpp
llcombobox.cpp
@ -46,12 +47,16 @@ set(llui_SOURCE_FILES
lleditmenuhandler.cpp
llf32uictrl.cpp
llfiltereditor.cpp
llflashtimer.cpp
llflatlistview.cpp
llfloater.cpp
llfloaterreg.cpp
llfloaterreglistener.cpp
llflyoutbutton.cpp
llfocusmgr.cpp
llfolderview.cpp
llfolderviewitem.cpp
llfolderviewmodel.cpp
llfunctorregistry.cpp
lliconctrl.cpp
llkeywords.cpp
@ -66,7 +71,6 @@ set(llui_SOURCE_FILES
llmultislider.cpp
llmultisliderctrl.cpp
llnotifications.cpp
llnotificationslistener.cpp
llnotificationsutil.cpp
llpanel.cpp
llprogressbar.cpp
@ -135,6 +139,7 @@ set(llui_HEADER_FILES
llbadgeowner.h
llbutton.h
llcallbackmap.h
llchatentry.h
llcheckboxctrl.h
llclipboard.h
llcombobox.h
@ -148,12 +153,16 @@ set(llui_HEADER_FILES
lleditmenuhandler.h
llf32uictrl.h
llfiltereditor.h
llflashtimer.h
llflatlistview.h
llfloater.h
llfloaterreg.h
llfloaterreglistener.h
llflyoutbutton.h
llfocusmgr.h
llfolderview.h
llfolderviewitem.h
llfolderviewmodel.h
llfunctorregistry.h
llhelp.h
lliconctrl.h
@ -171,7 +180,6 @@ set(llui_HEADER_FILES
llmultislider.h
llnotificationptr.h
llnotifications.h
llnotificationslistener.h
llnotificationsutil.h
llnotificationtemplate.h
llnotificationvisibilityrule.h

View File

@ -184,7 +184,7 @@ void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string
if (mHeaderTextbox)
{
std::string text = mHeaderTextbox->getText();
mStyleParams.font(mHeaderTextbox->getDefaultFont());
mStyleParams.font(mHeaderTextbox->getFont());
mStyleParams.font.style(style);
mHeaderTextbox->setText(text, mStyleParams);
}

View File

@ -105,6 +105,7 @@ LLButton::Params::Params()
badge("badge"),
handle_right_mouse("handle_right_mouse"),
held_down_delay("held_down_delay"),
button_flash_enable("button_flash_enable", false),
button_flash_count("button_flash_count"),
button_flash_rate("button_flash_rate")
{
@ -171,9 +172,24 @@ LLButton::LLButton(const LLButton::Params& p)
mHeldDownSignal(NULL),
mUseDrawContextAlpha(p.use_draw_context_alpha),
mHandleRightMouse(p.handle_right_mouse),
mButtonFlashCount(p.button_flash_count),
mButtonFlashRate(p.button_flash_rate)
mFlashingTimer(NULL)
{
if (p.button_flash_enable)
{
// If optional parameter "p.button_flash_count" is not provided, LLFlashTimer will be
// used instead it a "default" value from gSavedSettings.getS32("FlashCount")).
// Likewise, missing "p.button_flash_rate" is replaced by gSavedSettings.getF32("FlashPeriod").
// Note: flashing should be allowed in settings.xml (boolean key "EnableButtonFlashing").
S32 flash_count = p.button_flash_count.isProvided()? p.button_flash_count : 0;
F32 flash_rate = p.button_flash_rate.isProvided()? p.button_flash_rate : 0.0;
mFlashingTimer = new LLFlashTimer ((LLFlashTimer::callback_t)NULL, flash_count, flash_rate);
}
else
{
mButtonFlashCount = p.button_flash_count;
mButtonFlashRate = p.button_flash_rate;
}
static LLUICachedControl<S32> llbutton_orig_h_pad ("UIButtonOrigHPad", 0);
static Params default_params(LLUICtrlFactory::getDefaultParams<LLButton>());
@ -267,6 +283,11 @@ LLButton::~LLButton()
delete mMouseDownSignal;
delete mMouseUpSignal;
delete mHeldDownSignal;
if (mFlashingTimer)
{
mFlashingTimer->unset();
}
}
// HACK: Committing a button is the same as instantly clicking it.
@ -591,22 +612,6 @@ void LLButton::draw()
{
static LLCachedControl<bool> sEnableButtonFlashing(*LLUI::sSettingGroups["config"], "EnableButtonFlashing", true);
F32 alpha = mUseDrawContextAlpha ? getDrawContext().mAlpha : getCurrentTransparency();
bool flash = FALSE;
if( mFlashing)
{
if ( sEnableButtonFlashing)
{
F32 elapsed = mFlashingTimer.getElapsedTimeF32();
S32 flash_count = S32(elapsed * mButtonFlashRate * 2.f);
// flash on or off?
flash = (flash_count % 2 == 0) || flash_count > S32((F32)mButtonFlashCount * 2.f);
}
else
{ // otherwise just highlight button in flash color
flash = true;
}
}
bool pressed_by_keyboard = FALSE;
if (hasFocus())
@ -631,9 +636,21 @@ void LLButton::draw()
bool selected = getToggleState();
bool use_glow_effect = FALSE;
LLColor4 glow_color = LLColor4::white;
LLColor4 highlighting_color = LLColor4::white;
LLColor4 glow_color;
LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA;
LLUIImage* imagep = NULL;
// Cancel sticking of color, if the button is pressed,
// or when a flashing of the previously selected button is ended
if (mFlashingTimer
&& ((selected && !mFlashingTimer->isFlashingInProgress()) || pressed))
{
mFlashing = false;
}
bool flash = mFlashing && sEnableButtonFlashing;
if (pressed && mDisplayPressedState)
{
imagep = selected ? mImagePressedSelected : mImagePressed;
@ -699,15 +716,20 @@ void LLButton::draw()
imagep = mImageFlash;
}
// else use usual flashing via flash_color
else
else if (mFlashingTimer)
{
LLColor4 flash_color = mFlashBgColor.get();
use_glow_effect = TRUE;
glow_type = LLRender::BT_ALPHA; // blend the glow
if (mNeedsHighlight) // highlighted AND flashing
glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity
else
if (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress())
{
glow_color = flash_color;
}
else if (mNeedsHighlight)
{
glow_color = highlighting_color;
}
}
}
@ -756,8 +778,7 @@ void LLButton::draw()
if (use_glow_effect)
{
mCurGlowStrength = lerp(mCurGlowStrength,
mFlashing ? (flash? 1.0 : 0.0)
: mHoverGlowStrength,
mFlashing ? (mFlashingTimer->isCurrentlyHighlighted() || !mFlashingTimer->isFlashingInProgress() || mNeedsHighlight? 1.0 : 0.0) : mHoverGlowStrength,
LLCriticalDamp::getInterpolant(0.05f));
}
else
@ -944,21 +965,26 @@ void LLButton::setToggleState(BOOL b)
{
setControlValue(b); // will fire LLControlVariable callbacks (if any)
setValue(b); // may or may not be redundant
setFlashing(false); // stop flash state whenever the selected/unselected state if reset
// Unselected label assignments
autoResize();
}
}
void LLButton::setFlashing( BOOL b )
void LLButton::setFlashing(bool b)
{
if ((bool)b != mFlashing)
if (mFlashingTimer)
{
mFlashing = b;
mFlashingTimer.reset();
(b ? mFlashingTimer->startFlashing() : mFlashingTimer->stopFlashing());
}
else if (b != mFlashing)
{
mFlashing = b;
mFrameTimer.reset();
}
}
BOOL LLButton::toggleState()
{
bool flipped = ! getToggleState();

View File

@ -30,6 +30,7 @@
#include "lluuid.h"
#include "llbadgeowner.h"
#include "llcontrol.h"
#include "llflashtimer.h"
#include "lluictrl.h"
#include "v4color.h"
#include "llframetimer.h"
@ -133,6 +134,7 @@ public:
Optional<bool> handle_right_mouse;
Optional<bool> button_flash_enable;
Optional<S32> button_flash_count;
Optional<F32> button_flash_rate;
@ -199,8 +201,9 @@ public:
void setToggleState(BOOL b);
void setHighlight(bool b);
void setFlashing( BOOL b );
void setFlashing( bool b );
BOOL getFlashing() const { return mFlashing; }
LLFlashTimer* getFlashTimer() {return mFlashingTimer;}
void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; }
LLFontGL::HAlign getHAlign() const { return mHAlign; }
@ -373,7 +376,8 @@ protected:
bool mForcePressedState;
bool mDisplayPressedState;
LLFrameTimer mFlashingTimer;
LLFrameTimer mFrameTimer;
LLFlashTimer * mFlashingTimer;
bool mHandleRightMouse;
};

257
indra/llui/llchatentry.cpp Normal file
View File

@ -0,0 +1,257 @@
/**
* @file llchatentry.cpp
* @brief LLChatEntry implementation
*
* $LicenseInfo:firstyear=2001&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 "linden_common.h"
#include "llscrollcontainer.h"
#include "llchatentry.h"
static LLDefaultChildRegistry::Register<LLChatEntry> r("chat_editor");
LLChatEntry::Params::Params()
: has_history("has_history", true),
is_expandable("is_expandable", false),
expand_lines_count("expand_lines_count", 1)
{}
LLChatEntry::LLChatEntry(const Params& p)
: LLTextEditor(p),
mTextExpandedSignal(NULL),
mHasHistory(p.has_history),
mIsExpandable(p.is_expandable),
mExpandLinesCount(p.expand_lines_count),
mPrevLinesCount(0),
mSingleLineMode(false),
mPrevExpandedLineCount(S32_MAX)
{
// Initialize current history line iterator
mCurrentHistoryLine = mLineHistory.begin();
mAutoIndent = false;
}
LLChatEntry::~LLChatEntry()
{
delete mTextExpandedSignal;
}
void LLChatEntry::draw()
{
if(mIsExpandable)
{
expandText();
}
LLTextEditor::draw();
}
void LLChatEntry::onCommit()
{
updateHistory();
LLTextEditor::onCommit();
}
boost::signals2::connection LLChatEntry::setTextExpandedCallback(const commit_signal_t::slot_type& cb)
{
if (!mTextExpandedSignal)
{
mTextExpandedSignal = new commit_signal_t();
}
return mTextExpandedSignal->connect(cb);
}
void LLChatEntry::expandText()
{
S32 line_count = mSingleLineMode ? 1 : mExpandLinesCount;
int visible_lines_count = llabs(getVisibleLines(true).first - getVisibleLines(true).second);
bool can_changed = getLineCount() <= line_count || line_count < mPrevExpandedLineCount ;
mPrevExpandedLineCount = line_count;
// true if pasted text has more lines than expand height limit and expand limit is not reached yet
bool text_pasted = (getLineCount() > line_count) && (visible_lines_count < line_count);
if (mIsExpandable && (can_changed || text_pasted || mSingleLineMode) && getLineCount() != mPrevLinesCount)
{
int lines_height = 0;
if (text_pasted)
{
// text is pasted and now mLineInfoList.size() > mExpandLineCounts and mLineInfoList is not empty,
// so lines_height is the sum of the last 'expanded_line_count' lines height
lines_height = (mLineInfoList.end() - line_count)->mRect.mTop - mLineInfoList.back().mRect.mBottom;
}
else
{
lines_height = mLineInfoList.begin()->mRect.mTop - mLineInfoList.back().mRect.mBottom;
}
int height = mVPad * 2 + lines_height;
LLRect doc_rect = getRect();
doc_rect.setOriginAndSize(doc_rect.mLeft, doc_rect.mBottom, doc_rect.getWidth(), height);
setShape(doc_rect);
mPrevLinesCount = getLineCount();
if (mTextExpandedSignal)
{
(*mTextExpandedSignal)(this, LLSD() );
}
needsReflow();
}
}
// line history support
void LLChatEntry::updateHistory()
{
// On history enabled, remember committed line and
// reset current history line number.
// Be sure only to remember lines that are not empty and that are
// different from the last on the list.
if (mHasHistory && getLength())
{
// Add text to history, ignoring duplicates
if (mLineHistory.empty() || getText() != mLineHistory.back())
{
mLineHistory.push_back(getText());
}
mCurrentHistoryLine = mLineHistory.end();
}
}
void LLChatEntry::beforeValueChange()
{
if(this->getLength() == 0 && !mLabel.empty())
{
this->clearSegments();
}
}
void LLChatEntry::onValueChange(S32 start, S32 end)
{
//Internally resetLabel() must meet a condition before it can reset the label
resetLabel();
}
bool LLChatEntry::useLabel()
{
return !getLength() && !mLabel.empty();
}
void LLChatEntry::onFocusReceived()
{
}
void LLChatEntry::onFocusLost()
{
}
BOOL LLChatEntry::handleSpecialKey(const KEY key, const MASK mask)
{
BOOL handled = FALSE;
// In the case of a chat entry, pressing RETURN when something is selected
// should NOT erase the selection (unlike a notecard, for example)
if (key == KEY_RETURN)
{
endOfDoc();
startSelection();
endSelection();
}
LLTextEditor::handleSpecialKey(key, mask);
switch(key)
{
case KEY_RETURN:
if (MASK_NONE == mask)
{
needsReflow();
}
break;
case KEY_UP:
if (mHasHistory && MASK_CONTROL == mask)
{
if (!mLineHistory.empty() && mCurrentHistoryLine > mLineHistory.begin())
{
setText(*(--mCurrentHistoryLine));
endOfDoc();
}
else
{
LLUI::reportBadKeystroke();
}
handled = TRUE;
}
break;
case KEY_DOWN:
if (mHasHistory && MASK_CONTROL == mask)
{
if (!mLineHistory.empty() && mCurrentHistoryLine < (mLineHistory.end() - 1) )
{
setText(*(++mCurrentHistoryLine));
endOfDoc();
}
else if (!mLineHistory.empty() && mCurrentHistoryLine == (mLineHistory.end() - 1) )
{
mCurrentHistoryLine++;
std::string empty("");
setText(empty);
needsReflow();
endOfDoc();
}
else
{
LLUI::reportBadKeystroke();
}
handled = TRUE;
}
break;
default:
break;
}
return handled;
}
void LLChatEntry::enableSingleLineMode(bool single_line_mode)
{
if (mScroller)
{
mScroller->setSize(single_line_mode ? 0 : -1);
}
mSingleLineMode = single_line_mode;
mPrevLinesCount = -1;
setWordWrap(!single_line_mode);
}

106
indra/llui/llchatentry.h Normal file
View File

@ -0,0 +1,106 @@
/**
* @file llchatentry.h
* @author Paul Guslisty
* @brief Text editor widget which is used for user input
*
* Features:
* Optional line history so previous entries can be recalled by CTRL UP/DOWN
* Optional auto-resize behavior on input chat field
*
* $LicenseInfo:firstyear=2001&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 LLCHATENTRY_H_
#define LLCHATENTRY_H_
#include "lltexteditor.h"
class LLChatEntry : public LLTextEditor
{
public:
struct Params : public LLInitParam::Block<Params, LLTextEditor::Params>
{
Optional<bool> has_history,
is_expandable;
Optional<int> expand_lines_count;
Params();
};
virtual ~LLChatEntry();
protected:
friend class LLUICtrlFactory;
LLChatEntry(const Params& p);
/*virtual*/ void beforeValueChange();
/*virtual*/ void onValueChange(S32 start, S32 end);
/*virtual*/ bool useLabel();
public:
virtual void draw();
virtual void onCommit();
/*virtual*/ void onFocusReceived();
/*virtual*/ void onFocusLost();
void enableSingleLineMode(bool single_line_mode);
boost::signals2::connection setTextExpandedCallback(const commit_signal_t::slot_type& cb);
private:
/**
* Implements auto-resize behavior.
* When user's typing reaches the right edge of the chat field
* the chat field expands vertically by one line. The bottom of
* the chat field remains bottom-justified. The chat field does
* not expand beyond mExpandLinesCount.
*/
void expandText();
/**
* Implements line history so previous entries can be recalled by CTRL UP/DOWN
*/
void updateHistory();
BOOL handleSpecialKey(const KEY key, const MASK mask);
// Fired when text height expanded to mExpandLinesCount
commit_signal_t* mTextExpandedSignal;
// line history support:
typedef std::vector<std::string> line_history_t;
line_history_t::iterator mCurrentHistoryLine; // currently browsed history line
line_history_t mLineHistory; // line history storage
bool mHasHistory; // flag for enabled/disabled line history
bool mIsExpandable;
bool mSingleLineMode;
S32 mExpandLinesCount;
S32 mPrevLinesCount;
S32 mPrevExpandedLineCount;
};
#endif /* LLCHATENTRY_H_ */

View File

@ -107,7 +107,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p)
LLButton::Params params = p.check_button;
params.rect(btn_rect);
//params.control_name(p.control_name);
params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onButtonPress, this, _2));
params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onCommit, this));
params.commit_on_return(false);
// Checkboxes only allow boolean initial values, but buttons can
// take any LLSD.
@ -123,18 +123,6 @@ LLCheckBoxCtrl::~LLCheckBoxCtrl()
// Children all cleaned up by default view destructor.
}
// static
void LLCheckBoxCtrl::onButtonPress( const LLSD& data )
{
//if (mRadioStyle)
//{
// setValue(TRUE);
//}
onCommit();
}
void LLCheckBoxCtrl::onCommit()
{
if( getEnabled() )

View File

@ -103,8 +103,6 @@ public:
virtual void setControlName(const std::string& control_name, LLView* context);
void onButtonPress(const LLSD& data);
virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control.
virtual void resetDirty(); // Clear dirty state

View File

@ -63,6 +63,7 @@ LLCommand::Params::Params()
, is_running_parameters("is_running_parameters")
, is_starting_function("is_starting_function")
, is_starting_parameters("is_starting_parameters")
, is_flashing_allowed("is_flashing_allowed", false)
{
}
@ -83,6 +84,7 @@ LLCommand::LLCommand(const LLCommand::Params& p)
, mIsRunningParameters(p.is_running_parameters)
, mIsStartingFunction(p.is_starting_function)
, mIsStartingParameters(p.is_starting_parameters)
, mIsFlashingAllowed(p.is_flashing_allowed)
{
}

View File

@ -111,6 +111,8 @@ public:
Optional<std::string> is_starting_function;
Optional<LLSD> is_starting_parameters;
Optional<bool> is_flashing_allowed;
Params();
};
@ -138,6 +140,8 @@ public:
const std::string& isStartingFunctionName() const { return mIsStartingFunction; }
const LLSD& isStartingParameters() const { return mIsStartingParameters; }
bool isFlashingAllowed() const { return mIsFlashingAllowed; }
private:
LLCommandId mIdentifier;
@ -161,6 +165,8 @@ private:
std::string mIsStartingFunction;
LLSD mIsStartingParameters;
bool mIsFlashingAllowed;
};

View File

@ -31,7 +31,6 @@
LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
mDockWidget(dockWidget),
mDockableFloater(dockableFloater),
mDockTongue(dockTongue),
mDockTongueX(0),
@ -39,6 +38,11 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
{
mDockAt = dockAt;
if (dockWidget != NULL)
{
mDockWidgetHandle = dockWidget->getHandle();
}
if (dockableFloater->isDocked())
{
on();
@ -62,7 +66,7 @@ LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
repositionDockable();
}
if (mDockWidget != NULL)
if (getDock() != NULL)
{
mDockWidgetVisible = isDockVisible();
}
@ -78,14 +82,15 @@ LLDockControl::~LLDockControl()
void LLDockControl::setDock(LLView* dockWidget)
{
mDockWidget = dockWidget;
if (mDockWidget != NULL)
if (dockWidget != NULL)
{
mDockWidgetHandle = dockWidget->getHandle();
repositionDockable();
mDockWidgetVisible = isDockVisible();
}
else
{
mDockWidgetHandle = LLHandle<LLView>();
mDockWidgetVisible = false;
}
}
@ -97,8 +102,8 @@ void LLDockControl::getAllowedRect(LLRect& rect)
void LLDockControl::repositionDockable()
{
if (!mDockWidget) return;
LLRect dockRect = mDockWidget->calcScreenRect();
if (!getDock()) return;
LLRect dockRect = getDock()->calcScreenRect();
LLRect rootRect;
LLRect floater_rect = mDockableFloater->calcScreenRect();
mGetAllowedRectCallback(rootRect);
@ -150,13 +155,13 @@ bool LLDockControl::isDockVisible()
{
bool res = true;
if (mDockWidget != NULL)
if (getDock() != NULL)
{
//we should check all hierarchy
res = mDockWidget->isInVisibleChain();
res = getDock()->isInVisibleChain();
if (res)
{
LLRect dockRect = mDockWidget->calcScreenRect();
LLRect dockRect = getDock()->calcScreenRect();
switch (mDockAt)
{
@ -169,7 +174,7 @@ bool LLDockControl::isDockVisible()
// assume that parent for all dockable floaters
// is the root view
LLRect dockParentRect =
mDockWidget->getRootView()->calcScreenRect();
getDock()->getRootView()->calcScreenRect();
if (dockRect.mRight <= dockParentRect.mLeft
|| dockRect.mLeft >= dockParentRect.mRight)
{
@ -189,7 +194,7 @@ bool LLDockControl::isDockVisible()
void LLDockControl::moveDockable()
{
// calculate new dockable position
LLRect dockRect = mDockWidget->calcScreenRect();
LLRect dockRect = getDock()->calcScreenRect();
LLRect rootRect;
mGetAllowedRectCallback(rootRect);
@ -263,7 +268,7 @@ void LLDockControl::moveDockable()
// calculate dock tongue position
dockParentRect = mDockWidget->getParent()->calcScreenRect();
dockParentRect = getDock()->getParent()->calcScreenRect();
if (dockRect.getCenterX() < dockParentRect.mLeft)
{
mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
@ -299,7 +304,7 @@ void LLDockControl::moveDockable()
}
// calculate dock tongue position
dockParentRect = mDockWidget->getParent()->calcScreenRect();
dockParentRect = getDock()->getParent()->calcScreenRect();
if (dockRect.getCenterX() < dockParentRect.mLeft)
{
mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;

View File

@ -63,7 +63,7 @@ public:
void setDock(LLView* dockWidget);
LLView* getDock()
{
return mDockWidget;
return mDockWidgetHandle.get();
}
void repositionDockable();
void drawToungue();
@ -83,7 +83,7 @@ private:
bool mRecalculateDockablePosition;
bool mDockWidgetVisible;
DocAt mDockAt;
LLView* mDockWidget;
LLHandle<LLView> mDockWidgetHandle;
LLRect mPrevDockRect;
LLRect mRootRect;
LLRect mFloaterRect;

100
indra/llui/llflashtimer.cpp Normal file
View File

@ -0,0 +1,100 @@
/**
* @file llflashtimer.cpp
* @brief LLFlashTimer class implementation
*
* $LicenseInfo:firstyear=2002&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 "../newview/llviewerprecompiledheaders.h"
#include "llflashtimer.h"
#include "../newview/llviewercontrol.h"
#include "lleventtimer.h"
LLFlashTimer::LLFlashTimer(callback_t cb, S32 count, F32 period)
: LLEventTimer(period)
, mCallback(cb)
, mCurrentTickCount(0)
, mIsFlashingInProgress(false)
, mIsCurrentlyHighlighted(false)
, mUnset(false)
{
mEventTimer.stop();
// By default use settings from settings.xml to be able change them via Debug settings. See EXT-5973.
// Due to Timer is implemented as derived class from EventTimer it is impossible to change period
// in runtime. So, both settings are made as required restart.
mFlashCount = 2 * ((count > 0) ? count : gSavedSettings.getS32("FlashCount"));
if (mPeriod <= 0)
{
mPeriod = gSavedSettings.getF32("FlashPeriod");
}
}
void LLFlashTimer::unset()
{
mUnset = true;
mCallback = NULL;
}
BOOL LLFlashTimer::tick()
{
mIsCurrentlyHighlighted = !mIsCurrentlyHighlighted;
if (mCallback)
{
mCallback(mIsCurrentlyHighlighted);
}
if (++mCurrentTickCount >= mFlashCount)
{
stopFlashing();
}
return mUnset;
}
void LLFlashTimer::startFlashing()
{
mIsFlashingInProgress = true;
mIsCurrentlyHighlighted = true;
mEventTimer.start();
}
void LLFlashTimer::stopFlashing()
{
mEventTimer.stop();
mIsFlashingInProgress = false;
mIsCurrentlyHighlighted = false;
mCurrentTickCount = 0;
}
bool LLFlashTimer::isFlashingInProgress()
{
return mIsFlashingInProgress;
}
bool LLFlashTimer::isCurrentlyHighlighted()
{
return mIsCurrentlyHighlighted;
}

73
indra/llui/llflashtimer.h Normal file
View File

@ -0,0 +1,73 @@
/**
* @file llflashtimer.h
* @brief LLFlashTimer class implementation
*
* $LicenseInfo:firstyear=2002&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_FLASHTIMER_H
#define LL_FLASHTIMER_H
#include "lleventtimer.h"
class LLFlashTimer : public LLEventTimer
{
public:
typedef boost::function<void (bool)> callback_t;
/**
* Constructor.
*
* @param count - how many times callback should be called (twice to not change original state)
* @param period - how frequently callback should be called
* @param cb - callback to be called each tick
*/
LLFlashTimer(callback_t cb = NULL, S32 count = 0, F32 period = 0.0);
~LLFlashTimer() {};
/*virtual*/ BOOL tick();
void startFlashing();
void stopFlashing();
bool isFlashingInProgress();
bool isCurrentlyHighlighted();
/*
* Use this instead of deleting this object.
* The next call to tick() will return true and that will destroy this object.
*/
void unset();
private:
callback_t mCallback;
/**
* How many times parent will blink.
*/
S32 mFlashCount;
S32 mCurrentTickCount;
bool mIsCurrentlyHighlighted;
bool mIsFlashingInProgress;
bool mUnset;
};
#endif /* LL_FLASHTIMER_H */

View File

@ -64,6 +64,8 @@
// use this to control "jumping" behavior when Ctrl-Tabbing
const S32 TABBED_FLOATER_OFFSET = 0;
extern LLControlGroup gSavedSettings;
namespace LLInitParam
{
void TypeValues<LLFloaterEnums::EOpenPositioning>::declareValues()
@ -627,6 +629,17 @@ void LLFloater::setVisible( BOOL visible )
storeVisibilityControl();
}
void LLFloater::setIsSingleInstance(BOOL is_single_instance)
{
mSingleInstance = is_single_instance;
if (!mIsReuseInitialized)
{
mReuseInstance = is_single_instance; // reuse single-instance floaters by default
}
}
// virtual
void LLFloater::handleVisibilityChange ( BOOL new_visibility )
{
@ -642,14 +655,20 @@ void LLFloater::openFloater(const LLSD& key)
{
llinfos << "Opening floater " << getName() << llendl;
mKey = key; // in case we need to open ourselves again
if (getSoundFlags() != SILENT
// don't play open sound for hosted (tabbed) windows
&& !getHost()
&& !getFloaterHost()
&& (!getVisible() || isMinimized()))
{
make_ui_sound("UISndWindowOpen");
//Don't play a sound for incoming voice call based upon chat preference setting
bool playSound = !(getName() == "incoming call" && gSavedSettings.getBOOL("PlaySoundIncomingVoiceCall") == FALSE);
if(playSound)
{
make_ui_sound("UISndWindowOpen");
}
}
//RN: for now, we don't allow rehosting from one multifloater to another
@ -713,6 +732,33 @@ void LLFloater::closeFloater(bool app_quitting)
make_ui_sound("UISndWindowClose");
}
gFocusMgr.clearLastFocusForGroup(this);
if (hasFocus())
{
// Do this early, so UI controls will commit before the
// window is taken down.
releaseFocus();
// give focus to dependee floater if it exists, and we had focus first
if (isDependent())
{
LLFloater* dependee = mDependeeHandle.get();
if (dependee && !dependee->isDead())
{
dependee->setFocus(TRUE);
}
}
}
//If floater is a dependent, remove it from parent (dependee)
LLFloater* dependee = mDependeeHandle.get();
if (dependee)
{
dependee->removeDependentFloater(this);
}
// now close dependent floater
for(handle_set_iter_t dependent_it = mDependents.begin();
dependent_it != mDependents.end(); )
@ -731,28 +777,6 @@ void LLFloater::closeFloater(bool app_quitting)
}
cleanupHandles();
gFocusMgr.clearLastFocusForGroup(this);
if (hasFocus())
{
// Do this early, so UI controls will commit before the
// window is taken down.
releaseFocus();
// give focus to dependee floater if it exists, and we had focus first
if (isDependent())
{
LLFloater* dependee = mDependeeHandle.get();
if (dependee && !dependee->isDead())
{
dependee->setFocus(TRUE);
}
}
// STORM-1879: since this floater has focus, treat the closeFloater- call
// like a click on the close-button, and close gear- and contextmenus
LLMenuGL::sMenuContainer->hideMenus();
}
dirtyRect();
@ -788,6 +812,20 @@ void LLFloater::closeFloater(bool app_quitting)
}
}
/*virtual*/
void LLFloater::closeHostedFloater()
{
// When toggling *visibility*, close the host instead of the floater when hosted
if (getHost())
{
getHost()->closeFloater();
}
else
{
closeFloater();
}
}
/*virtual*/
void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent)
{
@ -1188,7 +1226,6 @@ void LLFloater::setMinimized(BOOL minimize)
{
// minimized flag should be turned on before release focus
mMinimized = TRUE;
mExpandedRect = getRect();
// If the floater has been dragged while minimized in the
@ -1261,7 +1298,6 @@ void LLFloater::setMinimized(BOOL minimize)
}
setOrigin( mExpandedRect.mLeft, mExpandedRect.mBottom );
if (mButtonsEnabled[BUTTON_RESTORE])
{
mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
@ -1297,7 +1333,6 @@ void LLFloater::setMinimized(BOOL minimize)
// Reshape *after* setting mMinimized
reshape( mExpandedRect.getWidth(), mExpandedRect.getHeight(), TRUE );
applyPositioning(NULL, false);
}
make_ui_sound("UISndWindowClose");
@ -1419,7 +1454,6 @@ void LLFloater::setHost(LLMultiFloater* host)
mButtonScale = 1.f;
//mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE;
}
updateTitleButtons();
if (host)
{
mHostHandle = host->getHandle();
@ -1429,6 +1463,8 @@ void LLFloater::setHost(LLMultiFloater* host)
{
mHostHandle.markDead();
}
updateTitleButtons();
}
void LLFloater::moveResizeHandlesToFront()
@ -1585,10 +1621,19 @@ void LLFloater::bringToFront( S32 x, S32 y )
// virtual
void LLFloater::setVisibleAndFrontmost(BOOL take_focus)
void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key)
{
setVisible(TRUE);
setFrontmost(take_focus);
LLMultiFloater* hostp = getHost();
if (hostp)
{
hostp->setVisible(TRUE);
hostp->setFrontmost(take_focus);
}
else
{
setVisible(TRUE);
setFrontmost(take_focus);
}
}
void LLFloater::setFrontmost(BOOL take_focus)
@ -1670,10 +1715,12 @@ void LLFloater::onClickTearOff(LLFloater* self)
gFloaterView->addChild(self);
self->openFloater(self->getKey());
// only force position for floaters that don't have that data saved
if (self->mRectControl.empty())
if (self->mSaveRect && !self->mRectControl.empty())
{
self->applyRectControl();
}
else
{ // only force position for floaters that don't have that data saved
new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight());
self->setRect(new_rect);
}
@ -1687,6 +1734,10 @@ void LLFloater::onClickTearOff(LLFloater* self)
LLMultiFloater* new_host = (LLMultiFloater*)self->mLastHostHandle.get();
if (new_host)
{
if (self->mSaveRect)
{
self->storeRectControl();
}
self->setMinimized(FALSE); // to reenable minimize button if it was minimized
new_host->showFloater(self);
// make sure host is visible
@ -1695,6 +1746,7 @@ void LLFloater::onClickTearOff(LLFloater* self)
self->setTornOff(false);
}
self->updateTitleButtons();
self->setOpenPositioning(LLFloaterEnums::POSITIONING_RELATIVE);
}
// static
@ -1720,6 +1772,18 @@ void LLFloater::onClickHelp( LLFloater* self )
}
}
void LLFloater::initRectControl()
{
// save_rect and save_visibility only apply to registered floaters
if (mSaveRect)
{
std::string ctrl_name = getControlName(mInstanceName, mKey);
mRectControl = LLFloaterReg::declareRectControl(ctrl_name);
mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name);
mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);
}
}
// static
void LLFloater::closeFrontmostFloater()
{
@ -2164,7 +2228,8 @@ LLFloaterView::LLFloaterView (const Params& p)
mFocusCycleMode(FALSE),
mMinimizePositionVOffset(0),
mSnapOffsetBottom(0),
mSnapOffsetRight(0)
mSnapOffsetRight(0),
mFrontChild(NULL)
{
mSnapView = getHandle();
}
@ -2313,6 +2378,17 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF
void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
{
if (mFrontChild == child)
{
if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
{
child->setFocus(TRUE);
}
return;
}
mFrontChild = child;
// *TODO: make this respect floater's mAutoFocus value, instead of
// using parameter
if (child->getHost())
@ -2320,15 +2396,14 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
// this floater is hosted elsewhere and hence not one of our children, abort
return;
}
std::vector<LLView*> floaters_to_move;
std::vector<LLFloater*> floaters_to_move;
// Look at all floaters...tab
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
for (child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it)
{
LLView* viewp = *child_it;
LLFloater *floater = (LLFloater *)viewp;
LLFloater* floater = dynamic_cast<LLFloater*>(*child_it);
// ...but if I'm a dependent floater...
if (child->isDependent())
if (floater && child->isDependent())
{
// ...look for floaters that have me as a dependent...
LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle());
@ -2336,15 +2411,14 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
if (found_dependent != floater->mDependents.end())
{
// ...and make sure all children of that floater (including me) are brought to front...
for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
dependent_it != floater->mDependents.end(); )
for (LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
dependent_it != floater->mDependents.end(); ++dependent_it)
{
LLFloater* sibling = dependent_it->get();
if (sibling)
{
floaters_to_move.push_back(sibling);
}
++dependent_it;
}
//...before bringing my parent to the front...
floaters_to_move.push_back(floater);
@ -2352,10 +2426,10 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
}
}
std::vector<LLView*>::iterator view_it;
for(view_it = floaters_to_move.begin(); view_it != floaters_to_move.end(); ++view_it)
std::vector<LLFloater*>::iterator floater_it;
for(floater_it = floaters_to_move.begin(); floater_it != floaters_to_move.end(); ++floater_it)
{
LLFloater* floaterp = (LLFloater*)(*view_it);
LLFloater* floaterp = *floater_it;
sendChildToFront(floaterp);
// always unminimize dependee, but allow dependents to stay minimized
@ -2367,23 +2441,19 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
floaters_to_move.clear();
// ...then bringing my own dependents to the front...
for(LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin();
dependent_it != child->mDependents.end(); )
for (LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin();
dependent_it != child->mDependents.end(); ++dependent_it)
{
LLFloater* dependent = dependent_it->get();
if (dependent)
{
sendChildToFront(dependent);
//don't un-minimize dependent windows automatically
// respect user's wishes
//dependent->setMinimized(FALSE);
}
++dependent_it;
}
// ...and finally bringing myself to front
// (do this last, so that I'm left in front at end of this call)
if( *getChildList()->begin() != child )
if (*beginChild() != child)
{
sendChildToFront(child);
}
@ -2923,21 +2993,14 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
void LLFloater::setInstanceName(const std::string& name)
{
if (name == mInstanceName)
return;
if (name != mInstanceName)
{
llassert_always(mInstanceName.empty());
mInstanceName = name;
if (!mInstanceName.empty())
{
std::string ctrl_name = getControlName(mInstanceName, mKey);
// save_rect and save_visibility only apply to registered floaters
if (mSaveRect)
{
mRectControl = LLFloaterReg::declareRectControl(ctrl_name);
mPosXControl = LLFloaterReg::declarePosXControl(ctrl_name);
mPosYControl = LLFloaterReg::declarePosYControl(ctrl_name);
}
initRectControl();
if (!mVisibilityControl.empty())
{
mVisibilityControl = LLFloaterReg::declareVisibilityControl(ctrl_name);
@ -2948,6 +3011,7 @@ void LLFloater::setInstanceName(const std::string& name)
}
}
}
}
void LLFloater::setKey(const LLSD& newkey)
{

View File

@ -217,13 +217,17 @@ public:
/*virtual*/ void setFocus( BOOL b );
/*virtual*/ void setIsChrome(BOOL is_chrome);
/*virtual*/ void setRect(const LLRect &rect);
void setIsSingleInstance(BOOL is_single_instance);
void initFloater(const Params& p);
void openFloater(const LLSD& key = LLSD());
// If allowed, close the floater cleanly, releasing focus.
void closeFloater(bool app_quitting = false);
virtual void closeFloater(bool app_quitting = false);
// Close the floater or its host. Use when hidding or toggling a floater instance.
virtual void closeHostedFloater();
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
@ -301,6 +305,7 @@ public:
/*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override
void setFrontmost(BOOL take_focus = TRUE);
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
// Defaults to false.
virtual BOOL canSaveAs() const { return FALSE; }
@ -324,6 +329,8 @@ public:
virtual void setDocked(bool docked, bool pop_on_undock = true);
virtual void setTornOff(bool torn_off) { mTornOff = torn_off; }
bool isTornOff() {return mTornOff;}
void setOpenPositioning(LLFloaterEnums::EOpenPositioning pos) {mPositioning = pos;}
// Close the floater returned by getFrontmostClosableFloater() and
@ -354,6 +361,7 @@ protected:
void stackWith(LLFloater& other);
virtual void initRectControl();
virtual bool applyRectControl();
bool applyDockState();
void applyPositioning(LLFloater* other, bool on_open);
@ -367,7 +375,6 @@ protected:
void setInstanceName(const std::string& name);
virtual void bringToFront(S32 x, S32 y);
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE);
void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized
const LLRect& getExpandedRect() const { return mExpandedRect; }
@ -441,9 +448,10 @@ private:
LLUIString mTitle;
LLUIString mShortTitle;
BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater
bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater
bool mReuseInstance; // true if we want to hide the floater when we close it instead of destroying it
bool mIsReuseInitialized; // true if mReuseInstance already set from parameters
std::string mInstanceName; // Store the instance name so we can remove ourselves from the list
BOOL mCanTearOff;
BOOL mCanMinimize;
@ -570,6 +578,7 @@ private:
S32 mMinimizePositionVOffset;
typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t;
hidden_floaters_t mHiddenFloaters;
LLFloater * mFrontChild;
};
//

View File

@ -264,17 +264,9 @@ bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key)
LLFloater* instance = findInstance(name, key);
if (instance)
{
// When toggling *visibility*, close the host instead of the floater when hosted
if (instance->getHost())
instance->getHost()->closeFloater();
else
instance->closeFloater();
return true;
}
else
{
return false;
instance->closeHostedFloater();
}
return (instance != NULL);
}
//static
@ -284,11 +276,7 @@ bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key)
LLFloater* instance = findInstance(name, key);
if (LLFloater::isShown(instance))
{
// When toggling *visibility*, close the host instead of the floater when hosted
if (instance->getHost())
instance->getHost()->closeFloater();
else
instance->closeFloater();
instance->closeHostedFloater();
return false;
}
else
@ -481,31 +469,58 @@ void LLFloaterReg::toggleInstanceOrBringToFront(const LLSD& sdname, const LLSD&
// * Also, if it is not on top, bring it forward when focus is given.
// * Else the target floater is open, close it.
//
std::string name = sdname.asString();
LLFloater* instance = getInstance(name, key);
if (!instance)
{
lldebugs << "Unable to get instance of floater '" << name << "'" << llendl;
return;
}
else if (instance->isMinimized())
// If hosted, we need to take that into account
LLFloater* host = instance->getHost();
if (host)
{
instance->setMinimized(FALSE);
instance->setVisibleAndFrontmost();
}
else if (!instance->isShown())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost();
}
else if (!instance->isFrontmost())
{
instance->setVisibleAndFrontmost();
if (host->isMinimized() || !host->isShown() || !host->isFrontmost())
{
host->setMinimized(FALSE);
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->getVisible())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
instance->setFocus(TRUE);
}
else
{
instance->closeHostedFloater();
}
}
else
{
instance->closeFloater();
if (instance->isMinimized())
{
instance->setMinimized(FALSE);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->isShown())
{
instance->openFloater(key);
instance->setVisibleAndFrontmost(true, key);
}
else if (!instance->isFrontmost())
{
instance->setVisibleAndFrontmost(true, key);
}
else
{
instance->closeHostedFloater();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -39,19 +39,16 @@
#include "lluictrl.h"
#include "v4color.h"
#include "lldarray.h"
#include "stdenums.h"
#include "lldepthstack.h"
#include "lleditmenuhandler.h"
#include "llfontgl.h"
#include "llscrollcontainer.h"
#include "lltooldraganddrop.h"
#include "llviewertexture.h"
class LLFolderViewEventListener;
class LLFolderViewModelInterface;
class LLFolderViewFolder;
class LLFolderViewItem;
class LLInventoryModel;
class LLFolderViewFilter;
class LLPanel;
class LLLineEditor;
class LLMenuGL;
@ -90,136 +87,104 @@ public:
struct Params : public LLInitParam::Block<Params, LLFolderViewFolder::Params>
{
Mandatory<LLPanel*> parent_panel;
Optional<LLUUID> task_id;
Optional<std::string> title;
Optional<bool> use_label_suffix,
allow_multiselect,
show_empty_message,
show_load_status,
use_ellipses;
use_ellipses,
show_item_link_overlays;
Mandatory<LLFolderViewModelInterface*> view_model;
Mandatory<std::string> options_menu;
Params();
};
friend class LLFolderViewScrollContainer;
typedef std::deque<LLFolderViewItem*> selected_items_t;
LLFolderView(const Params&);
virtual ~LLFolderView( void );
virtual BOOL canFocusChildren() const;
virtual const LLFolderView* getRoot() const { return this; }
virtual LLFolderView* getRoot() { return this; }
// FolderViews default to sort by name. This will change that,
// and resort the items if necessary.
void setSortOrder(U32 order);
void setFilterPermMask(PermissionMask filter_perm_mask);
LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; }
const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; }
typedef boost::signals2::signal<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)> signal_t;
void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); }
void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }
// filter is never null
LLInventoryFilter* getFilter();
const std::string getFilterSubString(BOOL trim = FALSE);
U32 getFilterObjectTypes() const;
PermissionMask getFilterPermissions() const;
// *NOTE: use getFilter()->getShowFolderState();
//LLInventoryFilter::EFolderShow getShowFolderState();
U32 getSortOrder() const;
BOOL isFilterModified();
bool getAllowMultiSelect() { return mAllowMultiSelect; }
// Close all folders in the view
void closeAllFolders();
void openTopLevelFolders();
virtual void toggleOpen() {};
virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse);
virtual BOOL addFolder( LLFolderViewFolder* folder);
virtual void addFolder( LLFolderViewFolder* folder);
// Find width and height of this object and its children. Also
// makes sure that this view and its children are the right size.
virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
virtual S32 arrange( S32* width, S32* height );
virtual S32 getItemHeight();
void arrangeAll() { mArrangeGeneration++; }
S32 getArrangeGeneration() { return mArrangeGeneration; }
// Apply filters to control visibility of inventory items
virtual void filter( LLInventoryFilter& filter);
// applies filters to control visibility of items
virtual void filter( LLFolderViewFilter& filter);
// Get the last selected item
virtual LLFolderViewItem* getCurSelectedItem( void );
selected_items_t& getSelectedItems( void );
// Record the selected item and pass it down the hierarchy.
virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem,
BOOL take_keyboard_focus);
BOOL take_keyboard_focus = TRUE);
// Used by menu callbacks
void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus);
// Called once a frame to update the selection if mSelectThisID has been set
void updateSelection();
// This method is used to toggle the selection of an item.
// Walks children and keeps track of selected objects.
// This method is used to toggle the selection of an item. Walks
// children, and keeps track of selected objects.
virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected);
virtual std::set<LLUUID> getSelectionList() const;
virtual std::set<LLFolderViewItem*> getSelectionList() const;
// Make sure if ancestor is selected, descendents are not
// Make sure if ancestor is selected, descendants are not
void sanitizeSelection();
void clearSelection();
virtual void clearSelection();
void addToSelectionList(LLFolderViewItem* item);
void removeFromSelectionList(LLFolderViewItem* item);
BOOL startDrag(LLToolDragAndDrop::ESource source);
bool startDrag();
void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; }
void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; }
LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; }
// Deletion functionality
void removeSelectedItems();
static void removeCutItems();
// Open the selected item
void openSelectedItems( void );
void propertiesSelectedItems( void );
// Change the folder type
void changeType(LLInventoryModel *model, LLFolderType::EType new_folder_type);
void autoOpenItem(LLFolderViewFolder* item);
void closeAutoOpenedFolders();
BOOL autoOpenTest(LLFolderViewFolder* item);
BOOL isOpen() const { return TRUE; } // root folder always open
// Copy & paste
virtual void copy();
virtual BOOL canCopy() const;
virtual void copy();
virtual void cut();
virtual BOOL canCut() const;
virtual void cut();
virtual void paste();
virtual BOOL canPaste() const;
virtual void doDelete();
virtual BOOL canDoDelete() const;
virtual void paste();
LLFolderViewItem* getNextUnselectedItem();
// Public rename functionality - can only start the process
void startRenamingSelectedItem( void );
// These functions were used when there was only one folderview,
// and relied on that concept. This functionality is now handled
// by the listeners and the lldraganddroptool.
//LLFolderViewItem* getMovingItem() { return mMovingItem; }
//void setMovingItem( LLFolderViewItem* item ) { mMovingItem = item; }
//void dragItemIntoFolder( LLFolderViewItem* moving_item, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept );
//void dragFolderIntoFolder( LLFolderViewFolder* moving_folder, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept );
// LLView functionality
///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent );
/*virtual*/ BOOL handleKeyHere( KEY key, MASK mask );
@ -250,16 +215,9 @@ public:
BOOL getShowSingleSelection() { return mShowSingleSelection; }
F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); }
bool getUseEllipses() { return mUseEllipses; }
S32 getSelectedCount() { return (S32)mSelectedItems.size(); }
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
LLFolderViewItem* getItemByID(const LLUUID& id);
LLFolderViewFolder* getFolderByID(const LLUUID& id);
bool doToSelected(LLInventoryModel* model, const LLSD& userdata);
void doIdle(); // Real idle routine
static void idle(void* user_data); // static glue to doIdle()
void update(); // needs to be called periodically (e.g. once per frame)
BOOL needsAutoSelect() { return mNeedsAutoSelect && !mAutoSelectOverride; }
BOOL needsAutoRename() { return mNeedsAutoRename; }
@ -267,9 +225,9 @@ public:
void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; }
void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; }
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
bool showItemLinkOverlays() { return mShowItemLinkOverlays; }
BOOL getDebugFilters() { return mDebugFilters; }
void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
LLPanel* getParentPanel() { return mParentPanel; }
// DEBUG only
@ -298,18 +256,15 @@ protected:
BOOL addNoOptions(LLMenuGL* menu) const;
void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response);
protected:
LLHandle<LLView> mPopupMenuHandle;
typedef std::deque<LLFolderViewItem*> selected_items_t;
selected_items_t mSelectedItems;
BOOL mKeyboardSelection;
BOOL mAllowMultiSelect;
BOOL mShowEmptyMessage;
BOOL mShowFolderHierarchy;
LLUUID mSourceID;
// Renaming variables and methods
LLFolderViewItem* mRenameItem; // The item currently being renamed
@ -322,15 +277,13 @@ protected:
BOOL mAutoSelectOverride;
BOOL mNeedsAutoRename;
bool mUseLabelSuffix;
bool mShowItemLinkOverlays;
BOOL mDebugFilters;
U32 mSortOrder;
LLDepthStack<LLFolderViewFolder> mAutoOpenItems;
LLFolderViewFolder* mAutoOpenCandidate;
LLFrameTimer mAutoOpenTimer;
LLFrameTimer mSearchTimer;
std::string mSearchString;
LLInventoryFilter* mFilter;
BOOL mShowSelectionContext;
BOOL mShowSingleSelection;
LLFrameTimer mMultiSelectionFadeTimer;
@ -340,13 +293,11 @@ protected:
signal_t mReshapeSignal;
S32 mSignalSelectCallback;
S32 mMinWidth;
S32 mRunningHeight;
std::map<LLUUID, LLFolderViewItem*> mItemMap;
BOOL mDragAndDropThisFrame;
LLUUID mSelectThisID; // if non null, select this item
LLPanel* mParentPanel;
LLFolderViewModelInterface* mViewModel;
/**
* Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll.
@ -367,11 +318,82 @@ public:
};
bool sort_item_name(LLFolderViewItem* a, LLFolderViewItem* b);
bool sort_item_date(LLFolderViewItem* a, LLFolderViewItem* b);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewFunctor
//
// Simple abstract base class for applying a functor to folders and
// items in a folder view hierarchy. This is suboptimal for algorithms
// that only work folders or only work on items, but I'll worry about
// that later when it's determined to be too slow.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderViewFunctor
{
public:
virtual ~LLFolderViewFunctor() {}
virtual void doFolder(LLFolderViewFolder* folder) = 0;
virtual void doItem(LLFolderViewItem* item) = 0;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLSelectFirstFilteredItem
//
// This will select the first *item* found in the hierarchy. If no item can be
// selected, the first matching folder will.
// Since doFolder() is done first but we prioritize item selection, we let the
// first filtered folder set the selection and raise a folder flag.
// The selection might be overridden by the first filtered item in doItem()
// which checks an item flag. Since doFolder() checks the item flag too, the first
// item will still be selected if items were to be done first and folders second.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLSelectFirstFilteredItem : public LLFolderViewFunctor
{
public:
LLSelectFirstFilteredItem() : mItemSelected(FALSE), mFolderSelected(FALSE) {}
virtual ~LLSelectFirstFilteredItem() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
BOOL wasItemSelected() { return mItemSelected || mFolderSelected; }
protected:
BOOL mItemSelected;
BOOL mFolderSelected;
};
class LLOpenFilteredFolders : public LLFolderViewFunctor
{
public:
LLOpenFilteredFolders() {}
virtual ~LLOpenFilteredFolders() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
};
class LLSaveFolderState : public LLFolderViewFunctor
{
public:
LLSaveFolderState() : mApply(FALSE) {}
virtual ~LLSaveFolderState() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item) {}
void setApply(BOOL apply);
void clearOpenFolders() { mOpenFolders.clear(); }
protected:
std::set<LLUUID> mOpenFolders;
BOOL mApply;
};
class LLOpenFoldersWithSelection : public LLFolderViewFunctor
{
public:
LLOpenFoldersWithSelection() {}
virtual ~LLOpenFoldersWithSelection() {}
virtual void doFolder(LLFolderViewFolder* folder);
virtual void doItem(LLFolderViewItem* item);
};
// Flags for buildContextMenu()
const U32 SUPPRESS_OPEN_ITEM = 0x1;
const U32 FIRST_SELECTED_ITEM = 0x2;
const U32 ITEM_IN_MULTI_SELECTION = 0x4;
#endif // LL_LLFOLDERVIEW_H

2095
indra/llui/llfolderviewitem.cpp Executable file

File diff suppressed because it is too large Load Diff

View File

@ -26,55 +26,16 @@
#ifndef LLFOLDERVIEWITEM_H
#define LLFOLDERVIEWITEM_H
#include "llflashtimer.h"
#include "llview.h"
#include "lldarray.h" // *TODO: Eliminate, forward declare
#include "lluiimage.h"
class LLFontGL;
class LLFolderView;
class LLFolderViewEventListener;
class LLFolderViewModelItem;
class LLFolderViewFolder;
class LLFolderViewFunctor;
class LLFolderViewItem;
class LLFolderViewListenerFunctor;
class LLInventoryFilter;
class LLMenuGL;
class LLUIImage;
class LLViewerInventoryItem;
// These are grouping of inventory types.
// Order matters when sorting system folders to the top.
enum EInventorySortGroup
{
SG_SYSTEM_FOLDER,
SG_TRASH_FOLDER,
SG_NORMAL_FOLDER,
SG_ITEM
};
// *TODO: do we really need one sort object per folder?
// can we just have one of these per LLFolderView ?
class LLInventorySort
{
public:
LLInventorySort()
: mSortOrder(0),
mByDate(false),
mSystemToTop(false),
mFoldersByName(false) { }
// Returns true if order has changed
bool updateSort(U32 order);
U32 getSort() { return mSortOrder; }
bool isByDate() { return mByDate; }
bool operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b);
private:
U32 mSortOrder;
bool mByDate;
bool mSystemToTop;
bool mFoldersByName;
};
class LLFolderViewFilter;
class LLFolderViewModelInterface;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewItem
@ -86,134 +47,130 @@ private:
class LLFolderViewItem : public LLView
{
public:
static void initClass();
static void cleanupClass();
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Optional<LLUIImage*> icon;
Optional<LLUIImage*> icon_open; // used for folders
Optional<LLUIImage*> icon_overlay; // for links
Optional<LLFolderView*> root;
Mandatory<LLFolderViewEventListener*> listener;
Optional<LLUIImage*> folder_arrow_image,
selection_image;
Mandatory<LLFolderView*> root;
Mandatory<LLFolderViewModelItem*> listener;
Optional<LLUIImage*> folder_arrow_image;
Optional<S32> folder_indentation; // pixels
Optional<LLUIImage*> selection_image;
Optional<S32> item_height; // pixels
Optional<S32> item_top_pad; // pixels
Optional<S32> folder_indentation, // pixels
item_height,
item_top_pad;
Optional<S32> creation_date; //UTC seconds
Optional<time_t> creation_date;
Optional<bool> allow_open;
Optional<LLUIColor> font_color;
Optional<LLUIColor> font_highlight_color;
Optional<S32> left_pad,
icon_pad,
icon_width,
text_pad,
text_pad_right,
arrow_size,
max_folder_item_overlap;
Params();
};
// layout constants
static const S32 LEFT_PAD = 5;
// LEFT_INDENTATION is set via folder_indentation above
static const S32 ICON_PAD = 2;
static const S32 ICON_WIDTH = 16;
static const S32 TEXT_PAD = 1;
static const S32 TEXT_PAD_RIGHT = 4;
static const S32 ARROW_SIZE = 12;
static const S32 MAX_FOLDER_ITEM_OVERLAP = 2;
static const S32 DEFAULT_LABEL_PADDING_RIGHT = 4;
// animation parameters
static const F32 FOLDER_CLOSE_TIME_CONSTANT;
static const F32 FOLDER_OPEN_TIME_CONSTANT;
// Mostly for debugging printout purposes.
const std::string& getSearchableLabel() { return mSearchableLabel; }
BOOL isLoading() const { return mIsLoading; }
private:
BOOL mIsSelected;
static const F32 FOLDER_CLOSE_TIME_CONSTANT,
FOLDER_OPEN_TIME_CONSTANT;
protected:
friend class LLUICtrlFactory;
friend class LLFolderViewEventListener;
friend class LLFolderViewModelItem;
LLFolderViewItem(const Params& p);
std::string mLabel;
std::string mSearchableLabel;
S32 mLabelWidth;
bool mLabelWidthDirty;
time_t mCreationDate;
S32 mLabelPaddingRight;
LLFolderViewFolder* mParentFolder;
LLFolderViewEventListener* mListener;
BOOL mIsCurSelection;
BOOL mSelectPending;
LLPointer<LLFolderViewModelItem> mViewModelItem;
LLFontGL::StyleFlags mLabelStyle;
std::string mLabelSuffix;
LLUIImagePtr mIcon;
std::string mStatusText;
LLUIImagePtr mIconOpen;
LLUIImagePtr mIconOverlay;
BOOL mHasVisibleChildren;
LLUIImagePtr mIcon,
mIconOpen,
mIconOverlay;
S32 mLocalIndentation;
S32 mIndentation;
S32 mItemHeight;
BOOL mPassedFilter;
S32 mLastFilterGeneration;
std::string::size_type mStringMatchOffset;
S32 mDragStartX,
mDragStartY;
S32 mLeftPad,
mIconPad,
mIconWidth,
mTextPad,
mTextPadRight,
mArrowSize,
mMaxFolderItemOverlap;
F32 mControlLabelRotation;
LLFolderView* mRoot;
BOOL mDragAndDropTarget;
BOOL mIsLoading;
LLTimer mTimeSinceRequestStart;
bool mShowLoadStatus;
bool mIsMouseOverTitle;
bool mHasVisibleChildren,
mIsCurSelection,
mDragAndDropTarget,
mIsMouseOverTitle,
mAllowOpen,
mSelectPending;
LLUIColor mFontColor;
LLUIColor mFontHighlightColor;
// helper function to change the selection from the root.
void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected);
// For now assuming all colors are the same in derived classes.
static bool sColorSetInitialized;
static LLUIColor sFgColor;
static LLUIColor sFgDisabledColor;
static LLUIColor sHighlightBgColor;
static LLUIColor sFlashBgColor;
static LLUIColor sFocusOutlineColor;
static LLUIColor sMouseOverColor;
static LLUIColor sFilterBGColor;
static LLUIColor sFilterTextColor;
static LLUIColor sSuffixColor;
static LLUIColor sSearchStatusColor;
// this is an internal method used for adding items to folders. A
// no-op at this level, but reimplemented in derived classes.
virtual BOOL addItem(LLFolderViewItem*) { return FALSE; }
virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; }
virtual void addItem(LLFolderViewItem*) { }
virtual void addFolder(LLFolderViewFolder*) { }
virtual bool isHighlightAllowed();
virtual bool isHighlightActive();
virtual bool isFlashing() { return false; }
virtual void setFlashState(bool) { }
static LLFontGL* getLabelFontForStyle(U8 style);
virtual void setCreationDate(time_t creation_date_utc) { mCreationDate = creation_date_utc; }
BOOL mIsSelected;
public:
static void initClass();
static void cleanupClass();
BOOL postBuild();
// This function clears the currently selected item, and records
// the specified selected item appropriately for display and use
// in the UI. If open is TRUE, then folders are opened up along
// the way to the selection.
void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem,
BOOL take_keyboard_focus = TRUE);
virtual void openItem( void );
// This function is called when the folder view is dirty. It's
// implemented here but called by derived classes when folding the
// views.
void arrangeFromRoot();
void filterFromRoot( void );
void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus);
virtual ~LLFolderViewItem( void );
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
enum { ARRANGE = TRUE, DO_NOT_ARRANGE = FALSE };
virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root);
virtual EInventorySortGroup getSortGroup() const;
virtual void addToFolder(LLFolderViewFolder* folder);
// Finds width and height of this object and it's children. Also
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
virtual S32 arrange( S32* width, S32* height );
virtual S32 getItemHeight();
// applies filters to control visibility of inventory items
virtual void filter( LLInventoryFilter& filter);
// updates filter serial number and optionally propagated value up to root
S32 getLastFilterGeneration() { return mLastFilterGeneration; }
virtual void dirtyFilter();
virtual S32 getLabelXPos();
S32 getIconPad();
S32 getTextPad();
// If 'selection' is 'this' then note that otherwise ignore.
// Returns TRUE if this item ends up being selected.
@ -231,7 +188,7 @@ public:
virtual void selectItem();
// gets multiple-element selection
virtual std::set<LLUUID> getSelectionList() const;
virtual std::set<LLFolderViewItem*> getSelectionList() const;
// Returns true is this object and all of its children can be removed (deleted by user)
virtual BOOL isRemovable();
@ -253,74 +210,54 @@ public:
BOOL hasVisibleChildren() { return mHasVisibleChildren; }
void setShowLoadStatus(bool status) { mShowLoadStatus = status; }
// Call through to the viewed object and return true if it can be
// removed. Returns true if it's removed.
//virtual BOOL removeRecursively(BOOL single_item);
BOOL remove();
// Build an appropriate context menu for the item. Flags unused.
void buildContextMenu(LLMenuGL& menu, U32 flags);
void buildContextMenu(class LLMenuGL& menu, U32 flags);
// This method returns the actual name of the thing being
// viewed. This method will ask the viewed object itself.
const std::string& getName( void ) const;
const std::string& getSearchableLabel( void ) const;
// This method returns the label displayed on the view. This
// method was primarily added to allow sorting on the folder
// contents possible before the entire view has been constructed.
const std::string& getLabel() const { return mLabel; }
// Used for sorting, like getLabel() above.
virtual time_t getCreationDate() const { return mCreationDate; }
LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; }
const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; }
void setParentFolder(LLFolderViewFolder* parent) { mParentFolder = parent; }
LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE );
LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE );
const LLFolderViewEventListener* getListener( void ) const { return mListener; }
LLFolderViewEventListener* getListener( void ) { return mListener; }
// Gets the inventory item if it exists (null otherwise)
LLViewerInventoryItem * getInventoryItem(void);
const LLFolderViewModelItem* getViewModelItem( void ) const { return mViewModelItem; }
LLFolderViewModelItem* getViewModelItem( void ) { return mViewModelItem; }
const LLFolderViewModelInterface* getFolderViewModel( void ) const;
LLFolderViewModelInterface* getFolderViewModel( void );
// just rename the object.
void rename(const std::string& new_name);
// open
virtual void openItem( void );
virtual void preview(void);
// Show children (unfortunate that this is called "open")
// Show children
virtual void setOpen(BOOL open = TRUE) {};
virtual BOOL isOpen() const { return FALSE; }
virtual LLFolderView* getRoot();
virtual const LLFolderView* getRoot() const;
BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor );
S32 getIndentation() { return mIndentation; }
virtual BOOL potentiallyVisible(); // do we know for a fact that this item won't be displayed?
virtual BOOL potentiallyFiltered(); // do we know for a fact that this item has been filtered out?
virtual BOOL getFiltered();
virtual BOOL getFiltered(S32 filter_generation);
virtual void setFiltered(BOOL filtered, S32 filter_generation);
// change the icon
void setIcon(LLUIImagePtr icon);
virtual BOOL passedFilter(S32 filter_generation = -1);
// refresh information from the object being viewed.
void refreshFromListener();
virtual void refresh();
virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor);
// LLView functionality
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
@ -330,25 +267,23 @@ public:
virtual void onMouseLeave(S32 x, S32 y, MASK mask);
virtual LLView* findChildView(const std::string& name, BOOL recurse) const { return NULL; }
//virtual LLView* findChildView(const std::string& name, BOOL recurse) const { return LLView::findChildView(name, recurse); }
// virtual void handleDropped();
virtual void draw();
void drawOpenFolderArrow(const Params& default_params, const LLUIColor& fg_color);
void drawHighlight(const BOOL showContent, const BOOL hasKeyboardFocus, const LLUIColor &selectColor, const LLUIColor &flashColor, const LLUIColor &outlineColor, const LLUIColor &mouseOverColor);
void drawLabel(const LLFontGL * font, const F32 x, const F32 y, const LLColor4& color, F32 &right_x);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
private:
static std::map<U8, LLFontGL*> sFonts; // map of styles to fonts
};
// function used for sorting.
typedef bool (*sort_order_f)(LLFolderViewItem* a, LLFolderViewItem* b);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewFolder
//
@ -363,33 +298,26 @@ protected:
LLFolderViewFolder( const LLFolderViewItem::Params& );
friend class LLUICtrlFactory;
public:
typedef enum e_trash
{
UNKNOWN, TRASH, NOT_TRASH
} ETrash;
void updateLabelRotation();
virtual bool isCollapsed() { return FALSE; }
public:
typedef std::list<LLFolderViewItem*> items_t;
typedef std::list<LLFolderViewFolder*> folders_t;
protected:
items_t mItems;
folders_t mFolders;
LLInventorySort mSortFunction;
BOOL mIsOpen;
BOOL mExpanderHighlighted;
F32 mCurHeight;
F32 mTargetHeight;
F32 mAutoOpenCountdown;
time_t mSubtreeCreationDate;
mutable ETrash mAmTrash;
S32 mLastArrangeGeneration;
S32 mLastCalculatedWidth;
S32 mCompletedFilterGeneration;
S32 mMostFilteredDescendantGeneration;
bool mNeedsSort;
bool mPassedFolderFilter;
public:
typedef enum e_recurse_type
@ -403,48 +331,25 @@ public:
virtual ~LLFolderViewFolder( void );
virtual BOOL potentiallyVisible();
LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE );
LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE );
// addToFolder() returns TRUE if it succeeds. FALSE otherwise
virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root);
virtual void addToFolder(LLFolderViewFolder* folder);
// Finds width and height of this object and it's children. Also
// makes sure that this view and it's children are the right size.
virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
virtual S32 arrange( S32* width, S32* height );
BOOL needsArrange();
void requestSort();
// Returns the sort group (system, trash, folder) for this folder.
virtual EInventorySortGroup getSortGroup() const;
virtual void setCompletedFilterGeneration(S32 generation, BOOL recurse_up);
virtual S32 getCompletedFilterGeneration() { return mCompletedFilterGeneration; }
BOOL hasFilteredDescendants(S32 filter_generation);
BOOL hasFilteredDescendants();
// applies filters to control visibility of inventory items
virtual void filter( LLInventoryFilter& filter);
virtual void setFiltered(BOOL filtered, S32 filter_generation);
virtual BOOL getFiltered();
virtual BOOL getFiltered(S32 filter_generation);
virtual void dirtyFilter();
// folder-specific filtering (filter status propagates top down instead of bottom up)
void filterFolder(LLInventoryFilter& filter);
void setFilteredFolder(bool filtered, S32 filter_generation);
bool getFilteredFolder(S32 filter_generation);
bool descendantsPassedFilter(S32 filter_generation = -1);
// Passes selection information on to children and record
// selection information if necessary.
// Returns TRUE if this object (or a child) ends up being selected.
// If 'openitem' is TRUE then folders are opened up along the way to the selection.
virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus);
virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus = TRUE);
// This method is used to change the selection of an item.
// Recursively traverse all children; if 'selection' is 'this' then change
@ -464,31 +369,13 @@ public:
// destroys this folder, and all children
virtual void destroyView();
// If this folder can be removed, remove all children that can be
// removed, return TRUE if this is empty after the operation and
// it's viewed folder object can be removed.
//virtual BOOL removeRecursively(BOOL single_item);
//virtual BOOL remove();
// remove the specified item (and any children) if
// possible. Return TRUE if the item was deleted.
BOOL removeItem(LLFolderViewItem* item);
// simply remove the view (and any children) Don't bother telling
// the listeners.
void removeView(LLFolderViewItem* item);
// extractItem() removes the specified item from the folder, but
// doesn't delete it.
void extractItem( LLFolderViewItem* item );
virtual void extractItem( LLFolderViewItem* item );
// This function is called by a child that needs to be resorted.
void resort(LLFolderViewItem* item);
void setItemSortOrder(U32 ordering);
void sortBy(U32);
//BOOL (*func)(LLFolderViewItem* a, LLFolderViewItem* b));
void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; }
// folders can be opened. This will usually be called by internal
@ -499,8 +386,7 @@ public:
virtual void setOpen(BOOL openitem = TRUE);
// Called when a child is refreshed.
// don't rearrange child folder contents unless explicitly requested
virtual void requestArrange(BOOL include_descendants = FALSE);
virtual void requestArrange();
// internal method which doesn't update the entire view. This
// method was written because the list iterators destroy the state
@ -513,65 +399,60 @@ public:
// special case if an object is dropped on the child.
BOOL handleDragAndDropFromChild(MASK mask,
BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
void applyFunctorRecursively(LLFolderViewFunctor& functor);
virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor);
// Just apply this functor to the folder's immediate children.
void applyFunctorToChildren(LLFolderViewFunctor& functor);
// apply this functor to the folder's descendants.
void applyFunctorRecursively(LLFolderViewFunctor& functor);
virtual void openItem( void );
virtual BOOL addItem(LLFolderViewItem* item);
virtual BOOL addFolder( LLFolderViewFolder* folder);
// LLView functionality
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask );
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
BOOL handleDragAndDropToThisFolder(MASK mask, BOOL drop,
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
BOOL handleDragAndDropToThisFolder(MASK mask,
BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg);
virtual void draw();
time_t getCreationDate() const;
bool isTrash() const;
folders_t::const_iterator getFoldersBegin() const { return mFolders.begin(); }
folders_t::const_iterator getFoldersEnd() const { return mFolders.end(); }
folders_t::iterator getFoldersBegin() { return mFolders.begin(); }
folders_t::iterator getFoldersEnd() { return mFolders.end(); }
folders_t::size_type getFoldersCount() const { return mFolders.size(); }
items_t::const_iterator getItemsBegin() const { return mItems.begin(); }
items_t::const_iterator getItemsEnd() const { return mItems.end(); }
items_t::size_type getItemsCount() const { return mItems.size(); }
LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse);
void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector<LLFolderViewItem*>& items);
// internal functions for tracking folders and items separately
// use addToFolder() virtual method to ensure folders are always added to mFolders
// and not mItems
void addItem(LLFolderViewItem* item);
void addFolder( LLFolderViewFolder* folder);
//WARNING: do not call directly...use the appropriate LLFolderViewModel-derived class instead
template<typename SORT_FUNC> void sortFolders(const SORT_FUNC& func) { mFolders.sort(func); }
template<typename SORT_FUNC> void sortItems(const SORT_FUNC& func) { mItems.sort(func); }
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLFolderViewListenerFunctor
//
// This simple abstract base class can be used to applied to all
// listeners in a hierarchy.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLFolderViewListenerFunctor
{
public:
virtual ~LLFolderViewListenerFunctor() {}
virtual void operator()(LLFolderViewEventListener* listener) = 0;
};
#endif // LLFOLDERVIEWITEM_H

View File

@ -0,0 +1,68 @@
/**
* @file llfolderviewmodel.cpp
* @brief Implementation of the view model collection of classes.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llfolderviewmodel.h"
#include "lltrans.h"
bool LLFolderViewModelCommon::needsSort(LLFolderViewModelItem* item)
{
return item->getSortVersion() < mTargetSortVersion;
}
std::string LLFolderViewModelCommon::getStatusText()
{
if (!contentsReady() || mFolderView->getViewModelItem()->getLastFilterGeneration() < getFilter().getCurrentGeneration())
{
return LLTrans::getString("Searching");
}
else
{
return getFilter().getEmptyLookupMessage();
}
}
void LLFolderViewModelCommon::filter()
{
getFilter().setFilterCount(llclamp(LLUI::sSettingGroups["config"]->getS32("FilterItemsPerFrame"), 1, 5000));
mFolderView->getViewModelItem()->filter(getFilter());
}
bool LLFolderViewModelItemCommon::hasFilterStringMatch()
{
return mStringMatchOffsetFilter != std::string::npos;
}
std::string::size_type LLFolderViewModelItemCommon::getFilterStringOffset()
{
return mStringMatchOffsetFilter;
}
std::string::size_type LLFolderViewModelItemCommon::getFilterStringSize()
{
return mRootViewModel.getFilter().getFilterStringSize();
}

View File

@ -0,0 +1,444 @@
/**
* @file llfolderviewmodel.h
*
* $LicenseInfo:firstyear=2001&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 LLFOLDERVIEWMODEL_H
#define LLFOLDERVIEWMODEL_H
#include "llfontgl.h" // just for StyleFlags enum
#include "llfolderview.h"
// These are grouping of inventory types.
// Order matters when sorting system folders to the top.
enum EInventorySortGroup
{
SG_SYSTEM_FOLDER,
SG_TRASH_FOLDER,
SG_NORMAL_FOLDER,
SG_ITEM
};
class LLFontGL;
class LLInventoryModel;
class LLMenuGL;
class LLUIImage;
class LLUUID;
class LLFolderViewItem;
class LLFolderViewFolder;
class LLFolderViewFilter
{
public:
enum EFilterModified
{
FILTER_NONE, // nothing to do, already filtered
FILTER_RESTART, // restart filtering from scratch
FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter
FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one
};
public:
LLFolderViewFilter() {}
virtual ~LLFolderViewFilter() {}
// +-------------------------------------------------------------------+
// + Execution And Results
// +-------------------------------------------------------------------+
virtual bool check(const LLFolderViewModelItem* item) = 0;
virtual bool checkFolder(const LLFolderViewModelItem* folder) const = 0;
virtual void setEmptyLookupMessage(const std::string& message) = 0;
virtual std::string getEmptyLookupMessage() const = 0;
virtual bool showAllResults() const = 0;
virtual std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const = 0;
virtual std::string::size_type getFilterStringSize() const = 0;
// +-------------------------------------------------------------------+
// + Status
// +-------------------------------------------------------------------+
virtual bool isActive() const = 0;
virtual bool isModified() const = 0;
virtual void clearModified() = 0;
virtual const std::string& getName() const = 0;
virtual const std::string& getFilterText() = 0;
//RN: this is public to allow system to externally force a global refilter
virtual void setModified(EFilterModified behavior = FILTER_RESTART) = 0;
// +-------------------------------------------------------------------+
// + Count
// +-------------------------------------------------------------------+
virtual void setFilterCount(S32 count) = 0;
virtual S32 getFilterCount() const = 0;
virtual void decrementFilterCount() = 0;
// +-------------------------------------------------------------------+
// + Default
// +-------------------------------------------------------------------+
virtual bool isDefault() const = 0;
virtual bool isNotDefault() const = 0;
virtual void markDefault() = 0;
virtual void resetDefault() = 0;
// +-------------------------------------------------------------------+
// + Generation
// +-------------------------------------------------------------------+
virtual S32 getCurrentGeneration() const = 0;
virtual S32 getFirstSuccessGeneration() const = 0;
virtual S32 getFirstRequiredGeneration() const = 0;
};
class LLFolderViewModelInterface
{
public:
virtual ~LLFolderViewModelInterface() {}
virtual void requestSortAll() = 0;
virtual void sort(class LLFolderViewFolder*) = 0;
virtual void filter() = 0;
virtual bool contentsReady() = 0;
virtual void setFolderView(LLFolderView* folder_view) = 0;
virtual LLFolderViewFilter& getFilter() = 0;
virtual const LLFolderViewFilter& getFilter() const = 0;
virtual std::string getStatusText() = 0;
virtual bool startDrag(std::vector<LLFolderViewModelItem*>& items) = 0;
};
// This is an abstract base class that users of the folderview classes
// would use to bridge the folder view with the underlying data
class LLFolderViewModelItem : public LLRefCount
{
public:
LLFolderViewModelItem() { }
virtual ~LLFolderViewModelItem() { }
virtual void update() {} //called when drawing
virtual const std::string& getName() const = 0;
virtual const std::string& getDisplayName() const = 0;
virtual const std::string& getSearchableName() const = 0;
virtual LLPointer<LLUIImage> getIcon() const = 0;
virtual LLPointer<LLUIImage> getIconOpen() const { return getIcon(); }
virtual LLPointer<LLUIImage> getIconOverlay() const { return NULL; }
virtual LLFontGL::StyleFlags getLabelStyle() const = 0;
virtual std::string getLabelSuffix() const = 0;
virtual void openItem( void ) = 0;
virtual void closeItem( void ) = 0;
virtual void selectItem(void) = 0;
virtual BOOL isItemRenameable() const = 0;
virtual BOOL renameItem(const std::string& new_name) = 0;
virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed
virtual BOOL removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;
virtual BOOL isItemCopyable() const = 0;
virtual BOOL copyToClipboard() const = 0;
virtual BOOL cutToClipboard() const = 0;
virtual BOOL isClipboardPasteable() const = 0;
virtual void pasteFromClipboard() = 0;
virtual void pasteLinkFromClipboard() = 0;
virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet?
virtual bool filter( LLFolderViewFilter& filter) = 0;
virtual bool passedFilter(S32 filter_generation = -1) = 0;
virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0;
virtual void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) = 0;
virtual void setPassedFolderFilter(bool passed, S32 filter_generation) = 0;
virtual void dirtyFilter() = 0;
virtual bool hasFilterStringMatch() = 0;
virtual std::string::size_type getFilterStringOffset() = 0;
virtual std::string::size_type getFilterStringSize() = 0;
virtual S32 getLastFilterGeneration() const = 0;
virtual bool hasChildren() const = 0;
virtual void addChild(LLFolderViewModelItem* child) = 0;
virtual void removeChild(LLFolderViewModelItem* child) = 0;
// This method will be called to determine if a drop can be
// performed, and will set drop to TRUE if a drop is
// requested. Returns TRUE if a drop is possible/happened,
// otherwise FALSE.
virtual BOOL dragOrDrop(MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
std::string& tooltip_msg) = 0;
virtual void requestSort() = 0;
virtual S32 getSortVersion() = 0;
virtual void setSortVersion(S32 version) = 0;
virtual void setParent(LLFolderViewModelItem* parent) = 0;
virtual bool hasParent() = 0;
protected:
friend class LLFolderViewItem;
virtual void setFolderViewItem(LLFolderViewItem* folder_view_item) = 0;
};
class LLFolderViewModelItemCommon : public LLFolderViewModelItem
{
public:
LLFolderViewModelItemCommon(LLFolderViewModelInterface& root_view_model)
: mSortVersion(-1),
mPassedFilter(true),
mPassedFolderFilter(true),
mStringMatchOffsetFilter(std::string::npos),
mStringFilterSize(0),
mFolderViewItem(NULL),
mLastFilterGeneration(-1),
mLastFolderFilterGeneration(-1),
mMostFilteredDescendantGeneration(-1),
mParent(NULL),
mRootViewModel(root_view_model)
{
mChildren.clear();
}
void requestSort() { mSortVersion = -1; }
S32 getSortVersion() { return mSortVersion; }
void setSortVersion(S32 version) { mSortVersion = version;}
S32 getLastFilterGeneration() const { return mLastFilterGeneration; }
S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; }
void dirtyFilter()
{
mLastFilterGeneration = -1;
mLastFolderFilterGeneration = -1;
// bubble up dirty flag all the way to root
if (mParent)
{
mParent->dirtyFilter();
}
}
bool hasFilterStringMatch();
std::string::size_type getFilterStringOffset();
std::string::size_type getFilterStringSize();
typedef std::list<LLFolderViewModelItem*> child_list_t;
virtual void addChild(LLFolderViewModelItem* child)
{
// Avoid duplicates: bail out if that child is already present in the list
// Note: this happens when models are created before views
child_list_t::const_iterator iter;
for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
{
if (child == *iter)
{
return;
}
}
mChildren.push_back(child);
child->setParent(this);
dirtyFilter();
requestSort();
}
virtual void removeChild(LLFolderViewModelItem* child)
{
mChildren.remove(child);
child->setParent(NULL);
dirtyFilter();
}
virtual void clearChildren()
{
// As this is cleaning the whole list of children wholesale, we do need to delete the pointed objects
// This is different and not equivalent to calling removeChild() on each child
std::for_each(mChildren.begin(), mChildren.end(), DeletePointer());
mChildren.clear();
dirtyFilter();
}
child_list_t::const_iterator getChildrenBegin() const { return mChildren.begin(); }
child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); }
child_list_t::size_type getChildrenCount() const { return mChildren.size(); }
void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0)
{
mPassedFilter = passed;
mLastFilterGeneration = filter_generation;
mStringMatchOffsetFilter = string_offset;
mStringFilterSize = string_size;
}
void setPassedFolderFilter(bool passed, S32 filter_generation)
{
mPassedFolderFilter = passed;
mLastFolderFilterGeneration = filter_generation;
}
virtual bool potentiallyVisible()
{
return passedFilter() // we've passed the filter
|| getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration() // or we don't know yet
|| descendantsPassedFilter();
}
virtual bool passedFilter(S32 filter_generation = -1)
{
if (filter_generation < 0)
filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration();
bool passed_folder_filter = mPassedFolderFilter && mLastFolderFilterGeneration >= filter_generation;
bool passed_filter = mPassedFilter && mLastFilterGeneration >= filter_generation;
return passed_folder_filter
&& (descendantsPassedFilter(filter_generation)
|| passed_filter);
}
virtual bool descendantsPassedFilter(S32 filter_generation = -1)
{
if (filter_generation < 0) filter_generation = mRootViewModel.getFilter().getFirstSuccessGeneration();
return mMostFilteredDescendantGeneration >= filter_generation;
}
protected:
virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; }
virtual bool hasParent() { return mParent != NULL; }
S32 mSortVersion;
bool mPassedFilter;
bool mPassedFolderFilter;
std::string::size_type mStringMatchOffsetFilter;
std::string::size_type mStringFilterSize;
S32 mLastFilterGeneration;
S32 mLastFolderFilterGeneration;
S32 mMostFilteredDescendantGeneration;
child_list_t mChildren;
LLFolderViewModelItem* mParent;
LLFolderViewModelInterface& mRootViewModel;
void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;}
LLFolderViewItem* mFolderViewItem;
};
class LLFolderViewModelCommon : public LLFolderViewModelInterface
{
public:
LLFolderViewModelCommon()
: mTargetSortVersion(0),
mFolderView(NULL)
{}
virtual void requestSortAll()
{
// sort everything
mTargetSortVersion++;
}
virtual std::string getStatusText();
virtual void filter();
void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
protected:
bool needsSort(class LLFolderViewModelItem* item);
S32 mTargetSortVersion;
LLFolderView* mFolderView;
};
template <typename SORT_TYPE, typename ITEM_TYPE, typename FOLDER_TYPE, typename FILTER_TYPE>
class LLFolderViewModel : public LLFolderViewModelCommon
{
public:
LLFolderViewModel(){}
virtual ~LLFolderViewModel() {}
typedef SORT_TYPE SortType;
typedef ITEM_TYPE ItemType;
typedef FOLDER_TYPE FolderType;
typedef FILTER_TYPE FilterType;
virtual SortType& getSorter() { return mSorter; }
virtual const SortType& getSorter() const { return mSorter; }
virtual void setSorter(const SortType& sorter) { mSorter = sorter; requestSortAll(); }
virtual FilterType& getFilter() { return mFilter; }
virtual const FilterType& getFilter() const { return mFilter; }
virtual void setFilter(const FilterType& filter) { mFilter = filter; }
// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,
// this method needs to be overloaded and return the relevant fetch status.
virtual bool contentsReady() { return true; }
struct ViewModelCompare
{
ViewModelCompare(const SortType& sorter)
: mSorter(sorter)
{}
bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const
{
return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
}
bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const
{
return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
}
const SortType& mSorter;
};
void sort(LLFolderViewFolder* folder)
{
if (needsSort(folder->getViewModelItem()))
{
folder->sortFolders(ViewModelCompare(getSorter()));
folder->sortItems(ViewModelCompare(getSorter()));
folder->getViewModelItem()->setSortVersion(mTargetSortVersion);
folder->requestArrange();
}
}
protected:
SortType mSorter;
FilterType mFilter;
};
#endif // LLFOLDERVIEWMODEL_H

View File

@ -32,11 +32,10 @@
#include "lllocalcliprect.h"
#include "llpanel.h"
#include "llresizebar.h"
#include "llcriticaldamp.h"
#include "boost/foreach.hpp"
static const F32 MIN_FRACTIONAL_SIZE = 0.0f;
static const F32 MIN_FRACTIONAL_SIZE = 0.00001f;
static const F32 MAX_FRACTIONAL_SIZE = 1.f;
static LLDefaultChildRegistry::Register<LLLayoutStack> register_layout_stack("layout_stack");
@ -71,7 +70,7 @@ LLLayoutPanel::LLLayoutPanel(const Params& p)
mCollapseAmt(0.f),
mVisibleAmt(1.f), // default to fully visible
mResizeBar(NULL),
mFractionalSize(MIN_FRACTIONAL_SIZE),
mFractionalSize(0.f),
mTargetDim(0),
mIgnoreReshape(false),
mOrientation(LLLayoutStack::HORIZONTAL)
@ -521,7 +520,7 @@ void LLLayoutStack::updateFractionalSizes()
{
if (panelp->mAutoResize)
{
total_resizable_dim += llmax(0, panelp->getLayoutDim() - panelp->getRelevantMinDim());
total_resizable_dim += llmax(MIN_FRACTIONAL_SIZE, (F32)(panelp->getLayoutDim() - panelp->getRelevantMinDim()));
}
}
@ -672,12 +671,12 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
S32 new_dim = (mOrientation == HORIZONTAL)
? new_rect.getWidth()
: new_rect.getHeight();
S32 delta_dim = new_dim - resized_panel->getVisibleDim();
if (delta_dim == 0) return;
S32 delta_panel_dim = new_dim - resized_panel->getVisibleDim();
if (delta_panel_dim == 0) return;
F32 total_visible_fraction = 0.f;
F32 delta_auto_resize_headroom = 0.f;
F32 original_auto_resize_headroom = 0.f;
F32 old_auto_resize_headroom = 0.f;
LLLayoutPanel* other_resize_panel = NULL;
LLLayoutPanel* following_panel = NULL;
@ -686,7 +685,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
{
if (panelp->mAutoResize)
{
original_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim());
old_auto_resize_headroom += (F32)(panelp->mTargetDim - panelp->getRelevantMinDim());
if (panelp->getVisible() && !panelp->mCollapsed)
{
total_visible_fraction += panelp->mFractionalSize;
@ -704,25 +703,24 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
}
}
if (resized_panel->mAutoResize)
{
if (!other_resize_panel || !other_resize_panel->mAutoResize)
{
delta_auto_resize_headroom += delta_dim;
delta_auto_resize_headroom += delta_panel_dim;
}
}
else
{
if (!other_resize_panel || other_resize_panel->mAutoResize)
{
delta_auto_resize_headroom -= delta_dim;
delta_auto_resize_headroom -= delta_panel_dim;
}
}
F32 fraction_given_up = 0.f;
F32 fraction_remaining = 1.f;
F32 updated_auto_resize_headroom = original_auto_resize_headroom + delta_auto_resize_headroom;
F32 new_auto_resize_headroom = old_auto_resize_headroom + delta_auto_resize_headroom;
enum
{
@ -734,7 +732,14 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
BOOST_FOREACH(LLLayoutPanel* panelp, mPanels)
{
if (!panelp->getVisible() || panelp->mCollapsed) continue;
if (!panelp->getVisible() || panelp->mCollapsed)
{
if (panelp->mAutoResize)
{
fraction_remaining -= panelp->mFractionalSize;
}
continue;
}
if (panelp == resized_panel)
{
@ -746,9 +751,9 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
case BEFORE_RESIZED_PANEL:
if (panelp->mAutoResize)
{ // freeze current size as fraction of overall auto_resize space
F32 fractional_adjustment_factor = updated_auto_resize_headroom == 0.f
F32 fractional_adjustment_factor = new_auto_resize_headroom == 0.f
? 1.f
: original_auto_resize_headroom / updated_auto_resize_headroom;
: old_auto_resize_headroom / new_auto_resize_headroom;
F32 new_fractional_size = llclamp(panelp->mFractionalSize * fractional_adjustment_factor,
MIN_FRACTIONAL_SIZE,
MAX_FRACTIONAL_SIZE);
@ -765,9 +770,9 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
case RESIZED_PANEL:
if (panelp->mAutoResize)
{ // freeze new size as fraction
F32 new_fractional_size = (updated_auto_resize_headroom == 0.f)
F32 new_fractional_size = (new_auto_resize_headroom == 0.f)
? MAX_FRACTIONAL_SIZE
: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / updated_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
: llclamp(total_visible_fraction * (F32)(new_dim - panelp->getRelevantMinDim()) / new_auto_resize_headroom, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE);
fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
fraction_remaining -= panelp->mFractionalSize;
panelp->mFractionalSize = new_fractional_size;
@ -790,8 +795,13 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
}
else
{
if (new_auto_resize_headroom < 1.f)
{
new_auto_resize_headroom = 1.f;
}
F32 new_fractional_size = llclamp(total_visible_fraction * (F32)(panelp->mTargetDim - panelp->getRelevantMinDim() + delta_auto_resize_headroom)
/ updated_auto_resize_headroom,
/ new_auto_resize_headroom,
MIN_FRACTIONAL_SIZE,
MAX_FRACTIONAL_SIZE);
fraction_given_up -= new_fractional_size - panelp->mFractionalSize;
@ -800,7 +810,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
}
else
{
panelp->mTargetDim -= delta_dim;
panelp->mTargetDim -= delta_panel_dim;
}
which_panel = AFTER_RESIZED_PANEL;
break;
@ -816,7 +826,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect&
}
}
updateLayout();
normalizeFractionalSizes();
//normalizeFractionalSizes();
}
void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent)

View File

@ -29,6 +29,7 @@
#define LL_LLLAYOUTSTACK_H
#include "llpanel.h"
#include "llresizebar.h"
class LLLayoutPanel;
@ -178,6 +179,9 @@ public:
F32 getAutoResizeFactor() const;
F32 getVisibleAmount() const;
S32 getVisibleDim() const;
LLResizeBar* getResizeBar() { return mResizeBar; }
bool isCollapsed() const { return mCollapsed;}
void setOrientation(LLLayoutStack::ELayoutOrientation orientation);
void storeOriginalDim();

View File

@ -157,8 +157,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mHighlightColor(p.highlight_color()),
mPreeditBgColor(p.preedit_bg_color()),
mGLFont(p.font),
mContextMenuHandle(),
mAutoreplaceCallback()
mContextMenuHandle()
{
llassert( mMaxLengthBytes > 0 );
@ -203,6 +202,14 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
LLLineEditor::~LLLineEditor()
{
mCommitOnFocusLost = FALSE;
// Make sure no context menu linger around once the widget is deleted
LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get());
if (menu)
{
menu->hide();
}
setContextMenu(NULL);
// calls onCommit() while LLLineEditor still valid
gFocusMgr.releaseFocusIfNeeded( this );
@ -971,12 +978,6 @@ void LLLineEditor::addChar(const llwchar uni_char)
LLUI::reportBadKeystroke();
}
if (!mReadOnly && mAutoreplaceCallback != NULL)
{
// call callback
mAutoreplaceCallback(mText, mCursorPos);
}
getWindow()->hideCursorUntilMouseMove();
}

View File

@ -189,9 +189,6 @@ public:
virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text );
virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text );
typedef boost::function<void(LLUIString&, S32&)> autoreplace_callback_t;
autoreplace_callback_t mAutoreplaceCallback;
void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; }
const std::string& getLabel() { return mLabel.getString(); }

View File

@ -52,7 +52,7 @@ LLLoadingIndicator::LLLoadingIndicator(const Params& p)
void LLLoadingIndicator::initFromParams(const Params& p)
{
BOOST_FOREACH(LLUIImage* image, p.images.image)
BOOST_FOREACH(LLUIImage* image, p.images().image)
{
mImages.push_back(image);
}

View File

@ -51,7 +51,7 @@ class LLLoadingIndicator
LOG_CLASS(LLLoadingIndicator);
public:
struct Images : public LLInitParam::BatchBlock<Images>
struct Images : public LLInitParam::Block<Images>
{
Multiple<LLUIImage*> image;
@ -62,8 +62,8 @@ public:
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
{
Optional<F32> images_per_sec;
Optional<Images> images;
Optional<F32> images_per_sec;
Optional<Atomic<Images> > images;
Params()
: images_per_sec("images_per_sec", 1.0f),

View File

@ -44,33 +44,27 @@ void LLMenuButton::MenuPositions::declareValues()
LLMenuButton::Params::Params()
: menu_filename("menu_filename"),
position("position", MP_BOTTOM_LEFT)
position("menu_position", MP_BOTTOM_LEFT)
{
addSynonym(position, "position");
}
LLMenuButton::LLMenuButton(const LLMenuButton::Params& p)
: LLButton(p),
mIsMenuShown(false),
mMenuPosition(p.position)
mMenuPosition(p.position),
mOwnMenu(false)
{
std::string menu_filename = p.menu_filename;
if (!menu_filename.empty())
{
LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
return;
}
setMenu(menu_filename, mMenuPosition);
updateMenuOrigin();
}
menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
mMenuHandle = menu->getHandle();
updateMenuOrigin();
}
LLMenuButton::~LLMenuButton()
{
cleanup();
}
boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
@ -80,9 +74,7 @@ boost::signals2::connection LLMenuButton::setMouseDownCallback( const mouse_sign
void LLMenuButton::hideMenu()
{
if(mMenuHandle.isDead()) return;
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
LLToggleableMenu* menu = getMenu();
if (menu)
{
menu->setVisible(FALSE);
@ -94,19 +86,39 @@ LLToggleableMenu* LLMenuButton::getMenu()
return dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
}
void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/)
void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition position /*MP_TOP_LEFT*/)
{
if (menu_filename.empty())
{
return;
}
LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
if (!menu)
{
llwarns << "Error loading menu_button menu" << llendl;
return;
}
setMenu(menu, position, true);
}
void LLMenuButton::setMenu(LLToggleableMenu* menu, EMenuPosition position /*MP_TOP_LEFT*/, bool take_ownership /*false*/)
{
if (!menu) return;
cleanup(); // destroy the previous memnu if we own it
mMenuHandle = menu->getHandle();
mMenuPosition = position;
mOwnMenu = take_ownership;
menu->setVisibilityChangeCallback(boost::bind(&LLMenuButton::onMenuVisibilityChange, this, _2));
}
BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
{
if (mMenuHandle.isDead()) return FALSE;
if (!getMenu()) return FALSE;
if( KEY_RETURN == key && mask == MASK_NONE && !gKeyboard->getKeyRepeated(key))
{
@ -118,7 +130,7 @@ BOOL LLMenuButton::handleKeyHere(KEY key, MASK mask )
return TRUE;
}
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
LLToggleableMenu* menu = getMenu();
if (menu && menu->getVisible() && key == KEY_ESCAPE && mask == MASK_NONE)
{
menu->setVisible(FALSE);
@ -139,9 +151,12 @@ BOOL LLMenuButton::handleMouseDown(S32 x, S32 y, MASK mask)
void LLMenuButton::toggleMenu()
{
if(mMenuHandle.isDead()) return;
if (mValidateSignal && !(*mValidateSignal)(this, LLSD()))
{
return;
}
LLToggleableMenu* menu = dynamic_cast<LLToggleableMenu*>(mMenuHandle.get());
LLToggleableMenu* menu = getMenu();
if (!menu) return;
// Store the button rectangle to toggle menu visibility if a mouse event
@ -170,7 +185,8 @@ void LLMenuButton::toggleMenu()
void LLMenuButton::updateMenuOrigin()
{
if (mMenuHandle.isDead()) return;
LLToggleableMenu* menu = getMenu();
if (!menu) return;
LLRect rect = getRect();
@ -179,12 +195,12 @@ void LLMenuButton::updateMenuOrigin()
case MP_TOP_LEFT:
{
mX = rect.mLeft;
mY = rect.mTop + mMenuHandle.get()->getRect().getHeight();
mY = rect.mTop + menu->getRect().getHeight();
break;
}
case MP_TOP_RIGHT:
{
const LLRect& menu_rect = mMenuHandle.get()->getRect();
const LLRect& menu_rect = menu->getRect();
mX = rect.mRight - menu_rect.getWidth();
mY = rect.mTop + menu_rect.getHeight();
break;
@ -211,3 +227,11 @@ void LLMenuButton::onMenuVisibilityChange(const LLSD& param)
mIsMenuShown = false;
}
}
void LLMenuButton::cleanup()
{
if (mMenuHandle.get() && mOwnMenu)
{
mMenuHandle.get()->die();
}
}

View File

@ -34,6 +34,8 @@ class LLToggleableMenu;
class LLMenuButton
: public LLButton
{
LOG_CLASS(LLMenuButton);
public:
typedef enum e_menu_position
{
@ -53,7 +55,7 @@ public:
{
// filename for it's toggleable menu
Optional<std::string> menu_filename;
Optional<EMenuPosition> position;
Optional<EMenuPosition, MenuPositions> position;
Params();
};
@ -68,13 +70,15 @@ public:
void hideMenu();
LLToggleableMenu* getMenu();
void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT);
void setMenu(const std::string& menu_filename, EMenuPosition position = MP_TOP_LEFT);
void setMenu(LLToggleableMenu* menu, EMenuPosition position = MP_TOP_LEFT, bool take_ownership = false);
void setMenuPosition(EMenuPosition position) { mMenuPosition = position; }
protected:
friend class LLUICtrlFactory;
LLMenuButton(const Params&);
~LLMenuButton();
void toggleMenu();
void updateMenuOrigin();
@ -82,11 +86,14 @@ protected:
void onMenuVisibilityChange(const LLSD& param);
private:
void cleanup();
LLHandle<LLView> mMenuHandle;
bool mIsMenuShown;
EMenuPosition mMenuPosition;
S32 mX;
S32 mY;
bool mOwnMenu; // true if we manage the menu lifetime
};

View File

@ -593,12 +593,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
{
// the menu items are in the child list in bottom up order
LLView* prev_menu_item = parent_menu->findNextSibling(this);
return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
LLView* next_menu_item = parent_menu->findPrevSibling(this);
return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
}
}
@ -608,12 +608,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask)
if (y > getRect().getHeight() / 2)
{
LLView* prev_menu_item = parent_menu->findNextSibling(this);
return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
}
else
{
LLView* next_menu_item = parent_menu->findPrevSibling(this);
return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
}
}
@ -1751,35 +1751,50 @@ void LLMenuGL::setCanTearOff(BOOL tear_off)
bool LLMenuGL::addChild(LLView* view, S32 tab_group)
{
if (LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view))
LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view);
if (menup)
{
appendMenu(menup);
return true;
return appendMenu(menup);
}
else if (LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view))
LLMenuItemGL* itemp = dynamic_cast<LLMenuItemGL*>(view);
if (itemp)
{
append(itemp);
return true;
return append(itemp);
}
return false;
}
// Used in LLContextMenu and in LLTogleableMenu
// to add an item of context menu branch
// Add an item to the context menu branch
bool LLMenuGL::addContextChild(LLView* view, S32 tab_group)
{
LLContextMenu* context = dynamic_cast<LLContextMenu*>(view);
if (context)
{
return appendContextSubMenu(context);
}
LLMenuItemSeparatorGL* separator = dynamic_cast<LLMenuItemSeparatorGL*>(view);
if (separator)
{
return append(separator);
}
LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view);
if (item)
{
return append(item);
}
LLMenuGL* menup = dynamic_cast<LLMenuGL*>(view);
if (menup)
{
return appendMenu(menup);
}
return false;
}
@ -2446,6 +2461,56 @@ void LLMenuGL::empty( void )
deleteAllChildren();
}
// erase group of items from menu
void LLMenuGL::erase( S32 begin, S32 end, bool arrange/* = true*/)
{
S32 items = mItems.size();
if ( items == 0 || begin >= end || begin < 0 || end > items )
{
return;
}
item_list_t::iterator start_position = mItems.begin();
std::advance(start_position, begin);
item_list_t::iterator end_position = mItems.begin();
std::advance(end_position, end);
for (item_list_t::iterator position_iter = start_position; position_iter != end_position; position_iter++)
{
LLUICtrl::removeChild(*position_iter);
}
mItems.erase(start_position, end_position);
if (arrange)
{
needsArrange();
}
}
// add new item at position
void LLMenuGL::insert( S32 position, LLView * ctrl, bool arrange /*= true*/ )
{
LLMenuItemGL * item = dynamic_cast<LLMenuItemGL *>(ctrl);
if (NULL == item || position < 0 || position >= mItems.size())
{
return;
}
item_list_t::iterator position_iter = mItems.begin();
std::advance(position_iter, position);
mItems.insert(position_iter, item);
LLUICtrl::addChild(item);
if (arrange)
{
needsArrange();
}
}
// Adjust rectangle of the menu
void LLMenuGL::setLeftAndBottom(S32 left, S32 bottom)
{
@ -2487,7 +2552,8 @@ BOOL LLMenuGL::append( LLMenuItemGL* item )
// add a separator to this menu
BOOL LLMenuGL::addSeparator()
{
LLMenuItemGL* separator = new LLMenuItemSeparatorGL();
LLMenuItemSeparatorGL::Params p;
LLMenuItemGL* separator = LLUICtrlFactory::create<LLMenuItemSeparatorGL>(p);
return addChild(separator);
}
@ -3080,7 +3146,17 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
const S32 CURSOR_HEIGHT = 22; // Approximate "normal" cursor size
const S32 CURSOR_WIDTH = 12;
if(menu->getChildList()->empty())
//Do not show menu if all menu items are disabled
BOOL item_enabled = false;
for (LLView::child_list_t::const_iterator itor = menu->getChildList()->begin();
itor != menu->getChildList()->end();
++itor)
{
LLView *menu_item = (*itor);
item_enabled = item_enabled || menu_item->getEnabled();
}
if(menu->getChildList()->empty() || !item_enabled)
{
return;
}
@ -4039,11 +4115,6 @@ BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
return result;
}
void LLContextMenu::draw()
{
LLMenuGL::draw();
}
bool LLContextMenu::addChild(LLView* view, S32 tab_group)
{
return addContextChild(view, tab_group);

View File

@ -478,6 +478,12 @@ public:
// remove all items on the menu
void empty( void );
// erase group of items from menu
void erase( S32 begin, S32 end, bool arrange = true );
// add new item at position
void insert( S32 begin, LLView * ctrl, bool arrange = true );
void setItemLastSelected(LLMenuItemGL* item); // must be in menu
U32 getItemCount(); // number of menu items
LLMenuItemGL* getItem(S32 number); // 0 = first item
@ -675,8 +681,6 @@ public:
// can't set visibility directly, must call show or hide
virtual void setVisible (BOOL visible);
virtual void draw ();
virtual void show (S32 x, S32 y, LLView* spawning_view = NULL);
virtual void hide ();
@ -698,7 +702,6 @@ protected:
LLHandle<LLView> mSpawningViewHandle;
};
//-----------------------------------------------------------------------------
// class LLContextMenuBranch
// A branch to another context menu

View File

@ -41,8 +41,8 @@ LLMultiFloater::LLMultiFloater(const LLSD& key, const LLFloater::Params& params)
mTabContainer(NULL),
mTabPos(LLTabContainer::TOP),
mAutoResize(TRUE),
mOrigMinWidth(0),
mOrigMinHeight(0)
mOrigMinWidth(params.min_width),
mOrigMinHeight(params.min_height)
{
}
@ -173,7 +173,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
else if (floaterp->getHost())
{
// floaterp is hosted by somebody else and
// this is adding it, so remove it from it's old host
// this is adding it, so remove it from its old host
floaterp->getHost()->removeFloater(floaterp);
}
else if (floaterp->getParent() == gFloaterView)
@ -188,11 +188,13 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
floater_data.mHeight = floaterp->getRect().getHeight();
floater_data.mCanMinimize = floaterp->isMinimizeable();
floater_data.mCanResize = floaterp->isResizable();
floater_data.mSaveRect = floaterp->mSaveRect;
// remove minimize and close buttons
floaterp->setCanMinimize(FALSE);
floaterp->setCanResize(FALSE);
floaterp->setCanDrag(FALSE);
floaterp->mSaveRect = FALSE;
floaterp->storeRectControl();
// avoid double rendering of floater background (makes it more opaque)
floaterp->setBackgroundVisible(FALSE);
@ -291,6 +293,7 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp)
{
LLFloaterData& floater_data = found_data_it->second;
floaterp->setCanMinimize(floater_data.mCanMinimize);
floaterp->mSaveRect = floater_data.mSaveRect;
if (!floater_data.mCanResize)
{
// restore original size
@ -468,23 +471,12 @@ BOOL LLMultiFloater::postBuild()
void LLMultiFloater::updateResizeLimits()
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
// initialize minimum size constraint to the original xml values.
S32 new_min_width = mOrigMinWidth;
S32 new_min_height = mOrigMinHeight;
// possibly increase minimum size constraint due to children's minimums.
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
if (floaterp)
{
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height);
}
}
computeResizeLimits(new_min_width, new_min_height);
setResizeLimits(new_min_width, new_min_height);
S32 cur_height = getRect().getHeight();
@ -510,3 +502,22 @@ void LLMultiFloater::updateResizeLimits()
gFloaterView->adjustToFitScreen(this, TRUE);
}
}
void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height)
{
static LLUICachedControl<S32> tabcntr_close_btn_size ("UITabCntrCloseBtnSize", 0);
const LLFloater::Params& default_params = LLFloater::getDefaultParams();
S32 floater_header_size = default_params.header_height;
S32 tabcntr_header_height = LLPANEL_BORDER_WIDTH + tabcntr_close_btn_size;
// possibly increase minimum size constraint due to children's minimums.
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
{
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
if (floaterp)
{
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + floater_header_size + tabcntr_header_height);
}
}
}

View File

@ -45,8 +45,8 @@ public:
virtual BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void draw();
/*virtual*/ void setVisible(BOOL visible);
virtual void draw();
virtual void setVisible(BOOL visible);
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
/*virtual*/ bool addChild(LLView* view, S32 tab_group = 0);
@ -79,10 +79,11 @@ public:
protected:
struct LLFloaterData
{
S32 mWidth;
S32 mHeight;
BOOL mCanMinimize;
BOOL mCanResize;
S32 mWidth;
S32 mHeight;
BOOL mCanMinimize;
BOOL mCanResize;
BOOL mSaveRect;
};
LLTabContainer* mTabContainer;
@ -93,6 +94,9 @@ protected:
LLTabContainer::TabPosition mTabPos;
BOOL mAutoResize;
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
private:
virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height);
};
#endif // LL_MULTI_FLOATER_H

View File

@ -39,7 +39,6 @@
#include "lldir.h"
#include "llsdserialize.h"
#include "lltrans.h"
#include "llnotificationslistener.h"
#include "llstring.h"
#include "llsdparam.h"
#include "llsdutil.h"
@ -60,7 +59,8 @@ void NotificationPriorityValues::declareValues()
}
LLNotificationForm::FormElementBase::FormElementBase()
: name("name")
: name("name"),
enabled("enabled", true)
{}
LLNotificationForm::FormIgnore::FormIgnore()
@ -104,39 +104,7 @@ LLNotificationForm::Params::Params()
form_elements("")
{}
// Local channel for persistent notifications
// Stores only persistent notifications.
// Class users can use connectChanged() to process persistent notifications
// (see LLNotificationStorage for example).
class LLPersistentNotificationChannel : public LLNotificationChannel
{
LOG_CLASS(LLPersistentNotificationChannel);
public:
LLPersistentNotificationChannel() :
LLNotificationChannel("Persistent", "Visible", &notificationFilter, LLNotificationComparators::orderByUUID())
{
}
private:
// The channel gets all persistent notifications except those that have been canceled
static bool notificationFilter(LLNotificationPtr pNotification)
{
bool handle_notification = false;
handle_notification = pNotification->isPersistent()
&& !pNotification->isCancelled();
return handle_notification;
}
void onDelete(LLNotificationPtr pNotification)
{
// we want to keep deleted notifications in our log, otherwise some
// notifications will be lost on exit.
mItems.insert(pNotification);
}
};
bool filterIgnoredNotifications(LLNotificationPtr notification)
{
@ -210,6 +178,14 @@ LLNotificationForm::LLNotificationForm()
{
}
LLNotificationForm::LLNotificationForm( const LLNotificationForm& other )
{
mFormData = other.mFormData;
mIgnore = other.mIgnore;
mIgnoreMsg = other.mIgnoreMsg;
mIgnoreSetting = other.mIgnoreSetting;
mInvertSetting = other.mInvertSetting;
}
LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotificationForm::Params& p)
: mIgnore(IGNORE_NO),
@ -246,14 +222,6 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
LLParamSDParser parser;
parser.writeSD(mFormData, p.form_elements);
if (!mFormData.isArray())
{
// change existing contents to a one element array
LLSD new_llsd_array = LLSD::emptyArray();
new_llsd_array.append(mFormData);
mFormData = new_llsd_array;
}
for (LLSD::array_iterator it = mFormData.beginArray(), end_it = mFormData.endArray();
it != end_it;
++it)
@ -300,7 +268,7 @@ LLSD LLNotificationForm::getElement(const std::string& element_name)
}
bool LLNotificationForm::hasElement(const std::string& element_name)
bool LLNotificationForm::hasElement(const std::string& element_name) const
{
for (LLSD::array_const_iterator it = mFormData.beginArray();
it != mFormData.endArray();
@ -311,7 +279,48 @@ bool LLNotificationForm::hasElement(const std::string& element_name)
return false;
}
void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value)
void LLNotificationForm::getElements(LLSD& elements, S32 offset)
{
//Finds elements that the template did not add
LLSD::array_const_iterator it = mFormData.beginArray() + offset;
//Keeps track of only the dynamic elements
for(; it != mFormData.endArray(); ++it)
{
elements.append(*it);
}
}
bool LLNotificationForm::getElementEnabled(const std::string& element_name) const
{
for (LLSD::array_const_iterator it = mFormData.beginArray();
it != mFormData.endArray();
++it)
{
if ((*it)["name"].asString() == element_name)
{
return (*it)["enabled"].asBoolean();
}
}
return false;
}
void LLNotificationForm::setElementEnabled(const std::string& element_name, bool enabled)
{
for (LLSD::array_iterator it = mFormData.beginArray();
it != mFormData.endArray();
++it)
{
if ((*it)["name"].asString() == element_name)
{
(*it)["enabled"] = enabled;
}
}
}
void LLNotificationForm::addElement(const std::string& type, const std::string& name, const LLSD& value, bool enabled)
{
LLSD element;
element["type"] = type;
@ -319,6 +328,7 @@ void LLNotificationForm::addElement(const std::string& type, const std::string&
element["text"] = name;
element["value"] = value;
element["index"] = mFormData.size();
element["enabled"] = enabled;
mFormData.append(element);
}
@ -408,14 +418,19 @@ LLNotificationTemplate::LLNotificationTemplate(const LLNotificationTemplate::Par
mURLOption(p.url.option),
mURLTarget(p.url.target),
mUnique(p.unique.isProvided()),
mCombineBehavior(p.unique.combine),
mPriority(p.priority),
mPersist(p.persist),
mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name())
mDefaultFunctor(p.functor.isProvided() ? p.functor() : p.name()),
mLogToChat(p.log_to_chat),
mLogToIM(p.log_to_im),
mShowToast(p.show_toast),
mSoundName("")
{
if (p.sound.isProvided()
&& LLUI::sSettingGroups["config"]->controlExists(p.sound))
{
mSoundEffect = LLUUID(LLUI::sSettingGroups["config"]->getString(p.sound));
mSoundName = p.sound;
}
BOOST_FOREACH(const LLNotificationTemplate::UniquenessContext& context, p.unique.contexts)
@ -460,18 +475,20 @@ LLNotificationVisibilityRule::LLNotificationVisibilityRule(const LLNotificationV
}
}
LLNotification::LLNotification(const LLNotification::Params& p) :
LLNotification::LLNotification(const LLSDParamAdapter<Params>& p) :
mTimestamp(p.time_stamp),
mSubstitutions(p.substitutions),
mPayload(p.payload),
mExpiresAt(0),
mExpiresAt(p.expiry),
mTemporaryResponder(false),
mRespondedTo(false),
mPriority(p.priority),
mCancelled(false),
mIgnored(false),
mResponderObj(NULL),
mIsReusable(false)
mId(p.id.isProvided() ? p.id : LLUUID::generateNewID()),
mOfferFromAgent(p.offer_from_agent),
mIsDND(p.is_dnd)
{
if (p.functor.name.isChosen())
{
@ -494,52 +511,52 @@ LLNotification::LLNotification(const LLNotification::Params& p) :
mResponderObj = p.responder;
}
mId.generate();
init(p.name, p.form_elements);
}
LLNotification::LLNotification(const LLSD& sd) :
mTemporaryResponder(false),
mRespondedTo(false),
mCancelled(false),
mIgnored(false),
mResponderObj(NULL),
mIsReusable(false)
{
mId.generate();
mSubstitutions = sd["substitutions"];
mPayload = sd["payload"];
mTimestamp = sd["time"];
mExpiresAt = sd["expiry"];
mPriority = (ENotificationPriority)sd["priority"].asInteger();
mResponseFunctorName = sd["responseFunctor"].asString();
std::string templatename = sd["name"].asString();
init(templatename, LLSD());
// replace form with serialized version
mForm = LLNotificationFormPtr(new LLNotificationForm(sd["form"]));
}
LLSD LLNotification::asLLSD()
LLSD LLNotification::asLLSD(bool excludeTemplateElements)
{
LLSD output;
output["id"] = mId;
output["name"] = mTemplatep->mName;
output["form"] = getForm()->asLLSD();
output["substitutions"] = mSubstitutions;
output["payload"] = mPayload;
output["time"] = mTimestamp;
output["expiry"] = mExpiresAt;
output["priority"] = (S32)mPriority;
output["responseFunctor"] = mResponseFunctorName;
output["reusable"] = mIsReusable;
LLParamSDParser parser;
if(mResponder)
Params p;
p.id = mId;
p.name = mTemplatep->mName;
p.substitutions = mSubstitutions;
p.payload = mPayload;
p.time_stamp = mTimestamp;
p.expiry = mExpiresAt;
p.priority = mPriority;
LLNotificationFormPtr templateForm = mTemplatep->mForm;
LLSD formElements = mForm->asLLSD();
//All form elements (dynamic or not)
if(!excludeTemplateElements)
{
p.form_elements = formElements;
}
//Only dynamic form elements (exclude template elements)
else if(templateForm->getNumElements() < formElements.size())
{
LLSD dynamicElements;
//Offset to dynamic elements and store them
mForm->getElements(dynamicElements, templateForm->getNumElements());
p.form_elements = dynamicElements;
}
if(mResponder)
{
p.functor.responder_sd = mResponder->asLLSD();
}
if(!mResponseFunctorName.empty())
{
output["responder"] = mResponder->asLLSD();
p.functor.name = mResponseFunctorName;
}
LLSD output;
parser.writeSD(output, p);
return output;
}
@ -569,7 +586,6 @@ void LLNotification::updateFrom(LLNotificationPtr other)
mRespondedTo = other->mRespondedTo;
mResponse = other->mResponse;
mTemporaryResponder = other->mTemporaryResponder;
mIsReusable = other->isReusable();
update();
}
@ -668,7 +684,7 @@ void LLNotification::respond(const LLSD& response)
return;
}
if (mTemporaryResponder && !isReusable())
if (mTemporaryResponder)
{
LLNotificationFunctorRegistry::instance().unregisterFunctor(mResponseFunctorName);
mResponseFunctorName = "";
@ -829,7 +845,7 @@ void LLNotification::init(const std::string& template_name, const LLSD& form_ele
//mSubstitutions["_ARGS"] = get_all_arguments_as_text(mSubstitutions);
mForm = LLNotificationFormPtr(new LLNotificationForm(*mTemplatep->mForm));
mForm->append(form_elements);
mForm->append(form_elements);
// apply substitution to form labels
mForm->formatElements(mSubstitutions);
@ -897,6 +913,49 @@ std::string LLNotification::getURL() const
return (mTemplatep ? url : "");
}
bool LLNotification::canLogToChat() const
{
return mTemplatep->mLogToChat;
}
bool LLNotification::canLogToIM() const
{
return mTemplatep->mLogToIM;
}
bool LLNotification::canShowToast() const
{
return mTemplatep->mShowToast;
}
bool LLNotification::hasFormElements() const
{
return mTemplatep->mForm->getNumElements() != 0;
}
void LLNotification::playSound()
{
make_ui_sound(mTemplatep->mSoundName.c_str());
}
LLNotification::ECombineBehavior LLNotification::getCombineBehavior() const
{
return mTemplatep->mCombineBehavior;
}
void LLNotification::updateForm( const LLNotificationFormPtr& form )
{
mForm = form;
}
void LLNotification::repost()
{
mRespondedTo = false;
LLNotifications::instance().update(shared_from_this());
}
// =========================================================
// LLNotificationChannel implementation
// ---
@ -957,7 +1016,7 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
std::string cmd = payload["sigtype"];
LLNotificationSet::iterator foundItem = mItems.find(pNotification);
bool wasFound = (foundItem != mItems.end());
bool passesFilter = mFilter(pNotification);
bool passesFilter = mFilter ? mFilter(pNotification) : true;
// first, we offer the result of the filter test to the simple
// signals for pass/fail. One of these is guaranteed to be called.
@ -966,10 +1025,12 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
bool abortProcessing = false;
if (passesFilter)
{
onFilterPass(pNotification);
abortProcessing = mPassedFilter(payload);
}
else
{
onFilterFail(pNotification);
abortProcessing = mFailedFilter(payload);
}
@ -987,8 +1048,8 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
{
// not in our list, add it and say so
mItems.insert(pNotification);
abortProcessing = mChanged(payload);
onLoad(pNotification);
abortProcessing = mChanged(payload);
}
}
else if (cmd == "change")
@ -1003,18 +1064,18 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
{
// it already existed, so this is a change
// since it changed in place, all we have to do is resend the signal
abortProcessing = mChanged(payload);
onChange(pNotification);
abortProcessing = mChanged(payload);
}
else
{
// not in our list, add it and say so
mItems.insert(pNotification);
onChange(pNotification);
// our payload is const, so make a copy before changing it
LLSD newpayload = payload;
newpayload["sigtype"] = "add";
abortProcessing = mChanged(newpayload);
onChange(pNotification);
}
}
else
@ -1023,11 +1084,11 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
{
// it already existed, so this is a delete
mItems.erase(pNotification);
onChange(pNotification);
// our payload is const, so make a copy before changing it
LLSD newpayload = payload;
newpayload["sigtype"] = "delete";
abortProcessing = mChanged(newpayload);
onChange(pNotification);
}
// didn't pass, not on our list, do nothing
}
@ -1041,8 +1102,8 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
{
// not in our list, add it and say so
mItems.insert(pNotification);
abortProcessing = mChanged(payload);
onAdd(pNotification);
abortProcessing = mChanged(payload);
}
}
else if (cmd == "delete")
@ -1050,65 +1111,35 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt
// if we have it in our list, pass on the delete, then delete it, else do nothing
if (wasFound)
{
onDelete(pNotification);
abortProcessing = mChanged(payload);
// do not delete the notification to make LLChatHistory::appendMessage add notification panel to IM window
if( ! pNotification->isReusable() )
{
mItems.erase(pNotification);
onDelete(pNotification);
}
mItems.erase(pNotification);
}
}
return abortProcessing;
}
/* static */
LLNotificationChannelPtr LLNotificationChannel::buildChannel(const std::string& name,
const std::string& parent,
LLNotificationFilter filter,
LLNotificationComparator comparator)
LLNotificationChannel::LLNotificationChannel(const Params& p)
: LLNotificationChannelBase(p.filter()),
LLInstanceTracker<LLNotificationChannel, std::string>(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString()),
mName(p.name.isProvided() ? p.name : LLUUID::generateNewID().asString())
{
// note: this is not a leak; notifications are self-registering.
// This factory helps to prevent excess deletions by making sure all smart
// pointers to notification channels come from the same source
new LLNotificationChannel(name, parent, filter, comparator);
return LLNotifications::instance().getChannel(name);
BOOST_FOREACH(const std::string& source, p.sources)
{
connectToChannel(source);
}
}
LLNotificationChannel::LLNotificationChannel(const std::string& name,
const std::string& parent,
LLNotificationFilter filter,
LLNotificationComparator comparator) :
LLNotificationChannelBase(filter, comparator),
mName(name),
mParent(parent)
LLNotificationFilter filter)
: LLNotificationChannelBase(filter),
LLInstanceTracker<LLNotificationChannel, std::string>(name),
mName(name)
{
// store myself in the channel map
LLNotifications::instance().addChannel(LLNotificationChannelPtr(this));
// bind to notification broadcast
if (parent.empty())
{
LLNotifications::instance().connectChanged(
boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
}
else
{
LLNotificationChannelPtr p = LLNotifications::instance().getChannel(parent);
p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
}
}
void LLNotificationChannel::setComparator(LLNotificationComparator comparator)
{
mComparator = comparator;
LLNotificationSet s2(mComparator);
s2.insert(mItems.begin(), mItems.end());
mItems.swap(s2);
// notify clients that we've been resorted
mChanged(LLSD().with("sigtype", "sort"));
connectToChannel(parent);
}
bool LLNotificationChannel::isEmpty() const
@ -1131,6 +1162,11 @@ LLNotificationChannel::Iterator LLNotificationChannel::end()
return mItems.end();
}
size_t LLNotificationChannel::size()
{
return mItems.size();
}
std::string LLNotificationChannel::summarize()
{
std::string s("Channel '");
@ -1144,22 +1180,33 @@ std::string LLNotificationChannel::summarize()
return s;
}
void LLNotificationChannel::connectToChannel( const std::string& channel_name )
{
if (channel_name.empty())
{
LLNotifications::instance().connectChanged(
boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
}
else
{
LLNotificationChannelPtr p = LLNotifications::instance().getChannel(channel_name);
p->connectChanged(boost::bind(&LLNotificationChannelBase::updateItem, this, _1));
}
}
// ---
// END OF LLNotificationChannel implementation
// =========================================================
// =========================================================
// ============================================== ===========
// LLNotifications implementation
// ---
LLNotifications::LLNotifications() : LLNotificationChannelBase(LLNotificationFilters::includeEverything,
LLNotificationComparators::orderByUUID()),
mIgnoreAllNotifications(false)
LLNotifications::LLNotifications()
: LLNotificationChannelBase(LLNotificationFilters::includeEverything),
mIgnoreAllNotifications(false)
{
LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Notification.Show", boost::bind(&LLNotifications::addFromCallback, this, _2));
mListener.reset(new LLNotificationsListener(*this));
}
@ -1196,7 +1243,15 @@ bool LLNotifications::uniqueFilter(LLNotificationPtr pNotif)
if (pNotif != existing_notification
&& pNotif->isEquivalentTo(existing_notification))
{
return false;
if (pNotif->getCombineBehavior() == LLNotification::CANCEL_OLD)
{
cancel(existing_notification);
return true;
}
else
{
return false;
}
}
}
@ -1236,43 +1291,43 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload)
return false;
}
// Update 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)
switch(pNotif->getCombineBehavior())
{
LLNotificationPtr existing_notification = existing_it->second;
if (pNotif != existing_notification
&& pNotif->isEquivalentTo(existing_notification))
case LLNotification::REPLACE_WITH_NEW:
// Update 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)
{
// copy notification instance data over to oldest instance
// of this unique notification and update it
existing_notification->updateFrom(pNotif);
// then delete the new one
cancel(pNotif);
LLNotificationPtr existing_notification = existing_it->second;
if (pNotif != existing_notification
&& pNotif->isEquivalentTo(existing_notification))
{
// copy notification instance data over to oldest instance
// of this unique notification and update it
existing_notification->updateFrom(pNotif);
// then delete the new one
cancel(pNotif);
}
}
break;
case LLNotification::KEEP_OLD:
break;
case LLNotification::CANCEL_OLD:
// already handled by filter logic
break;
default:
break;
}
return false;
}
void LLNotifications::addChannel(LLNotificationChannelPtr pChan)
{
mChannels[pChan->getName()] = pChan;
}
LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName)
{
ChannelMap::iterator p = mChannels.find(channelName);
if(p == mChannels.end())
{
llerrs << "Did not find channel named " << channelName << llendl;
return LLNotificationChannelPtr();
}
return p->second;
return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName));
}
@ -1288,24 +1343,21 @@ void LLNotifications::createDefaultChannels()
{
// now construct the various channels AFTER loading the notifications,
// because the history channel is going to rewrite the stored notifications file
LLNotificationChannel::buildChannel("Enabled", "",
!boost::bind(&LLNotifications::getIgnoreAllNotifications, this));
LLNotificationChannel::buildChannel("Expiration", "Enabled",
boost::bind(&LLNotifications::expirationFilter, this, _1));
LLNotificationChannel::buildChannel("Unexpired", "Enabled",
!boost::bind(&LLNotifications::expirationFilter, this, _1)); // use negated bind
LLNotificationChannel::buildChannel("Unique", "Unexpired",
boost::bind(&LLNotifications::uniqueFilter, this, _1));
LLNotificationChannel::buildChannel("Ignore", "Unique",
filterIgnoredNotifications);
LLNotificationChannel::buildChannel("VisibilityRules", "Ignore",
boost::bind(&LLNotifications::isVisibleByRules, this, _1));
LLNotificationChannel::buildChannel("Visible", "VisibilityRules",
&LLNotificationFilters::includeEverything);
// create special persistent notification channel
// this isn't a leak, don't worry about the empty "new"
new LLPersistentNotificationChannel();
mDefaultChannels.push_back(new LLNotificationChannel("Enabled", "",
!boost::bind(&LLNotifications::getIgnoreAllNotifications, this)));
mDefaultChannels.push_back(new LLNotificationChannel("Expiration", "Enabled",
boost::bind(&LLNotifications::expirationFilter, this, _1)));
mDefaultChannels.push_back(new LLNotificationChannel("Unexpired", "Enabled",
!boost::bind(&LLNotifications::expirationFilter, this, _1))); // use negated bind
mDefaultChannels.push_back(new LLNotificationChannel("Unique", "Unexpired",
boost::bind(&LLNotifications::uniqueFilter, this, _1)));
mDefaultChannels.push_back(new LLNotificationChannel("Ignore", "Unique",
filterIgnoredNotifications));
mDefaultChannels.push_back(new LLNotificationChannel("VisibilityRules", "Ignore",
boost::bind(&LLNotifications::isVisibleByRules, this, _1)));
mDefaultChannels.push_back(new LLNotificationChannel("Visible", "VisibilityRules",
&LLNotificationFilters::includeEverything));
mDefaultChannels.push_back(new LLPersistentNotificationChannel());
// connect action methods to these channels
LLNotifications::instance().getChannel("Enabled")->
@ -1537,34 +1589,32 @@ void LLNotifications::addFromCallback(const LLSD& name)
add(name.asString(), LLSD(), LLSD());
}
LLNotificationPtr LLNotifications::add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload)
LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload)
{
LLNotification::Params::Functor functor_p;
functor_p.name = name;
return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
}
LLNotificationPtr LLNotifications::add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload,
const std::string& functor_name)
LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, const std::string& functor_name)
{
LLNotification::Params::Functor functor_p;
functor_p.name = functor_name;
return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
return add(LLNotification::Params().name(name)
.substitutions(substitutions)
.payload(payload)
.functor(functor_p));
}
//virtual
LLNotificationPtr LLNotifications::add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload,
LLNotificationFunctorRegistry::ResponseFunctor functor)
LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, LLNotificationFunctorRegistry::ResponseFunctor functor)
{
LLNotification::Params::Functor functor_p;
functor_p.function = functor;
return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));
return add(LLNotification::Params().name(name)
.substitutions(substitutions)
.payload(payload)
.functor(functor_p));
}
// generalized add function that takes a parameter block object for more complex instantiations
@ -1595,12 +1645,11 @@ void LLNotifications::cancel(LLNotificationPtr pNotif)
if (pNotif == NULL || pNotif->isCancelled()) return;
LLNotificationSet::iterator it=mItems.find(pNotif);
if (it == mItems.end())
if (it != mItems.end())
{
llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl;
pNotif->cancel();
updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
}
pNotif->cancel();
updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif);
}
void LLNotifications::cancelByName(const std::string& name)
@ -1639,7 +1688,7 @@ void LLNotifications::update(const LLNotificationPtr pNotif)
LLNotificationPtr LLNotifications::find(LLUUID uuid)
{
LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid));
LLNotificationPtr target = LLNotificationPtr(new LLNotification(LLNotification::Params().id(uuid)));
LLNotificationSet::iterator it=mItems.find(target);
if (it == mItems.end())
{
@ -1778,22 +1827,18 @@ std::ostream& operator<<(std::ostream& s, const LLNotification& notification)
return s;
}
//static
void LLPostponedNotification::lookupName(LLPostponedNotification* thiz,
const LLUUID& id,
void LLPostponedNotification::lookupName(const LLUUID& id,
bool is_group)
{
if (is_group)
{
gCacheName->getGroup(id,
boost::bind(&LLPostponedNotification::onGroupNameCache,
thiz, _1, _2, _3));
this, _1, _2, _3));
}
else
{
LLAvatarNameCache::get(id,
boost::bind(&LLPostponedNotification::onAvatarNameCache,
thiz, _1, _2));
fetchAvatarName(id);
}
}
@ -1804,9 +1849,24 @@ void LLPostponedNotification::onGroupNameCache(const LLUUID& id,
finalizeName(full_name);
}
void LLPostponedNotification::fetchAvatarName(const LLUUID& id)
{
if (id.notNull())
{
if (mAvatarNameCacheConnection.connected())
{
mAvatarNameCacheConnection.disconnect();
}
mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLPostponedNotification::onAvatarNameCache, this, _1, _2));
}
}
void LLPostponedNotification::onAvatarNameCache(const LLUUID& agent_id,
const LLAvatarName& av_name)
{
mAvatarNameCacheConnection.disconnect();
std::string name = av_name.getCompleteName();
// from PE merge - we should figure out if this is the right thing to do

View File

@ -87,17 +87,16 @@
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/type_traits.hpp>
#include <boost/signals2.hpp>
// we want to minimize external dependencies, but this one is important
#include "llsd.h"
// and we need this to manage the notification callbacks
#include "llevents.h"
#include "llfunctorregistry.h"
#include "llpointer.h"
#include "llinitparam.h"
#include "llnotificationslistener.h"
#include "llmortician.h"
#include "llnotificationptr.h"
#include "llpointer.h"
#include "llrefcount.h"
#include "llsdparam.h"
class LLAvatarName;
typedef enum e_notification_priority
@ -164,6 +163,7 @@ public:
struct FormElementBase : public LLInitParam::Block<FormElementBase>
{
Optional<std::string> name;
Optional<bool> enabled;
FormElementBase();
};
@ -233,16 +233,21 @@ public:
} EIgnoreType;
LLNotificationForm();
LLNotificationForm(const LLNotificationForm&);
LLNotificationForm(const LLSD& sd);
LLNotificationForm(const std::string& name, const Params& p);
void fromLLSD(const LLSD& sd);
LLSD asLLSD() const;
S32 getNumElements() { return mFormData.size(); }
LLSD getElement(S32 index) { return mFormData.get(index); }
LLSD getElement(const std::string& element_name);
bool hasElement(const std::string& element_name);
void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD());
void getElements(LLSD& elements, S32 offset = 0);
bool hasElement(const std::string& element_name) const;
bool getElementEnabled(const std::string& element_name) const;
void setElementEnabled(const std::string& element_name, bool enabled);
void addElement(const std::string& type, const std::string& name, const LLSD& value = LLSD(), bool enabled = true);
void formatElements(const LLSD& substitutions);
// appends form elements from another form serialized as LLSD
void append(const LLSD& sub_form);
@ -296,42 +301,52 @@ LOG_CLASS(LLNotification);
friend class LLNotifications;
public:
// parameter object used to instantiate a new notification
struct Params : public LLInitParam::Block<Params>
{
friend class LLNotification;
Mandatory<std::string> name;
// optional
Optional<LLSD> substitutions;
Optional<LLSD> payload;
Optional<LLUUID> id;
Optional<LLSD> substitutions,
form_elements,
payload;
Optional<ENotificationPriority, NotificationPriorityValues> priority;
Optional<LLSD> form_elements;
Optional<LLDate> time_stamp;
Optional<LLDate> time_stamp,
expiry;
Optional<LLNotificationContext*> context;
Optional<void*> responder;
Optional<bool> offer_from_agent;
Optional<bool> is_dnd;
struct Functor : public LLInitParam::ChoiceBlock<Functor>
{
Alternative<std::string> name;
Alternative<LLNotificationFunctorRegistry::ResponseFunctor> function;
Alternative<LLNotificationResponderPtr> responder;
Alternative<LLSD> responder_sd;
Functor()
: name("functor_name"),
: name("responseFunctor"),
function("functor"),
responder("responder")
responder("responder"),
responder_sd("responder_sd")
{}
};
Optional<Functor> functor;
Params()
: name("name"),
id("id"),
priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
time_stamp("time_stamp"),
time_stamp("time"),
payload("payload"),
form_elements("form_elements")
form_elements("form"),
substitutions("substitutions"),
expiry("expiry"),
offer_from_agent("offer_from_agent", false),
is_dnd("is_dnd", false)
{
time_stamp = LLDate::now();
responder = NULL;
@ -340,9 +355,13 @@ public:
Params(const std::string& _name)
: name("name"),
priority("priority", NOTIFICATION_PRIORITY_UNSPECIFIED),
time_stamp("time_stamp"),
time_stamp("time"),
payload("payload"),
form_elements("form_elements")
form_elements("form"),
substitutions("substitutions"),
expiry("expiry"),
offer_from_agent("offer_from_agent", false),
is_dnd("is_dnd", false)
{
functor.name = _name;
name = _name;
@ -355,7 +374,7 @@ public:
private:
LLUUID mId;
const LLUUID mId;
LLSD mPayload;
LLSD mSubstitutions;
LLDate mTimestamp;
@ -367,8 +386,9 @@ private:
ENotificationPriority mPriority;
LLNotificationFormPtr mForm;
void* mResponderObj; // TODO - refactor/remove this field
bool mIsReusable;
LLNotificationResponderPtr mResponder;
bool mOfferFromAgent;
bool mIsDND;
// a reference to the template
LLNotificationTemplatePtr mTemplatep;
@ -392,18 +412,10 @@ private:
void init(const std::string& template_name, const LLSD& form_elements);
LLNotification(const Params& p);
// this is just for making it easy to look things up in a set organized by UUID -- DON'T USE IT
// for anything real!
LLNotification(LLUUID uuid) : mId(uuid), mCancelled(false), mRespondedTo(false), mIgnored(false), mPriority(NOTIFICATION_PRIORITY_UNSPECIFIED), mTemporaryResponder(false) {}
void cancel();
public:
// constructor from a saved notification
LLNotification(const LLSD& sd);
LLNotification(const LLSDParamAdapter<Params>& p);
void setResponseFunctor(std::string const &responseFunctorName);
@ -446,7 +458,12 @@ public:
// ["time"] = time at which notification was generated;
// ["expiry"] = time at which notification expires;
// ["responseFunctor"] = name of registered functor that handles responses to notification;
LLSD asLLSD();
LLSD asLLSD(bool excludeTemplateElements = false);
const LLNotificationFormPtr getForm();
void updateForm(const LLNotificationFormPtr& form);
void repost();
void respond(const LLSD& sd);
void respondWithDefault();
@ -507,6 +524,21 @@ public:
return mTimestamp;
}
bool getOfferFromAgent() const
{
return mOfferFromAgent;
}
bool isDND() const
{
return mIsDND;
}
void setDND(const bool flag)
{
mIsDND = flag;
}
std::string getType() const;
std::string getMessage() const;
std::string getFooter() const;
@ -514,8 +546,21 @@ public:
std::string getURL() const;
S32 getURLOption() const;
S32 getURLOpenExternally() const;
bool canLogToChat() const;
bool canLogToIM() const;
bool canShowToast() const;
bool hasFormElements() const;
void playSound();
typedef enum e_combine_behavior
{
REPLACE_WITH_NEW,
KEEP_OLD,
CANCEL_OLD
} ECombineBehavior;
const LLNotificationFormPtr getForm();
ECombineBehavior getCombineBehavior() const;
const LLDate getExpiration() const
{
@ -532,10 +577,6 @@ public:
return mId;
}
bool isReusable() { return mIsReusable; }
void setReusable(bool reusable) { mIsReusable = reusable; }
// comparing two notifications normally means comparing them by UUID (so we can look them
// up quickly this way)
bool operator<(const LLNotification& rhs) const
@ -647,44 +688,17 @@ namespace LLNotificationFilters
namespace LLNotificationComparators
{
typedef enum e_direction { ORDER_DECREASING, ORDER_INCREASING } EDirection;
// generic order functor that takes method or member variable reference
template<typename T>
struct orderBy
struct orderByUUID
{
typedef boost::function<T (LLNotificationPtr)> field_t;
orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {}
bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs)
{
if (mDirection == ORDER_DECREASING)
{
return mField(lhs) > mField(rhs);
}
else
{
return mField(lhs) < mField(rhs);
}
return lhs->id() < rhs->id();
}
field_t mField;
EDirection mDirection;
};
struct orderByUUID : public orderBy<const LLUUID&>
{
orderByUUID(EDirection direction = ORDER_INCREASING) : orderBy<const LLUUID&>(&LLNotification::id, direction) {}
};
struct orderByDate : public orderBy<const LLDate&>
{
orderByDate(EDirection direction = ORDER_INCREASING) : orderBy<const LLDate&>(&LLNotification::getDate, direction) {}
};
};
typedef boost::function<bool (LLNotificationPtr)> LLNotificationFilter;
typedef boost::function<bool (LLNotificationPtr, LLNotificationPtr)> LLNotificationComparator;
typedef std::set<LLNotificationPtr, LLNotificationComparator> LLNotificationSet;
typedef std::set<LLNotificationPtr, LLNotificationComparators::orderByUUID> LLNotificationSet;
typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
// ========================================================
@ -705,12 +719,14 @@ typedef std::multimap<std::string, LLNotificationPtr> LLNotificationMap;
// all of the built-in tests should attach to the "Visible" channel
//
class LLNotificationChannelBase :
public LLEventTrackable
public LLEventTrackable,
public LLRefCount
{
LOG_CLASS(LLNotificationChannelBase);
public:
LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) :
mFilter(filter), mItems(comp)
LLNotificationChannelBase(LLNotificationFilter filter)
: mFilter(filter),
mItems()
{}
virtual ~LLNotificationChannelBase() {}
// you can also connect to a Channel, so you can be notified of
@ -776,6 +792,9 @@ protected:
virtual void onDelete(LLNotificationPtr p) {}
virtual void onChange(LLNotificationPtr p) {}
virtual void onFilterPass(LLNotificationPtr p) {}
virtual void onFilterFail(LLNotificationPtr p) {}
bool updateItem(const LLSD& payload, LLNotificationPtr pNotification);
LLNotificationFilter mFilter;
};
@ -785,64 +804,53 @@ protected:
// destroy it, but if it becomes necessary to do so, the shared_ptr model
// will ensure that we don't leak resources.
class LLNotificationChannel;
typedef boost::shared_ptr<LLNotificationChannel> LLNotificationChannelPtr;
typedef boost::intrusive_ptr<LLNotificationChannel> LLNotificationChannelPtr;
// manages a list of notifications
// Note that if this is ever copied around, we might find ourselves with multiple copies
// of a queue with notifications being added to different nonequivalent copies. So we
// make it inherit from boost::noncopyable, and then create a map of shared_ptr to manage it.
//
// NOTE: LLNotificationChannel is self-registering. The *correct* way to create one is to
// do something like:
// LLNotificationChannel::buildChannel("name", "parent"...);
// This returns an LLNotificationChannelPtr, which you can store, or
// you can then retrieve the channel by using the registry:
// LLNotifications::instance().getChannel("name")...
// make it inherit from boost::noncopyable, and then create a map of LLPointer to manage it.
//
class LLNotificationChannel :
boost::noncopyable,
public LLNotificationChannelBase
public LLNotificationChannelBase,
public LLInstanceTracker<LLNotificationChannel, std::string>
{
LOG_CLASS(LLNotificationChannel);
public:
// Notification Channels have a filter, which determines which notifications
// will be added to this channel.
// Channel filters cannot change.
struct Params : public LLInitParam::Block<Params>
{
Mandatory<std::string> name;
Optional<LLNotificationFilter> filter;
Multiple<std::string> sources;
};
LLNotificationChannel(const Params& p = Params());
LLNotificationChannel(const std::string& name, const std::string& parent, LLNotificationFilter filter);
virtual ~LLNotificationChannel() {}
typedef LLNotificationSet::iterator Iterator;
std::string getName() const { return mName; }
std::string getParentChannelName() { return mParent; }
void connectToChannel(const std::string& channel_name);
bool isEmpty() const;
S32 size() const;
Iterator begin();
Iterator end();
size_t size();
// Channels have a comparator to control sort order;
// the default sorts by arrival date
void setComparator(LLNotificationComparator comparator);
std::string summarize();
// factory method for constructing these channels; since they're self-registering,
// we want to make sure that you can't use new to make them
static LLNotificationChannelPtr buildChannel(const std::string& name, const std::string& parent,
LLNotificationFilter filter=LLNotificationFilters::includeEverything,
LLNotificationComparator comparator=LLNotificationComparators::orderByUUID());
protected:
// Notification Channels have a filter, which determines which notifications
// will be added to this channel.
// Channel filters cannot change.
// Channels have a protected constructor so you can't make smart pointers that don't
// come from our internal reference; call NotificationChannel::build(args)
LLNotificationChannel(const std::string& name, const std::string& parent,
LLNotificationFilter filter, LLNotificationComparator comparator);
private:
std::string mName;
std::string mParent;
LLNotificationComparator mComparator;
};
// An interface class to provide a clean linker seam to the LLNotifications class.
@ -925,10 +933,6 @@ public:
void createDefaultChannels();
typedef std::map<std::string, LLNotificationChannelPtr> ChannelMap;
ChannelMap mChannels;
void addChannel(LLNotificationChannelPtr pChan);
LLNotificationChannelPtr getChannel(const std::string& channelName);
std::string getGlobalString(const std::string& key) const;
@ -966,7 +970,7 @@ private:
bool mIgnoreAllNotifications;
boost::scoped_ptr<LLNotificationsListener> mListener;
std::vector<LLNotificationChannelPtr> mDefaultChannels;
};
/**
@ -979,7 +983,7 @@ private:
* 1 create class derived from LLPostponedNotification;
* 2 call LLPostponedNotification::add method;
*/
class LLPostponedNotification
class LLPostponedNotification : public LLMortician
{
public:
/**
@ -997,26 +1001,38 @@ public:
thiz->mParams = params;
// Avoid header file dependency on llcachename.h
lookupName(thiz, id, is_group);
thiz->lookupName(id, is_group);
}
private:
static void lookupName(LLPostponedNotification* thiz, const LLUUID& id, bool is_group);
void lookupName(const LLUUID& id, bool is_group);
// only used for groups
void onGroupNameCache(const LLUUID& id, const std::string& full_name, bool is_group);
// only used for avatars
void fetchAvatarName(const LLUUID& id);
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
// used for both group and avatar names
void finalizeName(const std::string& name);
void cleanup()
{
delete this;
die();
}
protected:
LLPostponedNotification() {}
virtual ~LLPostponedNotification() {}
LLPostponedNotification()
: mParams(),
mName(),
mAvatarNameCacheConnection()
{}
virtual ~LLPostponedNotification()
{
if (mAvatarNameCacheConnection.connected())
{
mAvatarNameCacheConnection.disconnect();
}
}
/**
* Abstract method provides possibility to modify notification parameters and
@ -1027,6 +1043,58 @@ protected:
LLNotification::Params mParams;
std::string mName;
boost::signals2::connection mAvatarNameCacheConnection;
};
// Stores only persistent notifications.
// Class users can use connectChanged() to process persistent notifications
// (see LLPersistentNotificationStorage for example).
class LLPersistentNotificationChannel : public LLNotificationChannel
{
LOG_CLASS(LLPersistentNotificationChannel);
public:
LLPersistentNotificationChannel()
: LLNotificationChannel("Persistent", "Visible", &notificationFilter)
{
}
typedef std::vector<LLNotificationPtr> history_list_t;
history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); }
history_list_t::iterator endHistory() { return mHistory.end(); }
private:
struct sortByTime
{
S32 operator ()(const LLNotificationPtr& a, const LLNotificationPtr& b)
{
return a->getDate() < b->getDate();
}
};
void sortHistory()
{
std::sort(mHistory.begin(), mHistory.end(), sortByTime());
}
// The channel gets all persistent notifications except those that have been canceled
static bool notificationFilter(LLNotificationPtr pNotification)
{
bool handle_notification = false;
handle_notification = pNotification->isPersistent()
&& !pNotification->isCancelled();
return handle_notification;
}
void onAdd(LLNotificationPtr p)
{
mHistory.push_back(p);
}
std::vector<LLNotificationPtr> mHistory;
};
#endif//LL_LLNOTIFICATIONS_H

View File

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

View File

@ -1,69 +0,0 @@
/**
* @file llnotificationslistener.h
* @author Brad Kittenbrink
* @date 2009-07-08
* @brief Wrap subset of LLNotifications API in event API for test scripts.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLNOTIFICATIONSLISTENER_H
#define LL_LLNOTIFICATIONSLISTENER_H
#include "lleventapi.h"
#include "llnotificationptr.h"
#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
class LLNotifications;
class LLSD;
class LLNotificationsListener : public LLEventAPI
{
public:
LLNotificationsListener(LLNotifications & notifications);
~LLNotificationsListener();
private:
void requestAdd(LLSD const & event_data) const;
void NotificationResponder(const std::string& replypump,
const LLSD& notification,
const LLSD& response) const;
void listChannels(const LLSD& params) const;
void listChannelNotifications(const LLSD& params) const;
void respond(const LLSD& params) const;
void cancel(const LLSD& params) const;
void ignore(const LLSD& params) const;
void forward(const LLSD& params);
static LLSD asLLSD(LLNotificationPtr);
class Forwarder;
typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
ForwarderMap mForwarders;
LLNotifications & mNotifications;
};
#endif // LL_LLNOTIFICATIONSLISTENER_H

View File

@ -49,7 +49,6 @@
//#include "llfunctorregistry.h"
//#include "llpointer.h"
#include "llinitparam.h"
//#include "llnotificationslistener.h"
//#include "llnotificationptr.h"
//#include "llcachename.h"
#include "llnotifications.h"
@ -61,6 +60,18 @@ typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
// from the appropriate local language directory).
struct LLNotificationTemplate
{
struct CombineBehaviorNames
: public LLInitParam::TypeValuesHelper<LLNotification::ECombineBehavior, CombineBehaviorNames>
{
static void declareValues()
{
declare("replace_with_new", LLNotification::REPLACE_WITH_NEW);
declare("keep_old", LLNotification::KEEP_OLD);
declare("cancel_old", LLNotification::CANCEL_OLD);
}
};
struct GlobalString : public LLInitParam::Block<GlobalString>
{
Mandatory<std::string> name,
@ -94,9 +105,11 @@ struct LLNotificationTemplate
Optional<LLInitParam::Flag> dummy_val;
public:
Multiple<UniquenessContext> contexts;
Optional<LLNotification::ECombineBehavior, CombineBehaviorNames> combine;
UniquenessConstraint()
: contexts("context"),
combine("combine", LLNotification::REPLACE_WITH_NEW),
dummy_val("")
{}
};
@ -183,7 +196,10 @@ struct LLNotificationTemplate
struct Params : public LLInitParam::Block<Params>
{
Mandatory<std::string> name;
Optional<bool> persist;
Optional<bool> persist,
log_to_im,
show_toast,
log_to_chat;
Optional<std::string> functor,
icon,
label,
@ -204,6 +220,9 @@ struct LLNotificationTemplate
Params()
: name("name"),
persist("persist", false),
log_to_im("log_to_im", false),
show_toast("show_toast", true),
log_to_chat("log_to_chat", true),
functor("functor"),
icon("icon"),
label("label"),
@ -262,6 +281,7 @@ struct LLNotificationTemplate
// (used for things like progress indications, or repeating warnings
// like "the grid is going down in N minutes")
bool mUnique;
LLNotification::ECombineBehavior mCombineBehavior;
// if we want to be unique only if a certain part of the payload or substitutions args
// are constant specify the field names for the payload. The notification will only be
// combined if all of the fields named in the context are identical in the
@ -302,12 +322,15 @@ struct LLNotificationTemplate
LLNotificationFormPtr mForm;
// default priority for notifications of this type
ENotificationPriority mPriority;
// UUID of the audio file to be played when this notification arrives
// this is loaded as a name, but looked up to get the UUID upon template load.
// If null, it wasn't specified.
LLUUID mSoundEffect;
// Stores the sound name which can then be used to play the sound using make_ui_sound
std::string mSoundName;
// List of tags that rules can match against.
std::list<std::string> mTags;
// inject these notifications into chat/IM streams
bool mLogToChat;
bool mLogToIM;
bool mShowToast;
};
#endif //LL_LLNOTIFICATION_TEMPLATE_H

View File

@ -45,7 +45,8 @@ LLResizeBar::LLResizeBar(const LLResizeBar::Params& p)
mSide( p.side ),
mSnappingEnabled(p.snapping_enabled),
mAllowDoubleClickSnapping(p.allow_double_click_snapping),
mResizingView(p.resizing_view)
mResizingView(p.resizing_view),
mResizeListener(NULL)
{
setFollowsNone();
// set up some generically good follow code.
@ -300,6 +301,11 @@ BOOL LLResizeBar::handleHover(S32 x, S32 y, MASK mask)
}
}
if (mResizeListener)
{
mResizeListener(NULL);
}
return handled;
} // end LLResizeBar::handleHover

View File

@ -71,6 +71,7 @@ public:
void setEnableSnapping(BOOL enable) { mSnappingEnabled = enable; }
void setAllowDoubleClickSnapping(BOOL allow) { mAllowDoubleClickSnapping = allow; }
bool canResize() { return getEnabled() && mMaxSize > mMinSize; }
void setResizeListener(boost::function<void(void*)> listener) {mResizeListener = listener;}
private:
S32 mDragLastScreenX;
@ -84,6 +85,7 @@ private:
BOOL mSnappingEnabled;
BOOL mAllowDoubleClickSnapping;
LLView* mResizingView;
boost::function<void(void*)> mResizeListener;
};
#endif // LL_RESIZEBAR_H

View File

@ -642,3 +642,8 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
{
changeLine( mStepSize, TRUE );
}
void LLScrollbar::setThickness(S32 thickness)
{
mThickness = thickness < 0 ? LLUI::sSettingGroups["config"]->getS32("UIScrollbarSize") : thickness;
}

View File

@ -124,6 +124,9 @@ public:
void onLineUpBtnPressed(const LLSD& data);
void onLineDownBtnPressed(const LLSD& data);
S32 getThickness() const { return mThickness; }
void setThickness(S32 thickness);
private:
void updateThumbRect();

View File

@ -73,7 +73,8 @@ LLScrollContainer::Params::Params()
hide_scrollbar("hide_scrollbar"),
min_auto_scroll_rate("min_auto_scroll_rate", 100),
max_auto_scroll_rate("max_auto_scroll_rate", 1000),
reserve_scroll_corner("reserve_scroll_corner", false)
reserve_scroll_corner("reserve_scroll_corner", false),
size("size", -1)
{}
@ -88,9 +89,12 @@ LLScrollContainer::LLScrollContainer(const LLScrollContainer::Params& p)
mReserveScrollCorner(p.reserve_scroll_corner),
mMinAutoScrollRate(p.min_auto_scroll_rate),
mMaxAutoScrollRate(p.max_auto_scroll_rate),
mScrolledView(NULL)
mScrolledView(NULL),
mSize(p.size)
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0);
S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize);
LLRect border_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 );
LLViewBorder::Params params;
params.name("scroll border");
@ -276,7 +280,6 @@ BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
EAcceptance* accept,
std::string& tooltip_msg)
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
// Scroll folder view if needed. Never accepts a drag or drop.
*accept = ACCEPT_NO;
BOOL handled = autoScroll(x, y);
@ -292,7 +295,8 @@ BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
bool LLScrollContainer::autoScroll(S32 x, S32 y)
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0);
S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize);
bool scrolling = false;
if( mScrollbar[HORIZONTAL]->getVisible() || mScrollbar[VERTICAL]->getVisible() )
@ -365,7 +369,9 @@ bool LLScrollContainer::autoScroll(S32 x, S32 y)
void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height, BOOL* show_h_scrollbar, BOOL* show_v_scrollbar ) const
{
const LLRect& doc_rect = getScrolledViewRect();
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0);
S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize);
S32 doc_width = doc_rect.getWidth();
S32 doc_height = doc_rect.getHeight();
@ -406,7 +412,9 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height
void LLScrollContainer::draw()
{
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0);
S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize);
if (mAutoScrolling)
{
// add acceleration to autoscroll
@ -515,7 +523,9 @@ void LLScrollContainer::updateScroll()
{
return;
}
static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
static LLUICachedControl<S32> scrollbar_size_control ("UIScrollbarSize", 0);
S32 scrollbar_size = (mSize == -1 ? scrollbar_size_control : mSize);
LLRect doc_rect = mScrolledView->getRect();
S32 doc_width = doc_rect.getWidth();
S32 doc_height = doc_rect.getHeight();
@ -716,3 +726,9 @@ S32 LLScrollContainer::getBorderWidth() const
return 0;
}
void LLScrollContainer::setSize(S32 size)
{
mSize = size;
mScrollbar[VERTICAL]->setThickness(size);
mScrollbar[HORIZONTAL]->setThickness(size);
}

View File

@ -68,6 +68,7 @@ public:
max_auto_scroll_rate;
Optional<LLUIColor> bg_color;
Optional<LLScrollbar::callback_t> scroll_callback;
Optional<S32> size;
Params();
};
@ -116,6 +117,9 @@ public:
bool autoScroll(S32 x, S32 y);
S32 getSize() const { return mSize; }
void setSize(S32 thickness);
protected:
LLView* mScrolledView;

View File

@ -1801,6 +1801,9 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
// (N.B. callbacks don't take const refs as id is local scope)
bool is_group = (mContextMenuType == MENU_GROUP);
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
registrar.add("Url.ShowProfile", boost::bind(&LLScrollListCtrl::showProfile, id, is_group));
registrar.add("Url.SendIM", boost::bind(&LLScrollListCtrl::sendIM, id));
registrar.add("Url.AddFriend", boost::bind(&LLScrollListCtrl::addFriend, id));
registrar.add("Url.Execute", boost::bind(&LLScrollListCtrl::showNameDetails, id, is_group));
registrar.add("Url.CopyLabel", boost::bind(&LLScrollListCtrl::copyNameToClipboard, id, is_group));
registrar.add("Url.CopyUrl", boost::bind(&LLScrollListCtrl::copySLURLToClipboard, id, is_group));
@ -1821,11 +1824,33 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
return FALSE;
}
void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
void LLScrollListCtrl::showProfile(std::string id, bool is_group)
{
// show the resident's profile or the group profile
std::string sltype = is_group ? "group" : "agent";
std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
LLUrlAction::showProfile(slurl);
}
void LLScrollListCtrl::sendIM(std::string id)
{
// send im to the resident
std::string slurl = "secondlife:///app/agent/" + id + "/about";
LLUrlAction::sendIM(slurl);
}
void LLScrollListCtrl::addFriend(std::string id)
{
// add resident to friends list
std::string slurl = "secondlife:///app/agent/" + id + "/about";
LLUrlAction::addFriend(slurl);
}
void LLScrollListCtrl::showNameDetails(std::string id, bool is_group)
{
// open the resident's details or the group details
std::string sltype = is_group ? "group" : "agent";
std::string slurl = "secondlife:///app/" + sltype + "/" + id + "/about";
LLUrlAction::clickAction(slurl);
}
@ -1841,7 +1866,7 @@ void LLScrollListCtrl::copyNameToClipboard(std::string id, bool is_group)
{
LLAvatarName av_name;
LLAvatarNameCache::get(LLUUID(id), &av_name);
name = av_name.getLegacyName();
name = av_name.getAccountName();
}
LLUrlAction::copyURLToClipboard(name);
}

View File

@ -430,6 +430,9 @@ private:
BOOL setSort(S32 column, BOOL ascending);
S32 getLinesPerPage();
static void showProfile(std::string id, bool is_group);
static void sendIM(std::string id);
static void addFriend(std::string id);
static void showNameDetails(std::string id, bool is_group);
static void copyNameToClipboard(std::string id, bool is_group);
static void copySLURLToClipboard(std::string id, bool is_group);

View File

@ -52,6 +52,7 @@ LLSpinCtrl::Params::Params()
: label_width("label_width"),
decimal_digits("decimal_digits"),
allow_text_entry("allow_text_entry", true),
allow_digits_only("allow_digits_only", false),
label_wrap("label_wrap", false),
text_enabled_color("text_enabled_color"),
text_disabled_color("text_disabled_color"),
@ -129,6 +130,10 @@ LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this ));
if (p.allow_digits_only)
{
mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
}
//RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
// than when it doesn't. Instead, if you always have to double click to select all the text,
// it's easier to understand

View File

@ -44,6 +44,7 @@ public:
Optional<S32> label_width;
Optional<U32> decimal_digits;
Optional<bool> allow_text_entry;
Optional<bool> allow_digits_only;
Optional<bool> label_wrap;
Optional<LLUIColor> text_enabled_color;

View File

@ -506,8 +506,8 @@ void LLTabContainer::draw()
}
}
mPrevArrowBtn->setFlashing(FALSE);
mNextArrowBtn->setFlashing(FALSE);
mPrevArrowBtn->setFlashing(false);
mNextArrowBtn->setFlashing(false);
}
@ -1209,7 +1209,11 @@ void LLTabContainer::removeTabPanel(LLPanel* child)
update_images(mTabList[mTabList.size()-2], mLastTabParams, getTabPosition());
}
removeChild( tuple->mButton );
if (!getTabsHidden())
{
// We need to remove tab buttons only if the tabs are not hidden.
removeChild( tuple->mButton );
}
delete tuple->mButton;
removeChild( tuple->mTabPanel );
@ -1480,13 +1484,21 @@ BOOL LLTabContainer::setTab(S32 which)
{
LLTabTuple* tuple = *iter;
BOOL is_selected = ( tuple == selected_tuple );
tuple->mButton->setUseEllipses(mUseTabEllipses);
tuple->mButton->setHAlign(mFontHalign);
tuple->mTabPanel->setVisible( is_selected );
// tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
tuple->mButton->setToggleState( is_selected );
// RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
tuple->mButton->setTabStop( is_selected );
// Although the selected tab must be complete, we may have hollow LLTabTuple tucked in the list
if (tuple->mButton)
{
tuple->mButton->setUseEllipses(mUseTabEllipses);
tuple->mButton->setHAlign(mFontHalign);
tuple->mButton->setToggleState( is_selected );
// RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs
tuple->mButton->setTabStop( is_selected );
}
if (tuple->mTabPanel)
{
tuple->mTabPanel->setVisible( is_selected );
//tuple->mTabPanel->setFocus(is_selected); // not clear that we want to do this here.
}
if (is_selected)
{
@ -1557,8 +1569,7 @@ BOOL LLTabContainer::selectTabByName(const std::string& name)
LLPanel* panel = getPanelByName(name);
if (!panel)
{
llwarns << "LLTabContainer::selectTabByName("
<< name << ") failed" << llendl;
llwarns << "LLTabContainer::selectTabByName(" << name << ") failed" << llendl;
return FALSE;
}

View File

@ -188,10 +188,11 @@ public:
void selectFirstTab();
void selectLastTab();
void selectNextTab();
void selectPrevTab();
void selectPrevTab();
BOOL selectTabPanel( LLPanel* child );
BOOL selectTab(S32 which);
BOOL selectTabByName(const std::string& title);
void setCurrentPanelIndex(S32 index) { mCurrentTabIdx = index; }
BOOL getTabPanelFlashing(LLPanel* child);
void setTabPanelFlashing(LLPanel* child, BOOL state);
@ -242,8 +243,6 @@ private:
void setTabsHidden(BOOL hidden) { mTabsHidden = hidden; }
BOOL getTabsHidden() const { return mTabsHidden; }
void setCurrentPanelIndex(S32 index) { mCurrentTabIdx = index; }
void scrollPrev() { mScrollPos = llmax(0, mScrollPos-1); } // No wrap
void scrollNext() { mScrollPos = llmin(mScrollPos+1, mMaxScrollPos); } // No wrap

View File

@ -46,6 +46,7 @@
const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
const S32 CURSOR_THICKNESS = 2;
const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click.
LLTextBase::line_info::line_info(S32 index_start, S32 index_end, LLRect rect, S32 line_num)
: mDocIndexStart(index_start),
@ -145,6 +146,7 @@ LLTextBase::Params::Params()
: cursor_color("cursor_color"),
text_color("text_color"),
text_readonly_color("text_readonly_color"),
text_tentative_color("text_tentative_color"),
bg_visible("bg_visible", false),
border_visible("border_visible", false),
bg_readonly_color("bg_readonly_color"),
@ -179,7 +181,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
: LLUICtrl(p, LLTextViewModelPtr(new LLTextViewModel)),
mURLClickSignal(NULL),
mMaxTextByteLength( p.max_text_length ),
mDefaultFont(p.font),
mFont(p.font),
mFontShadow(p.font_shadow),
mPopupMenu(NULL),
mReadOnly(p.read_only),
@ -190,6 +192,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
mFgColor(p.text_color),
mBorderVisible( p.border_visible ),
mReadOnlyFgColor(p.text_readonly_color),
mTentativeFgColor(p.text_tentative_color()),
mWriteableBgColor(p.bg_writeable_color),
mReadOnlyBgColor(p.bg_readonly_color),
mFocusBgColor(p.bg_focus_color),
@ -319,21 +322,26 @@ bool LLTextBase::truncate()
return did_truncate;
}
const LLStyle::Params& LLTextBase::getDefaultStyleParams()
const LLStyle::Params& LLTextBase::getStyleParams()
{
//FIXME: convert mDefaultStyle to a flyweight http://www.boost.org/doc/libs/1_40_0/libs/flyweight/doc/index.html
//and eliminate color member values
if (mStyleDirty)
{
mDefaultStyle
mStyle
.color(LLUIColor(&mFgColor)) // pass linked color instead of copy of mFGColor
.readonly_color(LLUIColor(&mReadOnlyFgColor))
.selected_color(LLUIColor(&mTextSelectedColor))
.font(mDefaultFont)
.font(mFont)
.drop_shadow(mFontShadow);
mStyleDirty = false;
}
return mDefaultStyle;
return mStyle;
}
void LLTextBase::beforeValueChange()
{
}
void LLTextBase::onValueChange(S32 start, S32 end)
@ -351,7 +359,6 @@ void LLTextBase::drawSelectionBackground()
S32 selection_left = llmin( mSelectionStart, mSelectionEnd );
S32 selection_right = llmax( mSelectionStart, mSelectionEnd );
LLRect selection_rect = mVisibleTextRect;
// Skip through the lines we aren't drawing.
LLRect content_display_rect = getVisibleDocumentRect();
@ -522,11 +529,17 @@ void LLTextBase::drawCursor()
void LLTextBase::drawText()
{
const S32 text_len = getLength();
if( text_len <= 0 )
S32 text_len = getLength();
if (text_len <= 0 && mLabel.empty())
{
return;
}
else if (useLabel())
{
text_len = mLabel.getWString().length();
}
S32 selection_left = -1;
S32 selection_right = -1;
// Draw selection even if we don't have keyboard focus for search/replace
@ -592,7 +605,8 @@ void LLTextBase::drawText()
// Find the start of the first word
U32 word_start = seg_start, word_end = -1;
while ( (word_start < wstrText.length()) && (!LLStringOps::isAlpha(wstrText[word_start])) )
U32 text_length = wstrText.length();
while ( (word_start < text_length) && (!LLStringOps::isAlpha(wstrText[word_start])) )
{
word_start++;
}
@ -614,11 +628,15 @@ void LLTextBase::drawText()
break;
}
// Don't process words shorter than 3 characters
std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start));
if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) )
if (word_start < text_length && word_end <= text_length && word_end > word_start)
{
mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end));
std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start));
// Don't process words shorter than 3 characters
if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) )
{
mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end));
}
}
// Find the start of the next word
@ -739,6 +757,8 @@ void LLTextBase::drawText()
S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::segment_vec_t* segments )
{
beforeValueChange();
S32 old_len = getLength(); // length() returns character length
S32 insert_len = wstr.length();
@ -770,7 +790,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
else
{
// create default editable segment to hold new text
LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
LLStyleConstSP sp(new LLStyle(getStyleParams()));
default_segment = new LLNormalTextSegment( sp, pos, pos + insert_len, *this);
}
@ -814,6 +834,8 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
{
beforeValueChange();
segment_set_t::iterator seg_iter = getSegIterContaining(pos);
while(seg_iter != mSegments.end())
{
@ -872,6 +894,8 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc)
{
beforeValueChange();
if (pos > (S32)getLength())
{
return 0;
@ -890,7 +914,7 @@ void LLTextBase::createDefaultSegment()
// ensures that there is always at least one segment
if (mSegments.empty())
{
LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
LLStyleConstSP sp(new LLStyle(getStyleParams()));
LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this);
mSegments.insert(default_segment);
default_segment->linkToDocument(this);
@ -980,6 +1004,13 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert)
BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
{
// handle triple click
if (!mTripleClickTimer.hasExpired())
{
selectAll();
return TRUE;
}
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
if (cur_segment && cur_segment->handleMouseDown(x, y, mask))
{
@ -1054,6 +1085,14 @@ BOOL LLTextBase::handleRightMouseUp(S32 x, S32 y, MASK mask)
BOOL LLTextBase::handleDoubleClick(S32 x, S32 y, MASK mask)
{
//Don't start triple click timer if user have clicked on scrollbar
mVisibleTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();
if (x >= mVisibleTextRect.mLeft && x <= mVisibleTextRect.mRight
&& y >= mVisibleTextRect.mBottom && y <= mVisibleTextRect.mTop)
{
mTripleClickTimer.setTimerExpirySec(TRIPLE_CLICK_INTERVAL);
}
LLTextSegmentPtr cur_segment = getSegmentAtLocalPos(x, y);
if (cur_segment && cur_segment->handleDoubleClick(x, y, mask))
{
@ -1338,6 +1377,25 @@ void LLTextBase::onSpellCheckSettingsChange()
mSpellCheckStart = mSpellCheckEnd = -1;
}
void LLTextBase::onFocusReceived()
{
LLUICtrl::onFocusReceived();
if (!getLength() && !mLabel.empty())
{
// delete label which is LLLabelTextSegment
clearSegments();
}
}
void LLTextBase::onFocusLost()
{
LLUICtrl::onFocusLost();
if (!getLength() && !mLabel.empty())
{
resetLabel();
}
}
// Sets the scrollbar from the cursor position
void LLTextBase::updateScrollFromCursor()
{
@ -1859,6 +1917,8 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.Execute", boost::bind(&LLUrlAction::executeSLURL, url));
registrar.add("Url.Teleport", boost::bind(&LLUrlAction::teleportToLocation, url));
registrar.add("Url.ShowProfile", boost::bind(&LLUrlAction::showProfile, url));
registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url));
registrar.add("Url.AddFriend", boost::bind(&LLUrlAction::addFriend, url));
registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
@ -1924,7 +1984,7 @@ static LLFastTimer::DeclareTimer FTM_PARSE_HTML("Parse HTML");
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LLStyle::Params style_params(input_params);
style_params.fillFrom(getDefaultStyleParams());
style_params.fillFrom(getStyleParams());
S32 part = (S32)LLTextParser::WHOLE;
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
@ -2009,6 +2069,44 @@ void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, c
appendTextImpl(new_text,input_params);
}
void LLTextBase::setLabel(const LLStringExplicit& label)
{
mLabel = label;
resetLabel();
}
BOOL LLTextBase::setLabelArg(const std::string& key, const LLStringExplicit& text )
{
mLabel.setArg(key, text);
return TRUE;
}
void LLTextBase::resetLabel()
{
if (useLabel())
{
clearSegments();
LLStyle* style = new LLStyle(getStyleParams());
style->setColor(mTentativeFgColor);
LLStyleConstSP sp(style);
LLTextSegmentPtr label = new LLLabelTextSegment(sp, 0, mLabel.getWString().length() + 1, *this);
insertSegment(label);
}
}
bool LLTextBase::useLabel()
{
return !getLength() && !mLabel.empty() && !hasFocus();
}
void LLTextBase::setFont(const LLFontGL* font)
{
mFont = font;
mStyleDirty = true;
}
void LLTextBase::needsReflow(S32 index)
{
lldebugs << "reflow on object " << (void*)this << " index = " << mReflowIndex << ", new index = " << index << llendl;
@ -2239,7 +2337,6 @@ const LLWString& LLTextBase::getWText() const
S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, BOOL round, bool hit_past_end_of_line) const
{
// Figure out which line we're nearest to.
LLRect visible_region = getVisibleDocumentRect();
LLRect doc_rect = mDocumentView->getRect();
S32 doc_y = local_y - doc_rect.mBottom;
@ -2399,7 +2496,7 @@ LLRect LLTextBase::getLocalRectFromDocIndex(S32 pos) const
{
// return default height rect in upper left
local_rect = content_window_rect;
local_rect.mBottom = local_rect.mTop - mDefaultFont->getLineHeight();
local_rect.mBottom = local_rect.mTop - mFont->getLineHeight();
return local_rect;
}
@ -2904,7 +3001,7 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
{
F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha;
const LLWString &text = mEditor.getWText();
const LLWString &text = getWText();
F32 right_x = rect.mLeft;
if (!mStyle->isVisible())
@ -3067,7 +3164,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
if (num_chars > 0)
{
height = mFontHeight;
const LLWString &text = mEditor.getWText();
const LLWString &text = getWText();
// if last character is a newline, then return true, forcing line break
width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
}
@ -3076,7 +3173,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const
{
const LLWString &text = mEditor.getWText();
const LLWString &text = getWText();
return mStyle->getFont()->charFromPixelOffset(text.c_str(), mStart + start_offset,
(F32)segment_local_x_coord,
F32_MAX,
@ -3086,7 +3183,7 @@ S32 LLNormalTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset,
S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const
{
const LLWString &text = mEditor.getWText();
const LLWString &text = getWText();
LLUIImagePtr image = mStyle->getImage();
if( image.notNull())
@ -3104,7 +3201,23 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
LLFontGL::EWordWrapStyle word_wrap_style = (line_offset == 0)
? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE
: LLFontGL::ONLY_WORD_BOUNDARIES;
S32 num_chars = mStyle->getFont()->maxDrawableChars(text.c_str() + segment_offset + mStart,
LLWString offsetString(text.c_str() + segment_offset + mStart);
if(getLength() < segment_offset + mStart)
{
llerrs << "getLength() < segment_offset + mStart\t getLength()\t" << getLength() << "\tsegment_offset:\t"
<< segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << "\tmax_chars\t" << max_chars << llendl;
}
if(offsetString.length() + 1 < max_chars)
{
llerrs << "offsetString.length() + 1 < max_chars\t max_chars:\t" << max_chars << "\toffsetString.length():\t" << offsetString.length()
<< getLength() << "\tsegment_offset:\t" << segment_offset << "\tmStart:\t" << mStart << "\tsegments\t" << mEditor.mSegments.size() << llendl;
}
S32 num_chars = mStyle->getFont()->maxDrawableChars(offsetString.c_str(),
(F32)num_pixels,
max_chars,
word_wrap_style);
@ -3122,7 +3235,7 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
S32 last_char_in_run = mStart + segment_offset + num_chars;
// check length first to avoid indexing off end of string
if (last_char_in_run < mEnd
&& (last_char_in_run >= mEditor.getLength() ))
&& (last_char_in_run >= getLength()))
{
num_chars++;
}
@ -3140,6 +3253,39 @@ void LLNormalTextSegment::dump() const
llendl;
}
/*virtual*/
const LLWString& LLNormalTextSegment::getWText() const
{
return mEditor.getWText();
}
/*virtual*/
const S32 LLNormalTextSegment::getLength() const
{
return mEditor.getLength();
}
LLLabelTextSegment::LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor )
: LLNormalTextSegment(style, start, end, editor)
{
}
LLLabelTextSegment::LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible)
: LLNormalTextSegment(color, start, end, editor, is_visible)
{
}
/*virtual*/
const LLWString& LLLabelTextSegment::getWText() const
{
return mEditor.getWlabel();
}
/*virtual*/
const S32 LLLabelTextSegment::getLength() const
{
return mEditor.getWlabel().length();
}
//
// LLOnHoverChangeableTextSegment
//
@ -3344,3 +3490,7 @@ F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 select
return 0.0;
}
void LLTextBase::setWordWrap(bool wrap)
{
mWordWrap = wrap;
}

View File

@ -41,6 +41,7 @@
#include <boost/signals2.hpp>
class LLScrollContainer;
class LLContextMenu;
class LLUrlMatch;
@ -106,7 +107,7 @@ class LLNormalTextSegment : public LLTextSegment
public:
LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
~LLNormalTextSegment();
virtual ~LLNormalTextSegment();
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
@ -131,6 +132,9 @@ public:
protected:
F32 drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRect rect);
virtual const LLWString& getWText() const;
virtual const S32 getLength() const;
protected:
class LLTextBase& mEditor;
LLStyleConstSP mStyle;
@ -140,6 +144,21 @@ protected:
boost::signals2::connection mImageLoadedConnection;
};
// This text segment is the same as LLNormalTextSegment, the only difference
// is that LLNormalTextSegment draws value of LLTextBase (LLTextBase::getWText()),
// but LLLabelTextSegment draws label of the LLTextBase (LLTextBase::mLabel)
class LLLabelTextSegment : public LLNormalTextSegment
{
public:
LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor );
LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
protected:
/*virtual*/ const LLWString& getWText() const;
/*virtual*/ const S32 getLength() const;
};
// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
{
@ -251,6 +270,7 @@ public:
Optional<LLUIColor> cursor_color,
text_color,
text_readonly_color,
text_tentative_color,
bg_readonly_color,
bg_writeable_color,
bg_focus_color,
@ -314,6 +334,9 @@ public:
/*virtual*/ BOOL canDeselect() const;
/*virtual*/ void deselect();
virtual void onFocusReceived();
virtual void onFocusLost();
// LLSpellCheckMenuHandler overrides
/*virtual*/ bool getSpellCheck() const;
@ -351,6 +374,21 @@ public:
const LLWString& getWText() const;
void appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params = LLStyle::Params());
void setLabel(const LLStringExplicit& label);
virtual BOOL setLabelArg(const std::string& key, const LLStringExplicit& text );
const std::string& getLabel() { return mLabel.getString(); }
const LLWString& getWlabel() { return mLabel.getWString();}
/**
* If label is set, draws text label (which is LLLabelTextSegment)
* that is visible when no user text provided
*/
void resetLabel();
void setFont(const LLFontGL* font);
// force reflow of text
void needsReflow(S32 index = 0);
@ -390,13 +428,16 @@ public:
bool scrolledToStart();
bool scrolledToEnd();
const LLFontGL* getDefaultFont() const { return mDefaultFont; }
const LLFontGL* getFont() const { return mFont; }
virtual void appendLineBreakSegment(const LLStyle::Params& style_params);
virtual void appendImageSegment(const LLStyle::Params& style_params);
virtual void appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);
boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb);
void setWordWrap(bool wrap);
LLScrollContainer* getScrollContainer() const { return mScroller; }
protected:
// helper structs
struct compare_bottom;
@ -464,7 +505,9 @@ protected:
LLTextBase(const Params &p);
virtual ~LLTextBase();
void initFromParams(const Params& p);
virtual void beforeValueChange();
virtual void onValueChange(S32 start, S32 end);
virtual bool useLabel();
// draw methods
void drawSelectionBackground(); // draws the black box behind the selected text
@ -490,7 +533,7 @@ protected:
void createDefaultSegment();
virtual void updateSegments();
void insertSegment(LLTextSegmentPtr segment_to_insert);
const LLStyle::Params& getDefaultStyleParams();
const LLStyle::Params& getStyleParams();
// manage lines
S32 getLineStart( S32 line ) const;
@ -535,15 +578,16 @@ protected:
LLRect mTextBoundingRect;
// default text style
LLStyle::Params mDefaultStyle;
LLStyle::Params mStyle;
bool mStyleDirty;
const LLFontGL* const mDefaultFont; // font that is used when none specified, can only be set by constructor
const LLFontGL::ShadowType mFontShadow; // shadow style, can only be set by constructor
const LLFontGL* mFont;
const LLFontGL::ShadowType mFontShadow;
// colors
LLUIColor mCursorColor;
LLUIColor mFgColor;
LLUIColor mReadOnlyFgColor;
LLUIColor mTentativeFgColor;
LLUIColor mWriteableBgColor;
LLUIColor mReadOnlyBgColor;
LLUIColor mFocusBgColor;
@ -558,7 +602,8 @@ protected:
// selection
S32 mSelectionStart;
S32 mSelectionEnd;
LLTimer mTripleClickTimer;
BOOL mIsSelecting; // Are we in the middle of a drag-select?
// spell checking
@ -587,12 +632,13 @@ protected:
bool mClip; // clip text to widget rect
bool mClipPartial; // false if we show lines that are partially inside bounding rect
bool mPlainText; // didn't use Image or Icon segments
bool mAutoIndent;
S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
// support widgets
LLContextMenu* mPopupMenu;
LLView* mDocumentView;
class LLScrollContainer* mScroller;
LLScrollContainer* mScroller;
// transient state
S32 mReflowIndex; // index at which to start reflow. S32_MAX indicates no reflow needed.
@ -602,6 +648,7 @@ protected:
// Fired when a URL link is clicked
commit_signal_t* mURLClickSignal;
LLUIString mLabel; // text label that is visible when no user text provided
};
#endif

View File

@ -237,6 +237,7 @@ LLTextEditor::Params::Params()
embedded_items("embedded_items", false),
ignore_tab("ignore_tab", true),
show_line_numbers("show_line_numbers", false),
auto_indent("auto_indent", true),
default_color("default_color"),
commit_on_focus_lost("commit_on_focus_lost", false),
show_context_menu("show_context_menu"),
@ -247,11 +248,13 @@ LLTextEditor::Params::Params()
LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
LLTextBase(p),
mAutoreplaceCallback(),
mBaseDocIsPristine(TRUE),
mPristineCmd( NULL ),
mLastCmd( NULL ),
mDefaultColor( p.default_color() ),
mShowLineNumbers ( p.show_line_numbers ),
mAutoIndent(p.auto_indent),
mCommitOnFocusLost( p.commit_on_focus_lost),
mAllowEmbeddedItems( p.embedded_items ),
mMouseDownX(0),
@ -260,7 +263,8 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mPrevalidateFunc(p.prevalidate_callback()),
mContextMenu(NULL),
mShowContextMenu(p.show_context_menu),
mEnableTooltipPaste(p.enable_tooltip_paste)
mEnableTooltipPaste(p.enable_tooltip_paste),
mPassDelete(FALSE)
{
mSourceID.generate();
@ -952,12 +956,18 @@ S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op
S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)
{
S32 end_pos = getEditableIndex(pos + length, true);
BOOL removedChar = FALSE;
segment_vec_t segments_to_remove;
// store text segments
getSegmentsInRange(segments_to_remove, pos, pos + length, false);
if(pos <= end_pos)
{
removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
}
return execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) );
return removedChar;
}
S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)
@ -1096,7 +1106,25 @@ void LLTextEditor::addChar(llwchar wc)
}
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
if (!mReadOnly && mAutoreplaceCallback != NULL)
{
// autoreplace the text, if necessary
S32 replacement_start;
S32 replacement_length;
LLWString replacement_string;
S32 new_cursor_pos = mCursorPos;
mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText());
if (replacement_length > 0 || !replacement_string.empty())
{
remove(replacement_start, replacement_length, true);
insert(replacement_start, replacement_string, false, LLTextSegmentPtr());
setCursorPos(new_cursor_pos);
}
}
}
void LLTextEditor::addLineBreakChar()
{
if( !getEnabled() )
@ -1621,7 +1649,10 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask)
{
deleteSelection(FALSE);
}
autoIndent(); // TODO: make this optional
if (mAutoIndent)
{
autoIndent();
}
}
else
{
@ -1792,7 +1823,7 @@ BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)
// virtual
BOOL LLTextEditor::canDoDelete() const
{
return !mReadOnly && ( hasSelection() || (mCursorPos < getLength()) );
return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) );
}
void LLTextEditor::doDelete()
@ -2061,7 +2092,7 @@ void LLTextEditor::drawPreeditMarker()
return;
}
const S32 line_height = mDefaultFont->getLineHeight();
const S32 line_height = mFont->getLineHeight();
S32 line_start = getLineStart(cur_line);
S32 line_y = mVisibleTextRect.mTop - line_height;
@ -2100,16 +2131,16 @@ void LLTextEditor::drawPreeditMarker()
S32 preedit_left = mVisibleTextRect.mLeft;
if (left > line_start)
{
preedit_left += mDefaultFont->getWidth(text, line_start, left - line_start);
preedit_left += mFont->getWidth(text, line_start, left - line_start);
}
S32 preedit_right = mVisibleTextRect.mLeft;
if (right < line_end)
{
preedit_right += mDefaultFont->getWidth(text, line_start, right - line_start);
preedit_right += mFont->getWidth(text, line_start, right - line_start);
}
else
{
preedit_right += mDefaultFont->getWidth(text, line_start, line_end - line_start);
preedit_right += mFont->getWidth(text, line_start, line_end - line_start);
}
if (mPreeditStandouts[i])
@ -2490,7 +2521,6 @@ void LLTextEditor::updateSegments()
mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this);
clearSegments();
segment_set_t::iterator insert_it = mSegments.begin();
for (segment_vec_t::iterator list_it = segment_list.begin(); list_it != segment_list.end(); ++list_it)
{
insertSegment(*list_it);
@ -2784,11 +2814,11 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
const LLWString textString(getWText());
const llwchar * const text = textString.c_str();
const S32 line_height = mDefaultFont->getLineHeight();
const S32 line_height = mFont->getLineHeight();
if (coord)
{
const S32 query_x = mVisibleTextRect.mLeft + mDefaultFont->getWidth(text, current_line_start, query - current_line_start);
const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start);
const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2;
S32 query_screen_x, query_screen_y;
localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y);
@ -2800,17 +2830,17 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect
S32 preedit_left = mVisibleTextRect.mLeft;
if (preedit_left_position > current_line_start)
{
preedit_left += mDefaultFont->getWidth(text, current_line_start, preedit_left_position - current_line_start);
preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start);
}
S32 preedit_right = mVisibleTextRect.mLeft;
if (preedit_right_position < current_line_end)
{
preedit_right += mDefaultFont->getWidth(text, current_line_start, preedit_right_position - current_line_start);
preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start);
}
else
{
preedit_right += mDefaultFont->getWidth(text, current_line_start, current_line_end - current_line_start);
preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start);
}
const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height;
@ -2887,7 +2917,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length)
S32 LLTextEditor::getPreeditFontSize() const
{
return llround((F32)mDefaultFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
return llround((F32)mFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
}
BOOL LLTextEditor::isDirty() const

View File

@ -65,7 +65,8 @@ public:
show_line_numbers,
commit_on_focus_lost,
show_context_menu,
enable_tooltip_paste;
enable_tooltip_paste,
auto_indent;
//colors
Optional<LLUIColor> default_color;
@ -157,6 +158,11 @@ public:
BOOL isPristine() const;
BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; }
// Autoreplace (formerly part of LLLineEditor)
typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t;
autoreplace_callback_t mAutoreplaceCallback;
void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
//
// Text manipulation
//
@ -203,6 +209,8 @@ public:
void setShowContextMenu(bool show) { mShowContextMenu = show; }
bool getShowContextMenu() const { return mShowContextMenu; }
void setPassDelete(BOOL b) { mPassDelete = b; }
protected:
void showContextMenu(S32 x, S32 y);
void drawPreeditMarker();
@ -215,8 +223,8 @@ protected:
S32 indentLine( S32 pos, S32 spaces );
void unindentLineBeforeCloseBrace();
virtual BOOL handleSpecialKey(const KEY key, const MASK mask);
BOOL handleNavigationKey(const KEY key, const MASK mask);
BOOL handleSpecialKey(const KEY key, const MASK mask);
BOOL handleSelectionKey(const KEY key, const MASK mask);
BOOL handleControlKey(const KEY key, const MASK mask);
@ -280,6 +288,7 @@ protected:
LLUIColor mDefaultColor;
BOOL mShowLineNumbers;
bool mAutoIndent;
/*virtual*/ void updateSegments();
void updateLinkSegments();
@ -325,6 +334,7 @@ private:
bool mShowContextMenu;
bool mParseOnTheFly;
bool mEnableTooltipPaste;
bool mPassDelete;
LLUUID mSourceID;

View File

@ -60,6 +60,8 @@ public:
// its visibility off.
bool toggleVisibility();
LLHandle<LLToggleableMenu> getHandle() { return getDerivedHandle<LLToggleableMenu>(); }
protected:
bool mClosedByButtonClick;
LLRect mButtonRect;

View File

@ -872,8 +872,15 @@ void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent)
void LLToolBar::createButtons()
{
std::set<LLUUID> set_flashing;
BOOST_FOREACH(LLToolBarButton* button, mButtons)
{
if (button->getFlashTimer() && button->getFlashTimer()->isFlashingInProgress())
{
set_flashing.insert(button->getCommandId().uuid());
}
if (mButtonRemoveSignal)
{
(*mButtonRemoveSignal)(button);
@ -896,6 +903,11 @@ void LLToolBar::createButtons()
{
(*mButtonAddSignal)(button);
}
if (set_flashing.find(button->getCommandId().uuid()) != set_flashing.end())
{
button->setFlashing(true);
}
}
mNeedsLayout = true;
}
@ -920,6 +932,7 @@ LLToolBarButton* LLToolBar::createButton(const LLCommandId& id)
button_p.label = LLTrans::getString(commandp->labelRef());
button_p.tool_tip = LLTrans::getString(commandp->tooltipRef());
button_p.image_overlay = LLUI::getUIImage(commandp->icon());
button_p.button_flash_enable = commandp->isFlashingAllowed();
button_p.overwriteFrom(mButtonParams[mButtonType]);
LLToolBarButton* button = LLUICtrlFactory::create<LLToolBarButton>(button_p);
@ -1046,10 +1059,9 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
// Convert drag position into insert position and rank
if (!isReadOnly() && handled && !drop)
{
LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
LLAssetType::EType type = inv_item->getType();
if (type == LLAssetType::AT_WIDGET)
if (cargo_type == DAD_WIDGET)
{
LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
LLCommandId dragged_command(inv_item->getUUID());
int orig_rank = getRankFromPosition(dragged_command);
mDragRank = getRankFromPosition(x, y);

View File

@ -288,7 +288,7 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
mTextBox->setText(p.message());
}
S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth());
S32 text_width = llmin(p.max_width(), mTextBox->getTextPixelWidth() + 1);
S32 text_height = mTextBox->getTextPixelHeight();
mTextBox->reshape(text_width, text_height);
if (mInfoButton)

View File

@ -77,6 +77,7 @@ std::list<std::string> gUntranslated;
/*static*/ LLUI::settings_map_t LLUI::sSettingGroups;
/*static*/ LLImageProviderInterface* LLUI::sImageProvider = NULL;
/*static*/ LLUIAudioCallback LLUI::sAudioCallback = NULL;
/*static*/ LLUIAudioCallback LLUI::sDeferredAudioCallback = NULL;
/*static*/ LLVector2 LLUI::sGLScaleFactor(1.f, 1.f);
/*static*/ LLWindow* LLUI::sWindow = NULL;
/*static*/ LLView* LLUI::sRootView = NULL;
@ -101,16 +102,18 @@ static LLDefaultChildRegistry::Register<LLToolBar> register_toolbar("toolbar");
//
// Functions
//
void make_ui_sound(const char* namep)
LLUUID find_ui_sound(const char * namep)
{
std::string name = ll_safe_string(namep);
LLUUID uuid = LLUUID(NULL);
if (!LLUI::sSettingGroups["config"]->controlExists(name))
{
llwarns << "tried to make UI sound for unknown sound name: " << name << llendl;
}
else
{
LLUUID uuid(LLUI::sSettingGroups["config"]->getString(name));
uuid = LLUUID(LLUI::sSettingGroups["config"]->getString(name));
if (uuid.isNull())
{
if (LLUI::sSettingGroups["config"]->getString(name) == LLUUID::null.asString())
@ -124,7 +127,6 @@ void make_ui_sound(const char* namep)
{
llwarns << "UI sound named: " << name << " does not translate to a valid uuid" << llendl;
}
}
else if (LLUI::sAudioCallback != NULL)
{
@ -132,9 +134,28 @@ void make_ui_sound(const char* namep)
{
llinfos << "UI sound name: " << name << llendl;
}
LLUI::sAudioCallback(uuid);
}
}
return uuid;
}
void make_ui_sound(const char* namep)
{
LLUUID soundUUID = find_ui_sound(namep);
if(soundUUID.notNull())
{
LLUI::sAudioCallback(soundUUID);
}
}
void make_ui_sound_deferred(const char* namep)
{
LLUUID soundUUID = find_ui_sound(namep);
if(soundUUID.notNull())
{
LLUI::sDeferredAudioCallback(soundUUID);
}
}
BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom)
@ -978,31 +999,31 @@ void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha)
{
if (!LLGLSLShader::sNoFixedFunction)
{
// Initialize the first time this is called.
const S32 PIXELS = 32;
static GLubyte checkerboard[PIXELS * PIXELS];
static BOOL first = TRUE;
if( first )
// Initialize the first time this is called.
const S32 PIXELS = 32;
static GLubyte checkerboard[PIXELS * PIXELS];
static BOOL first = TRUE;
if( first )
{
for( S32 i = 0; i < PIXELS; i++ )
{
for( S32 i = 0; i < PIXELS; i++ )
for( S32 j = 0; j < PIXELS; j++ )
{
for( S32 j = 0; j < PIXELS; j++ )
{
checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
}
checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF;
}
first = FALSE;
}
first = FALSE;
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// ...white squares
gGL.color4f( 1.f, 1.f, 1.f, alpha );
gl_rect_2d(rect);
// ...white squares
gGL.color4f( 1.f, 1.f, 1.f, alpha );
gl_rect_2d(rect);
// ...gray squares
gGL.color4f( .7f, .7f, .7f, alpha );
gGL.flush();
// ...gray squares
gGL.color4f( .7f, .7f, .7f, alpha );
gGL.flush();
glPolygonStipple( checkerboard );
@ -1478,148 +1499,137 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left,
gGL.popUIMatrix();
}
void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width,
const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec,
const U32 edges)
void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect,
const LLVector3& width_vec, const LLVector3& height_vec)
{
LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero;
LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero;
LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero;
LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero;
gGL.begin(LLRender::QUADS);
{
// draw bottom left
gGL.texCoord2f(0.f, 0.f);
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom);
gGL.vertex3f(0.f, 0.f, 0.f);
gGL.texCoord2f(border_scale.mV[VX], 0.f);
gGL.vertex3fv(left_border_width.mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(0.f, border_scale.mV[VY]);
gGL.vertex3fv(bottom_border_height.mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
// draw bottom middle
gGL.texCoord2f(border_scale.mV[VX], 0.f);
gGL.vertex3fv(left_border_width.mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
gGL.vertex3fv((width_vec - right_border_width).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
// draw bottom right
gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f);
gGL.vertex3fv((width_vec - right_border_width).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV);
gGL.texCoord2f(1.f, 0.f);
gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom);
gGL.vertex3fv(width_vec.mV);
gGL.texCoord2f(1.f, border_scale.mV[VY]);
gGL.vertex3fv((width_vec + bottom_border_height).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
// draw left
gGL.texCoord2f(0.f, border_scale.mV[VY]);
gGL.vertex3fv(bottom_border_height.mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
gGL.vertex3fv((height_vec - top_border_height).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
// draw middle
gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
// draw right
gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(1.f, border_scale.mV[VY]);
gGL.vertex3fv((width_vec + bottom_border_height).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom);
gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV);
gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
// draw top left
gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]);
gGL.vertex3fv((height_vec - top_border_height).mV);
gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], 1.f);
gGL.vertex3fv((left_border_width + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
gGL.texCoord2f(0.f, 1.f);
gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((height_vec).mV);
// draw top middle
gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
gGL.texCoord2f(border_scale.mV[VX], 1.f);
gGL.vertex3fv((left_border_width + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV);
// draw top right
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV);
gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]);
gGL.vertex3fv((width_vec + height_vec - top_border_height).mV);
gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop);
gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV);
gGL.texCoord2f(1.f, 1.f);
gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((width_vec + height_vec).mV);
gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f);
gGL.vertex3fv((width_vec - right_border_width + height_vec).mV);
gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop);
gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV);
}
gGL.end();
}
void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec)
{
gl_segmented_rect_3d_tex(border_scale, border_width, border_height, width_vec, height_vec, ROUNDED_RECT_TOP);
}
void LLUI::initClass(const settings_map_t& settings,
LLImageProviderInterface* image_provider,
LLUIAudioCallback audio_callback,
LLUIAudioCallback deferred_audio_callback,
const LLVector2* scale_factor,
const std::string& language)
{
@ -1634,6 +1644,7 @@ void LLUI::initClass(const settings_map_t& settings,
sImageProvider = image_provider;
sAudioCallback = audio_callback;
sDeferredAudioCallback = deferred_audio_callback;
sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor;
sWindow = NULL; // set later in startup
LLFontGL::sShadowColor = LLUIColorTable::instance().getColor("ColorDropShadow");
@ -2067,7 +2078,7 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path)
namespace LLInitParam
{
ParamValue<LLUIColor, TypeValues<LLUIColor> >::ParamValue(const LLUIColor& color)
ParamValue<LLUIColor>::ParamValue(const LLUIColor& color)
: super_t(color),
red("red"),
green("green"),
@ -2078,7 +2089,7 @@ namespace LLInitParam
updateBlockFromValue(false);
}
void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateValueFromBlock()
void ParamValue<LLUIColor>::updateValueFromBlock()
{
if (control.isProvided() && !control().empty())
{
@ -2090,7 +2101,7 @@ namespace LLInitParam
}
}
void ParamValue<LLUIColor, TypeValues<LLUIColor> >::updateBlockFromValue(bool make_block_authoritative)
void ParamValue<LLUIColor>::updateBlockFromValue(bool make_block_authoritative)
{
LLColor4 color = getValue();
red.set(color.mV[VRED], make_block_authoritative);
@ -2106,7 +2117,7 @@ namespace LLInitParam
&& !(b->getFontDesc() < a->getFontDesc());
}
ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::ParamValue(const LLFontGL* fontp)
ParamValue<const LLFontGL*>::ParamValue(const LLFontGL* fontp)
: super_t(fontp),
name("name"),
size("size"),
@ -2120,7 +2131,7 @@ namespace LLInitParam
updateBlockFromValue(false);
}
void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateValueFromBlock()
void ParamValue<const LLFontGL*>::updateValueFromBlock()
{
const LLFontGL* res_fontp = LLFontGL::getFontByName(name);
if (res_fontp)
@ -2143,7 +2154,7 @@ namespace LLInitParam
}
}
void ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >::updateBlockFromValue(bool make_block_authoritative)
void ParamValue<const LLFontGL*>::updateBlockFromValue(bool make_block_authoritative)
{
if (getValue())
{
@ -2153,7 +2164,7 @@ namespace LLInitParam
}
}
ParamValue<LLRect, TypeValues<LLRect> >::ParamValue(const LLRect& rect)
ParamValue<LLRect>::ParamValue(const LLRect& rect)
: super_t(rect),
left("left"),
top("top"),
@ -2165,7 +2176,7 @@ namespace LLInitParam
updateBlockFromValue(false);
}
void ParamValue<LLRect, TypeValues<LLRect> >::updateValueFromBlock()
void ParamValue<LLRect>::updateValueFromBlock()
{
LLRect rect;
@ -2229,7 +2240,7 @@ namespace LLInitParam
updateValue(rect);
}
void ParamValue<LLRect, TypeValues<LLRect> >::updateBlockFromValue(bool make_block_authoritative)
void ParamValue<LLRect>::updateBlockFromValue(bool make_block_authoritative)
{
// because of the ambiguity in specifying a rect by position and/or dimensions
// we use the lowest priority pairing so that any valid pairing in xui
@ -2246,7 +2257,7 @@ namespace LLInitParam
height.set(value.getHeight(), make_block_authoritative);
}
ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::ParamValue(const LLCoordGL& coord)
ParamValue<LLCoordGL>::ParamValue(const LLCoordGL& coord)
: super_t(coord),
x("x"),
y("y")
@ -2254,12 +2265,12 @@ namespace LLInitParam
updateBlockFromValue(false);
}
void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateValueFromBlock()
void ParamValue<LLCoordGL>::updateValueFromBlock()
{
updateValue(LLCoordGL(x, y));
}
void ParamValue<LLCoordGL, TypeValues<LLCoordGL> >::updateBlockFromValue(bool make_block_authoritative)
void ParamValue<LLCoordGL>::updateBlockFromValue(bool make_block_authoritative)
{
x.set(getValue().mX, make_block_authoritative);
y.set(getValue().mY, make_block_authoritative);

View File

@ -62,6 +62,7 @@ class LLHelp;
// UI colors
extern const LLColor4 UI_VERTEX_COLOR;
void make_ui_sound(const char* name);
void make_ui_sound_deferred(const char * name);
BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom);
void gl_state_for_2d(S32 width, S32 height);
@ -127,8 +128,7 @@ typedef enum e_rounded_edge
void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const U32 edges = ROUNDED_RECT_ALL);
void gl_segmented_rect_2d_fragment_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL);
void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec, U32 edges = ROUNDED_RECT_ALL);
void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec);
void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, const LLVector3& width_vec, const LLVector3& height_vec);
inline void gl_rect_2d( const LLRect& rect, BOOL filled )
{
@ -275,6 +275,7 @@ public:
static void initClass(const settings_map_t& settings,
LLImageProviderInterface* image_provider,
LLUIAudioCallback audio_callback = NULL,
LLUIAudioCallback deferred_audio_callback = NULL,
const LLVector2 *scale_factor = NULL,
const std::string& language = LLStringUtil::null);
static void cleanupClass();
@ -360,6 +361,7 @@ public:
//
static settings_map_t sSettingGroups;
static LLUIAudioCallback sAudioCallback;
static LLUIAudioCallback sDeferredAudioCallback;
static LLVector2 sGLScaleFactor;
static LLWindow* sWindow;
static LLView* sRootView;
@ -507,7 +509,7 @@ public:
namespace LLInitParam
{
template<>
class ParamValue<LLRect, TypeValues<LLRect> >
class ParamValue<LLRect>
: public CustomParamValue<LLRect>
{
typedef CustomParamValue<LLRect> super_t;
@ -526,7 +528,7 @@ namespace LLInitParam
};
template<>
class ParamValue<LLUIColor, TypeValues<LLUIColor> >
class ParamValue<LLUIColor>
: public CustomParamValue<LLUIColor>
{
typedef CustomParamValue<LLUIColor> super_t;
@ -544,7 +546,7 @@ namespace LLInitParam
};
template<>
class ParamValue<const LLFontGL*, TypeValues<const LLFontGL*> >
class ParamValue<const LLFontGL*>
: public CustomParamValue<const LLFontGL* >
{
typedef CustomParamValue<const LLFontGL*> super_t;
@ -584,7 +586,7 @@ namespace LLInitParam
template<>
class ParamValue<LLCoordGL, TypeValues<LLCoordGL> >
class ParamValue<LLCoordGL>
: public CustomParamValue<LLCoordGL>
{
typedef CustomParamValue<LLCoordGL> super_t;

View File

@ -247,13 +247,13 @@ const LLInitParam::BaseBlock& get_empty_param_block()
// adds a widget and its param block to various registries
//static
void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& tag)
void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const std::type_info* param_block_type, const std::string& name)
{
// associate parameter block type with template .xml file
std::string* existing_tag = LLWidgetNameRegistry::instance().getValue(param_block_type);
if (existing_tag != NULL)
std::string* existing_name = LLWidgetNameRegistry::instance().getValue(param_block_type);
if (existing_name != NULL)
{
if(*existing_tag != tag)
if(*existing_name != name)
{
std::cerr << "Duplicate entry for T::Params, try creating empty param block in derived classes that inherit T::Params" << std::endl;
// forcing crash here
@ -262,19 +262,15 @@ void LLUICtrlFactory::registerWidget(const std::type_info* widget_type, const st
}
else
{
// widget already registered
// widget already registered this name
return;
}
}
LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, tag);
LLWidgetNameRegistry::instance().defaultRegistrar().add(param_block_type, name);
//FIXME: comment this in when working on schema generation
//LLWidgetTypeRegistry::instance().defaultRegistrar().add(tag, widget_type);
//LLDefaultParamBlockRegistry::instance().defaultRegistrar().add(widget_type, &get_empty_param_block<T>);
}
//static
const std::string* LLUICtrlFactory::getWidgetTag(const std::type_info* widget_type)
{
return LLWidgetNameRegistry::instance().getValue(widget_type);
}

View File

@ -98,7 +98,7 @@ private:
ParamDefaults()
{
// look up template file for this param block...
const std::string* param_block_tag = getWidgetTag(&typeid(PARAM_BLOCK));
const std::string* param_block_tag = LLWidgetNameRegistry::instance().getValue(&typeid(PARAM_BLOCK));
if (param_block_tag)
{ // ...and if it exists, back fill values using the most specific template first
PARAM_BLOCK params;
@ -132,7 +132,6 @@ public:
template<typename T>
static const typename T::Params& getDefaultParams()
{
//#pragma message("Generating ParamDefaults")
return ParamDefaults<typename T::Params, 0>::instance().get();
}
@ -285,8 +284,6 @@ private:
}
static const std::string* getWidgetTag(const std::type_info* widget_type);
// this exists to get around dependency on llview
static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);

View File

@ -112,6 +112,50 @@ void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4&
drawSolid(border_rect, color);
}
void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis,
const LLRect& rect, const LLColor4& color)
{
F32 border_scale = 1.f;
F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight();
F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth();
if (rect.getHeight() < border_height || rect.getWidth() < border_width)
{
if(border_height - rect.getHeight() > border_width - rect.getWidth())
{
border_scale = (F32)rect.getHeight() / border_height;
}
else
{
border_scale = (F32)rect.getWidth() / border_width;
}
}
LLUI::pushMatrix();
{
LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis);
LLUI::translate(rect_origin.mV[VX],
rect_origin.mV[VY],
rect_origin.mV[VZ]);
gGL.getTexUnit(0)->bind(getImage());
gGL.color4fv(color.mV);
LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(),
mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(),
mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(),
mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight());
gl_segmented_rect_3d_tex(mClipRegion,
center_uv_rect,
LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(),
(rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(),
(rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(),
(border_height * border_scale * 0.5f) / (F32)rect.getHeight()),
rect.getWidth() * x_axis,
rect.getHeight() * y_axis);
} LLUI::popMatrix();
}
S32 LLUIImage::getWidth() const
{
// return clipped dimensions of actual image area
@ -155,7 +199,7 @@ void LLUIImage::onImageLoaded()
namespace LLInitParam
{
void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock()
void ParamValue<LLUIImage*>::updateValueFromBlock()
{
// The keyword "none" is specifically requesting a null image
// do not default to current value. Used to overwrite template images.
@ -172,7 +216,7 @@ namespace LLInitParam
}
}
void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue(bool make_block_authoritative)
void ParamValue<LLUIImage*>::updateBlockFromValue(bool make_block_authoritative)
{
if (getValue() == NULL)
{

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