Pull and merge from ssh://stinson@hg.lindenlab.com/richard/viewer-chui/.
commit
c1aa0cc4fc
|
|
@ -181,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)
|
||||
{
|
||||
|
|
@ -321,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;
|
||||
|
|
|
|||
|
|
@ -572,7 +572,7 @@ namespace LLInitParam
|
|||
};
|
||||
|
||||
typedef bool(*merge_func_t)(Param&, const Param&, bool);
|
||||
typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool);
|
||||
typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);
|
||||
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
|
||||
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
|
||||
typedef bool(*validation_func_t)(const Param*);
|
||||
|
|
@ -633,38 +633,38 @@ namespace LLInitParam
|
|||
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
|
||||
};
|
||||
|
||||
//TODO: implement in terms of owned_ptr
|
||||
template<typename T>
|
||||
//TODO: implement in terms of owned_ptr
|
||||
template<typename T>
|
||||
class LazyValue
|
||||
{
|
||||
{
|
||||
public:
|
||||
LazyValue()
|
||||
: mPtr(NULL)
|
||||
{}
|
||||
: mPtr(NULL)
|
||||
{}
|
||||
|
||||
~LazyValue()
|
||||
{
|
||||
delete mPtr;
|
||||
}
|
||||
{
|
||||
delete mPtr;
|
||||
}
|
||||
|
||||
LazyValue(const T& value)
|
||||
{
|
||||
{
|
||||
mPtr = new T(value);
|
||||
}
|
||||
|
||||
LazyValue(const LazyValue& other)
|
||||
: mPtr(NULL)
|
||||
{
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
}
|
||||
|
||||
LazyValue& operator = (const LazyValue& other)
|
||||
{
|
||||
if (!other.mPtr)
|
||||
{
|
||||
{
|
||||
delete mPtr;
|
||||
mPtr = NULL;
|
||||
}
|
||||
mPtr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mPtr)
|
||||
|
|
@ -675,9 +675,9 @@ namespace LLInitParam
|
|||
{
|
||||
*mPtr = *(other.mPtr);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const LazyValue& other) const
|
||||
{
|
||||
|
|
@ -685,13 +685,13 @@ namespace LLInitParam
|
|||
return *mPtr == *other.mPtr;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return mPtr == NULL;
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return mPtr == NULL;
|
||||
}
|
||||
|
||||
void set(const T& other)
|
||||
{
|
||||
void set(const T& other)
|
||||
{
|
||||
if (!mPtr)
|
||||
{
|
||||
mPtr = new T(other);
|
||||
|
|
@ -702,36 +702,36 @@ namespace LLInitParam
|
|||
}
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
const T& get() const
|
||||
{
|
||||
return *ensureInstance();
|
||||
}
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
T& get()
|
||||
{
|
||||
return *ensureInstance();
|
||||
}
|
||||
|
||||
operator const T&() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// lazily allocate an instance of T
|
||||
T* ensureInstance() const
|
||||
private:
|
||||
// lazily allocate an instance of T
|
||||
T* ensureInstance() const
|
||||
{
|
||||
if (mPtr == NULL)
|
||||
{
|
||||
if (mPtr == NULL)
|
||||
{
|
||||
mPtr = new T();
|
||||
}
|
||||
return mPtr;
|
||||
}
|
||||
mPtr = new T();
|
||||
}
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
mutable T* mPtr;
|
||||
};
|
||||
mutable T* mPtr;
|
||||
};
|
||||
|
||||
// root class of all parameter blocks
|
||||
|
||||
|
|
@ -838,7 +838,7 @@ namespace LLInitParam
|
|||
// Blocks can override this to do custom tracking of changes
|
||||
virtual void paramChanged(const Param& changed_param, bool user_provided) {}
|
||||
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
|
||||
|
||||
|
|
@ -913,7 +913,7 @@ namespace LLInitParam
|
|||
}
|
||||
|
||||
U32 getEnclosingBlockOffset() const
|
||||
{
|
||||
{
|
||||
return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;
|
||||
}
|
||||
|
||||
|
|
@ -970,7 +970,7 @@ namespace LLInitParam
|
|||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
// no further names in stack, attempt to parse value now
|
||||
|
|
@ -1128,7 +1128,7 @@ namespace LLInitParam
|
|||
}
|
||||
}
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
// attempt to parse block...
|
||||
|
|
@ -1287,7 +1287,7 @@ namespace LLInitParam
|
|||
}
|
||||
};
|
||||
|
||||
// container of non-block parameters
|
||||
// list of non-block parameters
|
||||
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
|
||||
: public Param
|
||||
|
|
@ -1316,7 +1316,7 @@ namespace LLInitParam
|
|||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
Parser::name_stack_range_t new_name_stack_range(name_stack_range);
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
|
|
@ -1499,7 +1499,7 @@ namespace LLInitParam
|
|||
}
|
||||
};
|
||||
|
||||
// container of block parameters
|
||||
// list of block parameters
|
||||
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
|
||||
: public Param
|
||||
|
|
@ -1528,30 +1528,35 @@ namespace LLInitParam
|
|||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
Parser::name_stack_range_t new_name_stack_range(name_stack_range);
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
bool new_value = false;
|
||||
bool new_array_value = false;
|
||||
|
||||
// pop first element if empty string
|
||||
if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
|
||||
{
|
||||
new_value |= new_name_stack_range.first->second;
|
||||
new_array_value = new_name_stack_range.first->second;
|
||||
++new_name_stack_range.first;
|
||||
}
|
||||
if (new_name || typed_param.mValues.empty())
|
||||
|
||||
if (new_name || new_array_value || typed_param.mValues.empty())
|
||||
{
|
||||
new_value = true;
|
||||
typed_param.mValues.push_back(value_t());
|
||||
}
|
||||
|
||||
param_value_t& value = typed_param.mValues.back();
|
||||
|
||||
// attempt to parse block...
|
||||
if(value.deserializeBlock(parser, new_name_stack_range, new_name))
|
||||
{
|
||||
typed_param.setProvided();
|
||||
if (new_array_value)
|
||||
{
|
||||
name_stack_range.first->second = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(named_value_t::valueNamesExist())
|
||||
|
|
@ -1565,6 +1570,10 @@ namespace LLInitParam
|
|||
{
|
||||
typed_param.mValues.back().setValueName(name);
|
||||
typed_param.setProvided();
|
||||
if (new_array_value)
|
||||
{
|
||||
name_stack_range.first->second = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2039,7 +2048,7 @@ namespace LLInitParam
|
|||
}
|
||||
}
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
if (name_stack_range.first == name_stack_range.second)
|
||||
{
|
||||
|
|
@ -2062,7 +2071,7 @@ namespace LLInitParam
|
|||
// dummy writer interfaces
|
||||
template<typename T>
|
||||
Deprecated& operator =(const T& val)
|
||||
{
|
||||
{
|
||||
// do nothing
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -2178,14 +2187,14 @@ namespace LLInitParam
|
|||
return mValue.getValue();
|
||||
}
|
||||
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
if (new_name)
|
||||
{
|
||||
resetToDefault();
|
||||
}
|
||||
return mValue.deserializeBlock(p, name_stack_range, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
|
||||
{
|
||||
|
|
@ -2271,12 +2280,12 @@ namespace LLInitParam
|
|||
return mValue.getValue();
|
||||
}
|
||||
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
if (new_name)
|
||||
{
|
||||
mCurParam = getBlockDescriptor().mAllParams.begin();
|
||||
}
|
||||
}
|
||||
if (name_stack_range.first == name_stack_range.second
|
||||
&& mCurParam != getBlockDescriptor().mAllParams.end())
|
||||
{
|
||||
|
|
@ -2288,7 +2297,7 @@ namespace LLInitParam
|
|||
if (deserialize_func
|
||||
&& paramp
|
||||
&& deserialize_func(*paramp, p, name_stack_range, new_name))
|
||||
{
|
||||
{
|
||||
++mCurParam;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2300,7 +2309,7 @@ namespace LLInitParam
|
|||
else
|
||||
{
|
||||
return mValue.deserializeBlock(p, name_stack_range, new_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
|
||||
|
|
@ -2353,7 +2362,7 @@ namespace LLInitParam
|
|||
: T(),
|
||||
mValidated(false)
|
||||
{}
|
||||
|
||||
|
||||
ParamValue(const default_value_t& value)
|
||||
: T(value.getValue()),
|
||||
mValidated(false)
|
||||
|
|
@ -2401,7 +2410,7 @@ namespace LLInitParam
|
|||
return mValue.get().getValue();
|
||||
}
|
||||
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name)
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
return mValue.get().deserializeBlock(p, name_stack_range, new_name);
|
||||
}
|
||||
|
|
@ -2425,7 +2434,7 @@ namespace LLInitParam
|
|||
{
|
||||
return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite);
|
||||
}
|
||||
|
||||
|
||||
bool validateBlock(bool emit_errors = true) const
|
||||
{
|
||||
return mValue.empty() || mValue.get().validateBlock(emit_errors);
|
||||
|
|
@ -2510,7 +2519,7 @@ namespace LLInitParam
|
|||
LLSD& getValue() { return mValue; }
|
||||
|
||||
// block param interface
|
||||
LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);
|
||||
LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
|
||||
{
|
||||
|
|
@ -2540,10 +2549,10 @@ namespace LLInitParam
|
|||
} EValueAge;
|
||||
|
||||
typedef ParamValue<T> derived_t;
|
||||
typedef CustomParamValue<T> self_t;
|
||||
typedef Block<derived_t> block_t;
|
||||
typedef CustomParamValue<T> self_t;
|
||||
typedef Block<derived_t> block_t;
|
||||
typedef T default_value_t;
|
||||
typedef T value_t;
|
||||
typedef T value_t;
|
||||
typedef void baseblock_base_class_t;
|
||||
|
||||
|
||||
|
|
@ -2553,7 +2562,7 @@ namespace LLInitParam
|
|||
mValidated(false)
|
||||
{}
|
||||
|
||||
bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name)
|
||||
bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
derived_t& typed_param = static_cast<derived_t&>(*this);
|
||||
// try to parse direct value T
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ namespace LLInitParam
|
|||
{
|
||||
// LLSD specialization
|
||||
// block param interface
|
||||
bool ParamValue<LLSD, NOT_BLOCK>::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))
|
||||
|
|
|
|||
|
|
@ -131,6 +131,9 @@ set(viewer_SOURCE_FILES
|
|||
llcommandlineparser.cpp
|
||||
llcompilequeue.cpp
|
||||
llconfirmationmanager.cpp
|
||||
llconversationlog.cpp
|
||||
llconversationloglist.cpp
|
||||
llconversationloglistitem.cpp
|
||||
llcurrencyuimanager.cpp
|
||||
llcylinder.cpp
|
||||
lldateutil.cpp
|
||||
|
|
@ -187,6 +190,8 @@ set(viewer_SOURCE_FILES
|
|||
llfloaterbuyland.cpp
|
||||
llfloatercamera.cpp
|
||||
llfloatercolorpicker.cpp
|
||||
llfloaterconversationlog.cpp
|
||||
llfloaterconversationpreview.cpp
|
||||
llfloaterdeleteenvpreset.cpp
|
||||
llfloaterdestinations.cpp
|
||||
llfloaterdisplayname.cpp
|
||||
|
|
@ -692,6 +697,9 @@ set(viewer_HEADER_FILES
|
|||
llcommandlineparser.h
|
||||
llcompilequeue.h
|
||||
llconfirmationmanager.h
|
||||
llconversationlog.h
|
||||
llconversationloglist.h
|
||||
llconversationloglistitem.h
|
||||
llcurrencyuimanager.h
|
||||
llcylinder.h
|
||||
lldateutil.h
|
||||
|
|
@ -748,6 +756,8 @@ set(viewer_HEADER_FILES
|
|||
llfloaterbuyland.h
|
||||
llfloatercamera.h
|
||||
llfloatercolorpicker.h
|
||||
llfloaterconversationlog.h
|
||||
llfloaterconversationpreview.h
|
||||
llfloaterdeleteenvpreset.h
|
||||
llfloaterdestinations.h
|
||||
llfloaterdisplayname.h
|
||||
|
|
|
|||
|
|
@ -10052,6 +10052,28 @@
|
|||
<key>Value</key>
|
||||
<integer>2</integer>
|
||||
</map>
|
||||
<key>CallLogSortOrder</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Specifies sort order for Call Log (0 = by name, 1 = by date)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>2</integer>
|
||||
</map>
|
||||
<key>SortFriendsFirst</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Specifies whether friends will be sorted first in Call Log</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>ShowPGSearchAll</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
#include "llares.h"
|
||||
#include "llcurl.h"
|
||||
#include "llcalc.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "lltexturestats.h"
|
||||
#include "lltexturestats.h"
|
||||
#include "llviewerwindow.h"
|
||||
|
|
@ -1824,6 +1825,9 @@ bool LLAppViewer::cleanup()
|
|||
// save mute list. gMuteList used to also be deleted here too.
|
||||
LLMuteList::getInstance()->cache(gAgent.getID());
|
||||
|
||||
//save call log list
|
||||
LLConversationLog::instance().cache();
|
||||
|
||||
if (mPurgeOnExit)
|
||||
{
|
||||
llinfos << "Purging all cache files on exit" << llendflush;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,336 @@
|
|||
/**
|
||||
* @file llconversationlog.h
|
||||
*
|
||||
* $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 "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
struct Conversation_params
|
||||
{
|
||||
Conversation_params(time_t time)
|
||||
: mTime(time),
|
||||
mTimestamp(LLConversation::createTimestamp(time))
|
||||
{}
|
||||
|
||||
time_t mTime;
|
||||
std::string mTimestamp;
|
||||
SessionType mConversationType;
|
||||
std::string mConversationName;
|
||||
std::string mHistoryFileName;
|
||||
LLUUID mSessionID;
|
||||
LLUUID mParticipantID;
|
||||
bool mIsVoice;
|
||||
bool mHasOfflineIMs;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* LLConversation implementation */
|
||||
/************************************************************************/
|
||||
|
||||
LLConversation::LLConversation(const Conversation_params& params)
|
||||
: mTime(params.mTime),
|
||||
mTimestamp(params.mTimestamp),
|
||||
mConversationType(params.mConversationType),
|
||||
mConversationName(params.mConversationName),
|
||||
mHistoryFileName(params.mHistoryFileName),
|
||||
mSessionID(params.mSessionID),
|
||||
mParticipantID(params.mParticipantID),
|
||||
mIsVoice(params.mIsVoice),
|
||||
mHasOfflineIMs(params.mHasOfflineIMs)
|
||||
{
|
||||
setListenIMFloaterOpened();
|
||||
}
|
||||
|
||||
LLConversation::LLConversation(const LLIMModel::LLIMSession& session)
|
||||
: mTime(time_corrected()),
|
||||
mTimestamp(createTimestamp(mTime)),
|
||||
mConversationType(session.mSessionType),
|
||||
mConversationName(session.mName),
|
||||
mHistoryFileName(session.mHistoryFileName),
|
||||
mSessionID(session.mSessionID),
|
||||
mParticipantID(session.mOtherParticipantID),
|
||||
mIsVoice(session.mStartedAsIMCall),
|
||||
mHasOfflineIMs(session.mHasOfflineMessage)
|
||||
{
|
||||
setListenIMFloaterOpened();
|
||||
}
|
||||
|
||||
LLConversation::LLConversation(const LLConversation& conversation)
|
||||
{
|
||||
mTime = conversation.getTime();
|
||||
mTimestamp = conversation.getTimestamp();
|
||||
mConversationType = conversation.getConversationType();
|
||||
mConversationName = conversation.getConversationName();
|
||||
mHistoryFileName = conversation.getHistoryFileName();
|
||||
mSessionID = conversation.getSessionID();
|
||||
mParticipantID = conversation.getParticipantID();
|
||||
mIsVoice = conversation.isVoice();
|
||||
mHasOfflineIMs = conversation.hasOfflineMessages();
|
||||
|
||||
setListenIMFloaterOpened();
|
||||
}
|
||||
|
||||
LLConversation::~LLConversation()
|
||||
{
|
||||
mIMFloaterShowedConnection.disconnect();
|
||||
}
|
||||
|
||||
void LLConversation::onIMFloaterShown(const LLUUID& session_id)
|
||||
{
|
||||
if (mSessionID == session_id)
|
||||
{
|
||||
mHasOfflineIMs = false;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string LLConversation::createTimestamp(const time_t& utc_time)
|
||||
{
|
||||
std::string timeStr;
|
||||
LLSD substitution;
|
||||
substitution["datetime"] = (S32) utc_time;
|
||||
|
||||
timeStr = "["+LLTrans::getString ("TimeMonth")+"]/["
|
||||
+LLTrans::getString ("TimeDay")+"]/["
|
||||
+LLTrans::getString ("TimeYear")+"] ["
|
||||
+LLTrans::getString ("TimeHour")+"]:["
|
||||
+LLTrans::getString ("TimeMin")+"]";
|
||||
|
||||
|
||||
LLStringUtil::format (timeStr, substitution);
|
||||
return timeStr;
|
||||
}
|
||||
|
||||
void LLConversation::setListenIMFloaterOpened()
|
||||
{
|
||||
LLIMFloater* floater = LLIMFloater::findInstance(mSessionID);
|
||||
|
||||
bool has_offline_ims = !mIsVoice && mHasOfflineIMs;
|
||||
bool ims_are_read = LLIMFloater::isVisible(floater) && floater->hasFocus();
|
||||
|
||||
// we don't need to listen for im floater with this conversation is opened
|
||||
// if floater is already opened or this conversation doesn't have unread offline messages
|
||||
if (has_offline_ims && !ims_are_read)
|
||||
{
|
||||
mIMFloaterShowedConnection = LLIMFloater::setIMFloaterShowedCallback(boost::bind(&LLConversation::onIMFloaterShown, this, _1));
|
||||
}
|
||||
}
|
||||
/************************************************************************/
|
||||
/* LLConversationLog implementation */
|
||||
/************************************************************************/
|
||||
|
||||
LLConversationLog::LLConversationLog()
|
||||
{
|
||||
loadFromFile(getFileName());
|
||||
|
||||
LLIMMgr::instance().addSessionObserver(this);
|
||||
LLAvatarTracker::instance().addObserver(this);
|
||||
}
|
||||
void LLConversationLog::logConversation(const LLConversation& conversation)
|
||||
{
|
||||
mConversations.push_back(conversation);
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
void LLConversationLog::removeConversation(const LLConversation& conversation)
|
||||
{
|
||||
conversations_vec_t::iterator conv_it = mConversations.begin();
|
||||
for(; conv_it != mConversations.end(); ++conv_it)
|
||||
{
|
||||
if (conv_it->getSessionID() == conversation.getSessionID() && conv_it->getTime() == conversation.getTime())
|
||||
{
|
||||
mConversations.erase(conv_it);
|
||||
notifyObservers();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const LLConversation* LLConversationLog::getConversation(const LLUUID& session_id)
|
||||
{
|
||||
conversations_vec_t::const_iterator conv_it = mConversations.begin();
|
||||
for(; conv_it != mConversations.end(); ++conv_it)
|
||||
{
|
||||
if (conv_it->getSessionID() == session_id)
|
||||
{
|
||||
return &*conv_it;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LLConversationLog::addObserver(LLConversationLogObserver* observer)
|
||||
{
|
||||
mObservers.insert(observer);
|
||||
}
|
||||
|
||||
void LLConversationLog::removeObserver(LLConversationLogObserver* observer)
|
||||
{
|
||||
mObservers.erase(observer);
|
||||
}
|
||||
|
||||
void LLConversationLog::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
|
||||
{
|
||||
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(session_id);
|
||||
if (session)
|
||||
{
|
||||
LLConversation conversation(*session);
|
||||
LLConversationLog::instance().logConversation(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
// LLFriendObserver
|
||||
void LLConversationLog::changed(U32 mask)
|
||||
{
|
||||
if (mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE))
|
||||
{
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
void LLConversationLog::cache()
|
||||
{
|
||||
saveToFile(getFileName());
|
||||
}
|
||||
|
||||
std::string LLConversationLog::getFileName()
|
||||
{
|
||||
std::string agent_id_string;
|
||||
gAgent.getID().toString(agent_id_string);
|
||||
|
||||
return gDirUtilp->getExpandedFilename(LL_PATH_CACHE, agent_id_string) + ".call_log";
|
||||
}
|
||||
|
||||
bool LLConversationLog::saveToFile(const std::string& filename)
|
||||
{
|
||||
if(!filename.size())
|
||||
{
|
||||
llwarns << "Call log list filename is empty!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLFILE* fp = LLFile::fopen(filename, "wb");
|
||||
if (!fp)
|
||||
{
|
||||
llwarns << "Couldn't open call log list" << filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string participant_id;
|
||||
std::string conversation_id;
|
||||
|
||||
conversations_vec_t::const_iterator conv_it = mConversations.begin();
|
||||
for (; conv_it != mConversations.end(); ++conv_it)
|
||||
{
|
||||
conv_it->getSessionID().toString(conversation_id);
|
||||
conv_it->getParticipantID().toString(participant_id);
|
||||
|
||||
// examples of two file entries
|
||||
// [1343221177] 0 1 0 John Doe| 7e4ec5be-783f-49f5-71dz-16c58c64c145 4ec62a74-c246-0d25-2af6-846beac2aa55 john.doe|
|
||||
// [1343222639] 2 0 0 Ad-hoc Conference| c3g67c89-c479-4c97-b21d-32869bcfe8rc 68f1c33e-4135-3e3e-a897-8c9b23115c09 Ad-hoc Conference hash597394a0-9982-766d-27b8-c75560213b9a|
|
||||
|
||||
fprintf(fp, "[%d] %d %d %d %s| %s %s %s|\n",
|
||||
(S32)conv_it->getTime(),
|
||||
(S32)conv_it->getConversationType(),
|
||||
(S32)conv_it->isVoice(),
|
||||
(S32)conv_it->hasOfflineMessages(),
|
||||
conv_it->getConversationName().c_str(),
|
||||
participant_id.c_str(),
|
||||
conversation_id.c_str(),
|
||||
conv_it->getHistoryFileName().c_str());
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
bool LLConversationLog::loadFromFile(const std::string& filename)
|
||||
{
|
||||
if(!filename.size())
|
||||
{
|
||||
llwarns << "Call log list filename is empty!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLFILE* fp = LLFile::fopen(filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
llwarns << "Couldn't open call log list" << filename << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[MAX_STRING];
|
||||
char conv_name_buffer[MAX_STRING];
|
||||
char part_id_buffer[MAX_STRING];
|
||||
char conv_id_buffer[MAX_STRING];
|
||||
char history_file_name[MAX_STRING];
|
||||
int is_voice;
|
||||
int has_offline_ims;
|
||||
int stype;
|
||||
S32 time;
|
||||
|
||||
while (!feof(fp) && fgets(buffer, MAX_STRING, fp))
|
||||
{
|
||||
conv_name_buffer[0] = '\0';
|
||||
part_id_buffer[0] = '\0';
|
||||
conv_id_buffer[0] = '\0';
|
||||
|
||||
sscanf(buffer, "[%d] %d %d %d %[^|]| %s %s %[^|]|",
|
||||
&time,
|
||||
&stype,
|
||||
&is_voice,
|
||||
&has_offline_ims,
|
||||
conv_name_buffer,
|
||||
part_id_buffer,
|
||||
conv_id_buffer,
|
||||
history_file_name);
|
||||
|
||||
Conversation_params params(time);
|
||||
params.mConversationType = (SessionType)stype;
|
||||
params.mIsVoice = is_voice;
|
||||
params.mHasOfflineIMs = has_offline_ims;
|
||||
params.mConversationName = std::string(conv_name_buffer);
|
||||
params.mParticipantID = LLUUID(part_id_buffer);
|
||||
params.mSessionID = LLUUID(conv_id_buffer);
|
||||
params.mHistoryFileName = std::string(history_file_name);
|
||||
|
||||
LLConversation conversation(params);
|
||||
mConversations.push_back(conversation);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
notifyObservers();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLConversationLog::notifyObservers()
|
||||
{
|
||||
std::set<LLConversationLogObserver*>::const_iterator iter = mObservers.begin();
|
||||
for (; iter != mObservers.end(); ++iter)
|
||||
{
|
||||
(*iter)->changed();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
* @file llconversationlog.h
|
||||
*
|
||||
* $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 LLCONVERSATIONLOG_H_
|
||||
#define LLCONVERSATIONLOG_H_
|
||||
|
||||
#include "llcallingcard.h"
|
||||
#include "llimfloater.h"
|
||||
#include "llimview.h"
|
||||
|
||||
class LLConversationLogObserver;
|
||||
struct Conversation_params;
|
||||
|
||||
typedef LLIMModel::LLIMSession::SType SessionType;
|
||||
|
||||
/*
|
||||
* This class represents a particular session(conversation) of any type(im/voice/p2p/group/...) by storing some of session's data.
|
||||
* Each LLConversation object has a corresponding visual representation in a form of LLConversationLogListItem.
|
||||
*/
|
||||
class LLConversation
|
||||
{
|
||||
public:
|
||||
|
||||
LLConversation(const Conversation_params& params);
|
||||
LLConversation(const LLIMModel::LLIMSession& session);
|
||||
LLConversation(const LLConversation& conversation);
|
||||
|
||||
~LLConversation();
|
||||
|
||||
const SessionType& getConversationType() const { return mConversationType; }
|
||||
const std::string& getConversationName() const { return mConversationName; }
|
||||
const std::string& getHistoryFileName() const { return mHistoryFileName; }
|
||||
const LLUUID& getSessionID() const { return mSessionID; }
|
||||
const LLUUID& getParticipantID() const { return mParticipantID; }
|
||||
const std::string& getTimestamp() const { return mTimestamp; }
|
||||
const time_t& getTime() const { return mTime; }
|
||||
bool isVoice() const { return mIsVoice; }
|
||||
bool hasOfflineMessages() const { return mHasOfflineIMs; }
|
||||
|
||||
/*
|
||||
* Resets flag of unread offline message to false when im floater with this conversation is opened.
|
||||
*/
|
||||
void onIMFloaterShown(const LLUUID& session_id);
|
||||
|
||||
/*
|
||||
* returns string representation(in form of: mm/dd/yyyy hh:mm) of time when conversation was started
|
||||
*/
|
||||
static const std::string createTimestamp(const time_t& utc_time);
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* If conversation has unread offline messages sets callback for opening LLIMFloater
|
||||
* with this conversation.
|
||||
*/
|
||||
void setListenIMFloaterOpened();
|
||||
|
||||
boost::signals2::connection mIMFloaterShowedConnection;
|
||||
|
||||
time_t mTime; // start time of conversation
|
||||
SessionType mConversationType;
|
||||
std::string mConversationName;
|
||||
std::string mHistoryFileName;
|
||||
LLUUID mSessionID;
|
||||
LLUUID mParticipantID;
|
||||
bool mIsVoice;
|
||||
bool mHasOfflineIMs;
|
||||
std::string mTimestamp; // conversation start time in form of: mm/dd/yyyy hh:mm
|
||||
};
|
||||
|
||||
/**
|
||||
* LLConversationLog stores all agent's conversations.
|
||||
* This class is responsible for creating and storing LLConversation objects when im or voice session starts.
|
||||
* Also this class saves/retrieves conversations to/from file.
|
||||
*
|
||||
* Also please note that it may be several conversations with the same sessionID stored in the conversation log.
|
||||
* To distinguish two conversations with the same sessionID it's also needed to compare their creation date.
|
||||
*/
|
||||
|
||||
class LLConversationLog : public LLSingleton<LLConversationLog>, LLIMSessionObserver, LLFriendObserver
|
||||
{
|
||||
friend class LLSingleton<LLConversationLog>;
|
||||
public:
|
||||
|
||||
/**
|
||||
* adds conversation to the conversation list and notifies observers
|
||||
*/
|
||||
void logConversation(const LLConversation& conversation);
|
||||
void removeConversation(const LLConversation& conversation);
|
||||
|
||||
/**
|
||||
* Returns first conversation with matched session_id
|
||||
*/
|
||||
const LLConversation* getConversation(const LLUUID& session_id);
|
||||
|
||||
void addObserver(LLConversationLogObserver* observer);
|
||||
void removeObserver(LLConversationLogObserver* observer);
|
||||
|
||||
const std::vector<LLConversation>& getConversations() { return mConversations; }
|
||||
|
||||
// LLIMSessionObserver triggers
|
||||
virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id);
|
||||
virtual void sessionVoiceOrIMStarted(const LLUUID& session_id){} // Stub
|
||||
virtual void sessionRemoved(const LLUUID& session_id){} // Stub
|
||||
virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id){} // Stub
|
||||
|
||||
// LLFriendObserver trigger
|
||||
virtual void changed(U32 mask);
|
||||
|
||||
/**
|
||||
* public method which is called on viewer exit to save conversation log
|
||||
*/
|
||||
void cache();
|
||||
|
||||
private:
|
||||
|
||||
LLConversationLog();
|
||||
void notifyObservers();
|
||||
|
||||
/**
|
||||
* constructs file name in which conversations log will be saved
|
||||
* file name template: agentID.call_log.
|
||||
* For example: a086icaa-782d-88d0-ae29-987a55c99sss.call_log
|
||||
*/
|
||||
std::string getFileName();
|
||||
|
||||
bool saveToFile(const std::string& filename);
|
||||
bool loadFromFile(const std::string& filename);
|
||||
|
||||
typedef std::vector<LLConversation> conversations_vec_t;
|
||||
std::vector<LLConversation> mConversations;
|
||||
std::set<LLConversationLogObserver*> mObservers;
|
||||
};
|
||||
|
||||
class LLConversationLogObserver
|
||||
{
|
||||
public:
|
||||
virtual ~LLConversationLogObserver(){}
|
||||
virtual void changed() = 0;
|
||||
};
|
||||
|
||||
#endif /* LLCONVERSATIONLOG_H_ */
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
/**
|
||||
* @file llconversationloglist.cpp
|
||||
*
|
||||
* $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 "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llavataractions.h"
|
||||
#include "llagent.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloaterconversationpreview.h"
|
||||
#include "llgroupactions.h"
|
||||
#include "llconversationloglist.h"
|
||||
#include "llconversationloglistitem.h"
|
||||
#include "llviewermenu.h"
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLConversationLogList> r("conversation_log_list");
|
||||
|
||||
static LLConversationLogListNameComparator NAME_COMPARATOR;
|
||||
static LLConversationLogListDateComparator DATE_COMPARATOR;
|
||||
|
||||
LLConversationLogList::LLConversationLogList(const Params& p)
|
||||
: LLFlatListViewEx(p),
|
||||
mIsDirty(true)
|
||||
{
|
||||
LLConversationLog::instance().addObserver(this);
|
||||
|
||||
// Set up context menu.
|
||||
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar check_registrar;
|
||||
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
|
||||
|
||||
registrar.add ("Calllog.Action", boost::bind(&LLConversationLogList::onCustomAction, this, _2));
|
||||
check_registrar.add ("Calllog.Check", boost::bind(&LLConversationLogList::isActionChecked,this, _2));
|
||||
enable_registrar.add("Calllog.Enable", boost::bind(&LLConversationLogList::isActionEnabled,this, _2));
|
||||
|
||||
LLToggleableMenu* context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(
|
||||
"menu_conversation_log_gear.xml",
|
||||
gMenuHolder,
|
||||
LLViewerMenuHolderGL::child_registry_t::instance());
|
||||
if(context_menu)
|
||||
{
|
||||
mContextMenu = context_menu->getHandle();
|
||||
}
|
||||
|
||||
mIsFriendsOnTop = gSavedSettings.getBOOL("SortFriendsFirst");
|
||||
}
|
||||
|
||||
LLConversationLogList::~LLConversationLogList()
|
||||
{
|
||||
if (mContextMenu.get())
|
||||
{
|
||||
mContextMenu.get()->die();
|
||||
}
|
||||
|
||||
LLConversationLog::instance().removeObserver(this);
|
||||
}
|
||||
|
||||
void LLConversationLogList::draw()
|
||||
{
|
||||
if (mIsDirty)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
LLFlatListViewEx::draw();
|
||||
}
|
||||
|
||||
BOOL LLConversationLogList::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
|
||||
|
||||
LLToggleableMenu* context_menu = mContextMenu.get();
|
||||
{
|
||||
context_menu->buildDrawLabels();
|
||||
if (context_menu && size())
|
||||
context_menu->updateParent(LLMenuGL::sMenuContainer);
|
||||
LLMenuGL::showPopup(this, context_menu, x, y);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void LLConversationLogList::setNameFilter(const std::string& filter)
|
||||
{
|
||||
std::string filter_upper = filter;
|
||||
LLStringUtil::toUpper(filter_upper);
|
||||
if (mNameFilter != filter_upper)
|
||||
{
|
||||
mNameFilter = filter_upper;
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLConversationLogList::findInsensitive(std::string haystack, const std::string& needle_upper)
|
||||
{
|
||||
LLStringUtil::toUpper(haystack);
|
||||
return haystack.find(needle_upper) != std::string::npos;
|
||||
}
|
||||
|
||||
void LLConversationLogList::sortByName()
|
||||
{
|
||||
setComparator(&NAME_COMPARATOR);
|
||||
sort();
|
||||
}
|
||||
|
||||
void LLConversationLogList::sortByDate()
|
||||
{
|
||||
setComparator(&DATE_COMPARATOR);
|
||||
sort();
|
||||
}
|
||||
|
||||
void LLConversationLogList::toggleSortFriendsOnTop()
|
||||
{
|
||||
mIsFriendsOnTop = !mIsFriendsOnTop;
|
||||
gSavedSettings.setBOOL("SortFriendsFirst", mIsFriendsOnTop);
|
||||
sort();
|
||||
}
|
||||
|
||||
void LLConversationLogList::changed()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void LLConversationLogList::addNewItem(const LLConversation* conversation)
|
||||
{
|
||||
LLConversationLogListItem* item = new LLConversationLogListItem(&*conversation);
|
||||
if (!mNameFilter.empty())
|
||||
{
|
||||
item->highlightNameDate(mNameFilter);
|
||||
}
|
||||
addItem(item, conversation->getSessionID(), ADD_TOP);
|
||||
}
|
||||
|
||||
void LLConversationLogList::refresh()
|
||||
{
|
||||
rebuildList();
|
||||
sort();
|
||||
|
||||
mIsDirty = false;
|
||||
}
|
||||
|
||||
void LLConversationLogList::rebuildList()
|
||||
{
|
||||
clear();
|
||||
|
||||
bool have_filter = !mNameFilter.empty();
|
||||
|
||||
const std::vector<LLConversation>& conversations = LLConversationLog::instance().getConversations();
|
||||
std::vector<LLConversation>::const_iterator iter = conversations.begin();
|
||||
|
||||
for (; iter != conversations.end(); ++iter)
|
||||
{
|
||||
bool not_found = have_filter && !findInsensitive(iter->getConversationName(), mNameFilter) && !findInsensitive(iter->getTimestamp(), mNameFilter);
|
||||
if (not_found)
|
||||
continue;
|
||||
|
||||
addNewItem(&*iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLConversationLogList::onCustomAction(const LLSD& userdata)
|
||||
{
|
||||
const std::string command_name = userdata.asString();
|
||||
const LLUUID& selected_id = getSelectedConversation()->getParticipantID();
|
||||
LLIMModel::LLIMSession::SType stype = getSelectedSessionType();
|
||||
|
||||
if ("im" == command_name)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case LLIMModel::LLIMSession::P2P_SESSION:
|
||||
LLAvatarActions::startIM(selected_id);
|
||||
break;
|
||||
|
||||
case LLIMModel::LLIMSession::GROUP_SESSION:
|
||||
LLGroupActions::startIM(selected_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ("call" == command_name)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case LLIMModel::LLIMSession::P2P_SESSION:
|
||||
LLAvatarActions::startCall(selected_id);
|
||||
break;
|
||||
|
||||
case LLIMModel::LLIMSession::GROUP_SESSION:
|
||||
LLGroupActions::startCall(selected_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ("view_profile" == command_name)
|
||||
{
|
||||
switch (stype)
|
||||
{
|
||||
case LLIMModel::LLIMSession::P2P_SESSION:
|
||||
LLAvatarActions::showProfile(selected_id);
|
||||
break;
|
||||
|
||||
case LLIMModel::LLIMSession::GROUP_SESSION:
|
||||
LLGroupActions::show(selected_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ("chat_history" == command_name)
|
||||
{
|
||||
const LLUUID& session_id = getSelectedConversation()->getSessionID();
|
||||
LLFloaterReg::showInstance("preview_conversation", session_id, true);
|
||||
}
|
||||
else if ("offer_teleport" == command_name)
|
||||
{
|
||||
LLAvatarActions::offerTeleport(selected_id);
|
||||
}
|
||||
else if("add_rem_friend" == command_name)
|
||||
{
|
||||
if (LLAvatarActions::isFriend(selected_id))
|
||||
{
|
||||
LLAvatarActions::removeFriendDialog(selected_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLAvatarActions::requestFriendshipDialog(selected_id);
|
||||
}
|
||||
}
|
||||
else if ("invite_to_group" == command_name)
|
||||
{
|
||||
LLAvatarActions::inviteToGroup(selected_id);
|
||||
}
|
||||
else if ("show_on_map" == command_name)
|
||||
{
|
||||
LLAvatarActions::showOnMap(selected_id);
|
||||
}
|
||||
else if ("share" == command_name)
|
||||
{
|
||||
LLAvatarActions::share(selected_id);
|
||||
}
|
||||
else if ("pay" == command_name)
|
||||
{
|
||||
LLAvatarActions::pay(selected_id);
|
||||
}
|
||||
else if ("block" == command_name)
|
||||
{
|
||||
LLAvatarActions::toggleBlock(selected_id);
|
||||
}
|
||||
}
|
||||
|
||||
bool LLConversationLogList::isActionEnabled(const LLSD& userdata)
|
||||
{
|
||||
if (numSelected() != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string command_name = userdata.asString();
|
||||
|
||||
LLIMModel::LLIMSession::SType stype = getSelectedSessionType();
|
||||
const LLUUID& selected_id = getSelectedConversation()->getParticipantID();
|
||||
|
||||
bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == stype;
|
||||
bool is_group = LLIMModel::LLIMSession::GROUP_SESSION == stype;
|
||||
|
||||
if ("can_im" == command_name || "can_view_profile" == command_name)
|
||||
{
|
||||
return is_p2p || is_group;
|
||||
}
|
||||
else if ("can_view_chat_history" == command_name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ("can_call" == command_name)
|
||||
{
|
||||
return (is_p2p || is_group) && LLAvatarActions::canCall();
|
||||
}
|
||||
else if ("add_rem_friend" == command_name ||
|
||||
"can_invite_to_group" == command_name ||
|
||||
"can_share" == command_name ||
|
||||
"can_block" == command_name ||
|
||||
"can_pay" == command_name)
|
||||
{
|
||||
return is_p2p;
|
||||
}
|
||||
else if("can_offer_teleport" == command_name)
|
||||
{
|
||||
return is_p2p && LLAvatarActions::canOfferTeleport(selected_id);
|
||||
}
|
||||
else if ("can_show_on_map")
|
||||
{
|
||||
return is_p2p && ((LLAvatarTracker::instance().isBuddyOnline(selected_id) && is_agent_mappable(selected_id)) || gAgent.isGodlike());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLConversationLogList::isActionChecked(const LLSD& userdata)
|
||||
{
|
||||
const std::string command_name = userdata.asString();
|
||||
|
||||
const LLUUID& selected_id = getSelectedConversation()->getParticipantID();
|
||||
bool is_p2p = LLIMModel::LLIMSession::P2P_SESSION == getSelectedSessionType();
|
||||
|
||||
if ("is_blocked" == command_name)
|
||||
{
|
||||
return is_p2p && LLAvatarActions::isBlocked(selected_id);
|
||||
}
|
||||
else if ("is_friend" == command_name)
|
||||
{
|
||||
return is_p2p && LLAvatarActions::isFriend(selected_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LLIMModel::LLIMSession::SType LLConversationLogList::getSelectedSessionType()
|
||||
{
|
||||
const LLConversationLogListItem* item = getSelectedConversationPanel();
|
||||
|
||||
if (item)
|
||||
{
|
||||
return item->getConversation()->getConversationType();
|
||||
}
|
||||
|
||||
return LLIMModel::LLIMSession::NONE_SESSION;
|
||||
}
|
||||
|
||||
const LLConversationLogListItem* LLConversationLogList::getSelectedConversationPanel()
|
||||
{
|
||||
LLPanel* panel = LLFlatListViewEx::getSelectedItem();
|
||||
LLConversationLogListItem* conv_panel = dynamic_cast<LLConversationLogListItem*>(panel);
|
||||
|
||||
return conv_panel;
|
||||
}
|
||||
|
||||
const LLConversation* LLConversationLogList::getSelectedConversation()
|
||||
{
|
||||
const LLConversationLogListItem* panel = getSelectedConversationPanel();
|
||||
|
||||
if (panel)
|
||||
{
|
||||
return panel->getConversation();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LLConversationLogListItemComparator::compare(const LLPanel* item1, const LLPanel* item2) const
|
||||
{
|
||||
const LLConversationLogListItem* conversation_item1 = dynamic_cast<const LLConversationLogListItem*>(item1);
|
||||
const LLConversationLogListItem* conversation_item2 = dynamic_cast<const LLConversationLogListItem*>(item2);
|
||||
|
||||
if (!conversation_item1 || !conversation_item2)
|
||||
{
|
||||
llerror("conversation_item1 and conversation_item2 cannot be null", 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return doCompare(conversation_item1, conversation_item2);
|
||||
}
|
||||
|
||||
bool LLConversationLogListNameComparator::doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const
|
||||
{
|
||||
std::string name1 = conversation1->getConversation()->getConversationName();
|
||||
std::string name2 = conversation2->getConversation()->getConversationName();
|
||||
const LLUUID& id1 = conversation1->getConversation()->getParticipantID();
|
||||
const LLUUID& id2 = conversation2->getConversation()->getParticipantID();
|
||||
|
||||
LLStringUtil::toUpper(name1);
|
||||
LLStringUtil::toUpper(name2);
|
||||
|
||||
bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst");
|
||||
if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
|
||||
{
|
||||
return LLAvatarActions::isFriend(id1);
|
||||
}
|
||||
|
||||
return name1 < name2;
|
||||
}
|
||||
|
||||
bool LLConversationLogListDateComparator::doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const
|
||||
{
|
||||
time_t date1 = conversation1->getConversation()->getTime();
|
||||
time_t date2 = conversation2->getConversation()->getTime();
|
||||
const LLUUID& id1 = conversation1->getConversation()->getParticipantID();
|
||||
const LLUUID& id2 = conversation2->getConversation()->getParticipantID();
|
||||
|
||||
bool friends_first = gSavedSettings.getBOOL("SortFriendsFirst");
|
||||
if (friends_first && (LLAvatarActions::isFriend(id1) ^ LLAvatarActions::isFriend(id2)))
|
||||
{
|
||||
return LLAvatarActions::isFriend(id1);
|
||||
}
|
||||
|
||||
return date1 > date2;
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* @file llconversationloglist.h
|
||||
*
|
||||
* $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 LLCONVERSATIONLOGLIST_H_
|
||||
#define LLCONVERSATIONLOGLIST_H_
|
||||
|
||||
#include "llconversationlog.h"
|
||||
#include "llflatlistview.h"
|
||||
#include "lltoggleablemenu.h"
|
||||
|
||||
class LLConversationLogListItem;
|
||||
|
||||
/**
|
||||
* List of all agent's conversations. I.e. history of conversations.
|
||||
* This list represents contents of the LLConversationLog.
|
||||
* Each change in LLConversationLog leads to rebuilding this list, so
|
||||
* it's always in actual state.
|
||||
*/
|
||||
|
||||
class LLConversationLogList: public LLFlatListViewEx, public LLConversationLogObserver
|
||||
{
|
||||
LOG_CLASS(LLConversationLogList);
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLFlatListViewEx::Params>
|
||||
{
|
||||
Params(){};
|
||||
};
|
||||
|
||||
LLConversationLogList(const Params& p);
|
||||
virtual ~LLConversationLogList();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
|
||||
LLToggleableMenu* getContextMenu() const { return mContextMenu.get(); }
|
||||
|
||||
void addNewItem(const LLConversation* conversation);
|
||||
void setNameFilter(const std::string& filter);
|
||||
void sortByName();
|
||||
void sortByDate();
|
||||
void toggleSortFriendsOnTop();
|
||||
bool getSortFriendsOnTop() const { return mIsFriendsOnTop; }
|
||||
|
||||
/**
|
||||
* Changes from LLConversationLogObserver
|
||||
*/
|
||||
virtual void changed();
|
||||
|
||||
private:
|
||||
|
||||
void setDirty(bool dirty = true) { mIsDirty = dirty; }
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* Clears list and re-adds items from LLConverstationLog
|
||||
* If filter is not empty re-adds items which match the filter
|
||||
*/
|
||||
void rebuildList();
|
||||
|
||||
bool findInsensitive(std::string haystack, const std::string& needle_upper);
|
||||
|
||||
void onCustomAction (const LLSD& userdata);
|
||||
bool isActionEnabled(const LLSD& userdata);
|
||||
bool isActionChecked(const LLSD& userdata);
|
||||
|
||||
LLIMModel::LLIMSession::SType getSelectedSessionType();
|
||||
const LLConversationLogListItem* getSelectedConversationPanel();
|
||||
const LLConversation* getSelectedConversation();
|
||||
|
||||
LLHandle<LLToggleableMenu> mContextMenu;
|
||||
bool mIsDirty;
|
||||
bool mIsFriendsOnTop;
|
||||
std::string mNameFilter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract comparator for ConversationLogList items
|
||||
*/
|
||||
class LLConversationLogListItemComparator : public LLFlatListView::ItemComparator
|
||||
{
|
||||
LOG_CLASS(LLConversationLogListItemComparator);
|
||||
|
||||
public:
|
||||
LLConversationLogListItemComparator() {};
|
||||
virtual ~LLConversationLogListItemComparator() {};
|
||||
|
||||
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const = 0;
|
||||
};
|
||||
|
||||
class LLConversationLogListNameComparator : public LLConversationLogListItemComparator
|
||||
{
|
||||
LOG_CLASS(LLConversationLogListNameComparator);
|
||||
|
||||
public:
|
||||
LLConversationLogListNameComparator() {};
|
||||
virtual ~LLConversationLogListNameComparator() {};
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const;
|
||||
};
|
||||
|
||||
class LLConversationLogListDateComparator : public LLConversationLogListItemComparator
|
||||
{
|
||||
LOG_CLASS(LLConversationLogListDateComparator);
|
||||
|
||||
public:
|
||||
LLConversationLogListDateComparator() {};
|
||||
virtual ~LLConversationLogListDateComparator() {};
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool doCompare(const LLConversationLogListItem* conversation1, const LLConversationLogListItem* conversation2) const;
|
||||
};
|
||||
|
||||
#endif /* LLCONVERSATIONLOGLIST_H_ */
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/**
|
||||
* @file llconversationloglistitem.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
// llui
|
||||
#include "lliconctrl.h"
|
||||
#include "lltextbox.h"
|
||||
#include "lltextutil.h"
|
||||
|
||||
// newview
|
||||
#include "llavatariconctrl.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "llconversationloglistitem.h"
|
||||
#include "llgroupiconctrl.h"
|
||||
#include "llinventoryicon.h"
|
||||
|
||||
LLConversationLogListItem::LLConversationLogListItem(const LLConversation* conversation)
|
||||
: LLPanel(),
|
||||
mConversation(conversation),
|
||||
mConversationName(NULL),
|
||||
mConversationDate(NULL)
|
||||
{
|
||||
buildFromFile("panel_conversation_log_list_item.xml");
|
||||
|
||||
LLIMFloater* floater = LLIMFloater::findInstance(mConversation->getSessionID());
|
||||
|
||||
bool has_offline_ims = !mConversation->isVoice() && mConversation->hasOfflineMessages();
|
||||
bool ims_are_read = LLIMFloater::isVisible(floater) && floater->hasFocus();
|
||||
|
||||
if (has_offline_ims && !ims_are_read)
|
||||
{
|
||||
mIMFloaterShowedConnection = LLIMFloater::setIMFloaterShowedCallback(boost::bind(&LLConversationLogListItem::onIMFloaterShown, this, _1));
|
||||
}
|
||||
}
|
||||
|
||||
LLConversationLogListItem::~LLConversationLogListItem()
|
||||
{
|
||||
mIMFloaterShowedConnection.disconnect();
|
||||
}
|
||||
|
||||
BOOL LLConversationLogListItem::postBuild()
|
||||
{
|
||||
initIcons();
|
||||
|
||||
// set conversation name
|
||||
mConversationName = getChild<LLTextBox>("conversation_name");
|
||||
mConversationName->setValue(mConversation->getConversationName());
|
||||
|
||||
// set conversation date and time
|
||||
mConversationDate = getChild<LLTextBox>("date_time");
|
||||
mConversationDate->setValue(mConversation->getTimestamp());
|
||||
|
||||
getChild<LLButton>("delete_btn")->setClickedCallback(boost::bind(&LLConversationLogListItem::onRemoveBtnClicked, this));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::initIcons()
|
||||
{
|
||||
switch (mConversation->getConversationType())
|
||||
{
|
||||
case LLIMModel::LLIMSession::P2P_SESSION:
|
||||
case LLIMModel::LLIMSession::ADHOC_SESSION:
|
||||
{
|
||||
LLAvatarIconCtrl* avatar_icon = getChild<LLAvatarIconCtrl>("avatar_icon");
|
||||
avatar_icon->setVisible(TRUE);
|
||||
avatar_icon->setValue(mConversation->getParticipantID());
|
||||
break;
|
||||
}
|
||||
case LLIMModel::LLIMSession::GROUP_SESSION:
|
||||
{
|
||||
LLGroupIconCtrl* group_icon = getChild<LLGroupIconCtrl>("group_icon");
|
||||
group_icon->setVisible(TRUE);
|
||||
group_icon->setValue(mConversation->getSessionID());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mConversation->isVoice())
|
||||
{
|
||||
getChild<LLIconCtrl>("voice_session_icon")->setVisible(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mConversation->hasOfflineMessages())
|
||||
{
|
||||
getChild<LLIconCtrl>("unread_ims_icon")->setVisible(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::onMouseEnter(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
getChildView("hovered_icon")->setVisible(true);
|
||||
LLPanel::onMouseEnter(x, y, mask);
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::onMouseLeave(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
getChildView("hovered_icon")->setVisible(false);
|
||||
LLPanel::onMouseLeave(x, y, mask);
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::setValue(const LLSD& value)
|
||||
{
|
||||
if (!value.isMap() || !value.has("selected"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
getChildView("selected_icon")->setVisible(value["selected"]);
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::onIMFloaterShown(const LLUUID& session_id)
|
||||
{
|
||||
if (mConversation->getSessionID() == session_id)
|
||||
{
|
||||
getChild<LLIconCtrl>("unread_ims_icon")->setVisible(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::onRemoveBtnClicked()
|
||||
{
|
||||
LLConversationLog::instance().removeConversation(*mConversation);
|
||||
}
|
||||
|
||||
void LLConversationLogListItem::highlightNameDate(const std::string& highlited_text)
|
||||
{
|
||||
LLStyle::Params params;
|
||||
LLTextUtil::textboxSetHighlightedVal(mConversationName, params, mConversation->getConversationName(), highlited_text);
|
||||
LLTextUtil::textboxSetHighlightedVal(mConversationDate, params, mConversation->getTimestamp(), highlited_text);
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* @file llconversationloglistitem.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLCONVERSATIONLOGLISTITEM_H_
|
||||
#define LLCONVERSATIONLOGLISTITEM_H_
|
||||
|
||||
#include "llimfloater.h"
|
||||
#include "llpanel.h"
|
||||
|
||||
class LLTextBox;
|
||||
class LLConversation;
|
||||
|
||||
/**
|
||||
* This class is a visual representation of LLConversation, each of which is LLConversationLog entry.
|
||||
* LLConversationLogList consists of these LLConversationLogListItems.
|
||||
* LLConversationLogListItem consists of:
|
||||
* conversaion_type_icon
|
||||
* conversaion_name
|
||||
* conversaion_date
|
||||
* Also LLConversationLogListItem holds pointer to its LLConversationLog.
|
||||
*/
|
||||
|
||||
class LLConversationLogListItem : public LLPanel
|
||||
{
|
||||
public:
|
||||
LLConversationLogListItem(const LLConversation* conversation);
|
||||
virtual ~LLConversationLogListItem();
|
||||
|
||||
void onMouseEnter(S32 x, S32 y, MASK mask);
|
||||
void onMouseLeave(S32 x, S32 y, MASK mask);
|
||||
|
||||
virtual void setValue(const LLSD& value);
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
void onIMFloaterShown(const LLUUID& session_id);
|
||||
void onRemoveBtnClicked();
|
||||
|
||||
const LLConversation* getConversation() const { return mConversation; }
|
||||
|
||||
void highlightNameDate(const std::string& highlited_text);
|
||||
|
||||
private:
|
||||
|
||||
void initIcons();
|
||||
|
||||
const LLConversation* mConversation;
|
||||
|
||||
LLTextBox* mConversationName;
|
||||
LLTextBox* mConversationDate;
|
||||
|
||||
boost::signals2::connection mIMFloaterShowedConnection;
|
||||
};
|
||||
|
||||
#endif /* LLCONVERSATIONLOGITEM_H_ */
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* @file llfloaterconversationlog.cpp
|
||||
* @brief Functionality of the "conversation log" floater
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llconversationloglist.h"
|
||||
#include "llfiltereditor.h"
|
||||
#include "llfloaterconversationlog.h"
|
||||
#include "llmenubutton.h"
|
||||
|
||||
LLFloaterConversationLog::LLFloaterConversationLog(const LLSD& key)
|
||||
: LLFloater(key),
|
||||
mConversationLogList(NULL)
|
||||
{
|
||||
mCommitCallbackRegistrar.add("CallLog.Action", boost::bind(&LLFloaterConversationLog::onCustomAction, this, _2));
|
||||
mEnableCallbackRegistrar.add("CallLog.Check", boost::bind(&LLFloaterConversationLog::isActionChecked, this, _2));
|
||||
}
|
||||
|
||||
BOOL LLFloaterConversationLog::postBuild()
|
||||
{
|
||||
mConversationLogList = getChild<LLConversationLogList>("conversation_log_list");
|
||||
|
||||
switch (gSavedSettings.getU32("CallLogSortOrder"))
|
||||
{
|
||||
case E_SORT_BY_NAME:
|
||||
mConversationLogList->sortByName();
|
||||
break;
|
||||
|
||||
case E_SORT_BY_DATE:
|
||||
mConversationLogList->sortByDate();
|
||||
break;
|
||||
}
|
||||
|
||||
// Use the context menu of the Conversation list for the Conversation tab gear menu.
|
||||
LLToggleableMenu* conversations_gear_menu = mConversationLogList->getContextMenu();
|
||||
if (conversations_gear_menu)
|
||||
{
|
||||
getChild<LLMenuButton>("conversations_gear_btn")->setMenu(conversations_gear_menu, LLMenuButton::MP_BOTTOM_LEFT);
|
||||
}
|
||||
|
||||
getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterConversationLog::onFilterEdit, this, _2));
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterConversationLog::draw()
|
||||
{
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
void LLFloaterConversationLog::onFilterEdit(const std::string& search_string)
|
||||
{
|
||||
std::string filter = search_string;
|
||||
LLStringUtil::trimHead(filter);
|
||||
|
||||
mConversationLogList->setNameFilter(filter);
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterConversationLog::onCustomAction (const LLSD& userdata)
|
||||
{
|
||||
const std::string command_name = userdata.asString();
|
||||
|
||||
if ("sort_by_name" == command_name)
|
||||
{
|
||||
mConversationLogList->sortByName();
|
||||
gSavedSettings.setU32("CallLogSortOrder", E_SORT_BY_NAME);
|
||||
}
|
||||
else if ("sort_by_date" == command_name)
|
||||
{
|
||||
mConversationLogList->sortByDate();
|
||||
gSavedSettings.setU32("CallLogSortOrder", E_SORT_BY_DATE);
|
||||
}
|
||||
else if ("sort_friends_on_top" == command_name)
|
||||
{
|
||||
mConversationLogList->toggleSortFriendsOnTop();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLFloaterConversationLog::isActionEnabled(const LLSD& userdata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLFloaterConversationLog::isActionChecked(const LLSD& userdata)
|
||||
{
|
||||
const std::string command_name = userdata.asString();
|
||||
|
||||
U32 sort_order = gSavedSettings.getU32("CallLogSortOrder");
|
||||
|
||||
if ("sort_by_name" == command_name)
|
||||
{
|
||||
return sort_order == E_SORT_BY_NAME;
|
||||
}
|
||||
else if ("sort_by_date" == command_name)
|
||||
{
|
||||
return sort_order == E_SORT_BY_DATE;
|
||||
}
|
||||
else if ("sort_friends_on_top" == command_name)
|
||||
{
|
||||
return gSavedSettings.getBOOL("SortFriendsFirst");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file llfloaterconversationlog.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERCONVERSATIONLOG_H_
|
||||
#define LL_LLFLOATERCONVERSATIONLOG_H_
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLConversationLogList;
|
||||
|
||||
class LLFloaterConversationLog : public LLFloater
|
||||
{
|
||||
public:
|
||||
|
||||
typedef enum e_sort_oder{
|
||||
E_SORT_BY_NAME = 0,
|
||||
E_SORT_BY_DATE = 1,
|
||||
} ESortOrder;
|
||||
|
||||
LLFloaterConversationLog(const LLSD& key);
|
||||
virtual ~LLFloaterConversationLog(){};
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
virtual void draw();
|
||||
|
||||
void onFilterEdit(const std::string& search_string);
|
||||
|
||||
private:
|
||||
|
||||
void onCustomAction (const LLSD& userdata);
|
||||
bool isActionEnabled(const LLSD& userdata);
|
||||
bool isActionChecked(const LLSD& userdata);
|
||||
|
||||
LLConversationLogList* mConversationLogList;
|
||||
};
|
||||
|
||||
|
||||
#endif /* LLFLOATERCONVERSATIONLOG_H_ */
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* @file llfloaterconversationpreview.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llconversationlog.h"
|
||||
#include "llfloaterconversationpreview.h"
|
||||
#include "llimview.h"
|
||||
#include "lllineeditor.h"
|
||||
|
||||
LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id)
|
||||
: LLFloater(session_id),
|
||||
mChatHistory(NULL),
|
||||
mSessionID(session_id.asUUID())
|
||||
{}
|
||||
|
||||
BOOL LLFloaterConversationPreview::postBuild()
|
||||
{
|
||||
mChatHistory = getChild<LLChatHistory>("chat_history");
|
||||
|
||||
const LLConversation* conv = LLConversationLog::instance().getConversation(mSessionID);
|
||||
if (conv)
|
||||
{
|
||||
std::string name = conv->getConversationName();
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[NAME]"] = name;
|
||||
std::string title = getString("Title", args);
|
||||
setTitle(title);
|
||||
|
||||
getChild<LLLineEditor>("description")->setValue(name);
|
||||
}
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterConversationPreview::draw()
|
||||
{
|
||||
LLFloater::draw();
|
||||
}
|
||||
|
||||
void LLFloaterConversationPreview::onOpen(const LLSD& session_id)
|
||||
{
|
||||
const LLConversation* conv = LLConversationLog::instance().getConversation(session_id);
|
||||
if (!conv)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::list<LLSD> messages;
|
||||
std::string file = conv->getHistoryFileName();
|
||||
LLLogChat::loadAllHistory(file, messages);
|
||||
|
||||
if (messages.size())
|
||||
{
|
||||
std::ostringstream message;
|
||||
std::list<LLSD>::const_iterator iter = messages.begin();
|
||||
for (; iter != messages.end(); ++iter)
|
||||
{
|
||||
LLSD msg = *iter;
|
||||
|
||||
std::string time = msg["time"].asString();
|
||||
LLUUID from_id = msg["from_id"].asUUID();
|
||||
std::string from = msg["from"].asString();
|
||||
std::string message = msg["message"].asString();
|
||||
bool is_history = msg["is_history"].asBoolean();
|
||||
|
||||
LLChat chat;
|
||||
chat.mFromID = from_id;
|
||||
chat.mSessionID = session_id;
|
||||
chat.mFromName = from;
|
||||
chat.mTimeStr = time;
|
||||
chat.mChatStyle = is_history ? CHAT_STYLE_HISTORY : chat.mChatStyle;
|
||||
chat.mText = message;
|
||||
|
||||
appendMessage(chat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterConversationPreview::appendMessage(const LLChat& chat)
|
||||
{
|
||||
if (!chat.mMuted)
|
||||
{
|
||||
LLSD args;
|
||||
args["use_plain_text_chat_history"] = true;
|
||||
args["show_time"] = true;
|
||||
args["show_names_for_p2p_conv"] = true;
|
||||
|
||||
mChatHistory->appendMessage(chat);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @file llfloaterconversationpreview.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLFLOATERCONVERSATIONPREVIEW_H_
|
||||
#define LLFLOATERCONVERSATIONPREVIEW_H_
|
||||
|
||||
#include "llchathistory.h"
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLFloaterConversationPreview : public LLFloater
|
||||
{
|
||||
public:
|
||||
|
||||
LLFloaterConversationPreview(const LLSD& session_id);
|
||||
virtual ~LLFloaterConversationPreview(){};
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
virtual void draw();
|
||||
virtual void onOpen(const LLSD& session_id);
|
||||
|
||||
private:
|
||||
void appendMessage(const LLChat& chat);
|
||||
|
||||
LLChatHistory* mChatHistory;
|
||||
LLUUID mSessionID;
|
||||
};
|
||||
|
||||
#endif /* LLFLOATERCONVERSATIONPREVIEW_H_ */
|
||||
|
|
@ -60,6 +60,8 @@
|
|||
#include "llnotificationmanager.h"
|
||||
#include "llautoreplace.h"
|
||||
|
||||
floater_showed_signal_t LLIMFloater::sIMFloaterShowedSignal;
|
||||
|
||||
LLIMFloater::LLIMFloater(const LLUUID& session_id)
|
||||
: LLIMConversation(session_id),
|
||||
mLastMessageIndex(-1),
|
||||
|
|
@ -771,6 +773,11 @@ void LLIMFloater::setVisible(BOOL visible)
|
|||
chiclet->setToggleState(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (visible)
|
||||
{
|
||||
sIMFloaterShowedSignal(mSessionID);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLIMFloater::getVisible()
|
||||
|
|
@ -1340,3 +1347,8 @@ void LLIMFloater::addToHost(const LLUUID& session_id)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::signals2::connection LLIMFloater::setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb)
|
||||
{
|
||||
return LLIMFloater::sIMFloaterShowedSignal.connect(cb);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ class LLChatHistory;
|
|||
class LLInventoryItem;
|
||||
class LLInventoryCategory;
|
||||
|
||||
typedef boost::signals2::signal<void(const LLUUID& session_id)> floater_showed_signal_t;
|
||||
|
||||
/**
|
||||
* Individual IM window that appears at the bottom of the screen,
|
||||
* optionally "docked" to the bottom tray.
|
||||
|
|
@ -125,7 +127,11 @@ public:
|
|||
|
||||
bool getStartConferenceInSameFloater() const { return mStartConferenceInSameFloater; }
|
||||
|
||||
static boost::signals2::connection setIMFloaterShowedCallback(const floater_showed_signal_t::slot_type& cb);
|
||||
static floater_showed_signal_t sIMFloaterShowedSignal;
|
||||
|
||||
private:
|
||||
|
||||
// process focus events to set a currently active session
|
||||
/* virtual */ void onFocusLost();
|
||||
/* virtual */ void onFocusReceived();
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ BOOL LLIMFloaterContainer::postBuild()
|
|||
p.rect = mConversationsListPanel->getLocalRect();
|
||||
p.follows.flags = FOLLOWS_ALL;
|
||||
p.listener = base_item;
|
||||
p.root = NULL;
|
||||
|
||||
mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
|
||||
mConversationsListPanel->addChild(mConversationsRoot);
|
||||
|
|
|
|||
|
|
@ -175,10 +175,11 @@ LLIMModel::LLIMModel()
|
|||
addNewMsgCallback(boost::bind(&toast_callback, _1));
|
||||
}
|
||||
|
||||
LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice)
|
||||
LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg)
|
||||
: mSessionID(session_id),
|
||||
mName(name),
|
||||
mType(type),
|
||||
mHasOfflineMessage(has_offline_msg),
|
||||
mParticipantUnreadMessageCount(0),
|
||||
mNumUnread(0),
|
||||
mOtherParticipantID(other_participant_id),
|
||||
|
|
@ -375,6 +376,8 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES
|
|||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Update speakers list when connected
|
||||
if (LLVoiceChannel::STATE_CONNECTED == new_state)
|
||||
|
|
@ -676,7 +679,7 @@ void LLIMModel::testMessages()
|
|||
|
||||
//session name should not be empty
|
||||
bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,
|
||||
const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice)
|
||||
const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg)
|
||||
{
|
||||
if (name.empty())
|
||||
{
|
||||
|
|
@ -690,7 +693,7 @@ bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, co
|
|||
return false;
|
||||
}
|
||||
|
||||
LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice);
|
||||
LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids, voice, has_offline_msg);
|
||||
mId2SessionMap[session_id] = session;
|
||||
|
||||
// When notifying observer, name of session is used instead of "name", because they may not be the
|
||||
|
|
@ -702,10 +705,10 @@ bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, co
|
|||
|
||||
}
|
||||
|
||||
bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice)
|
||||
bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, bool voice, bool has_offline_msg)
|
||||
{
|
||||
uuid_vec_t no_ids;
|
||||
return newSession(session_id, name, type, other_participant_id, no_ids, voice);
|
||||
return newSession(session_id, name, type, other_participant_id, no_ids, voice, has_offline_msg);
|
||||
}
|
||||
|
||||
bool LLIMModel::clearSession(const LLUUID& session_id)
|
||||
|
|
@ -2398,6 +2401,7 @@ void LLIMMgr::addMessage(
|
|||
const LLUUID& target_id,
|
||||
const std::string& from,
|
||||
const std::string& msg,
|
||||
bool is_offline_msg,
|
||||
const std::string& session_name,
|
||||
EInstantMessage dialog,
|
||||
U32 parent_estate_id,
|
||||
|
|
@ -2423,7 +2427,7 @@ void LLIMMgr::addMessage(
|
|||
bool new_session = !hasSession(new_session_id);
|
||||
if (new_session)
|
||||
{
|
||||
LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id);
|
||||
LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg);
|
||||
|
||||
// When we get a new IM, and if you are a god, display a bit
|
||||
// of information about the source. This is to help liaisons
|
||||
|
|
@ -3307,6 +3311,7 @@ public:
|
|||
from_id,
|
||||
name,
|
||||
buffer,
|
||||
IM_OFFLINE == offline,
|
||||
std::string((char*)&bin_bucket[0]),
|
||||
IM_SESSION_INVITE,
|
||||
message_params["parent_estate_id"].asInteger(),
|
||||
|
|
|
|||
|
|
@ -70,10 +70,11 @@ public:
|
|||
GROUP_SESSION,
|
||||
ADHOC_SESSION,
|
||||
AVALINE_SESSION,
|
||||
NONE_SESSION,
|
||||
} SType;
|
||||
|
||||
LLIMSession(const LLUUID& session_id, const std::string& name,
|
||||
const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice);
|
||||
const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg);
|
||||
virtual ~LLIMSession();
|
||||
|
||||
void sessionInitReplyReceived(const LLUUID& new_session_id);
|
||||
|
|
@ -133,6 +134,8 @@ public:
|
|||
//if IM session is created for a voice call
|
||||
bool mStartedAsIMCall;
|
||||
|
||||
bool mHasOfflineMessage;
|
||||
|
||||
private:
|
||||
void onAdHocNameCache(const LLAvatarName& av_name);
|
||||
|
||||
|
|
@ -181,10 +184,10 @@ public:
|
|||
* @param name session name should not be empty, will return false if empty
|
||||
*/
|
||||
bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id,
|
||||
const uuid_vec_t& ids, bool voice = false);
|
||||
const uuid_vec_t& ids, bool voice = false, bool has_offline_msg = false);
|
||||
|
||||
bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,
|
||||
const LLUUID& other_participant_id, bool voice = false);
|
||||
const LLUUID& other_participant_id, bool voice = false, bool has_offline_msg = false);
|
||||
|
||||
/**
|
||||
* Remove all session data associated with a session specified by session_id
|
||||
|
|
@ -325,6 +328,7 @@ public:
|
|||
const LLUUID& target_id,
|
||||
const std::string& from,
|
||||
const std::string& msg,
|
||||
bool is_offline_msg = false,
|
||||
const std::string& session_name = LLStringUtil::null,
|
||||
EInstantMessage dialog = IM_NOTHING_SPECIAL,
|
||||
U32 parent_estate_id = 0,
|
||||
|
|
|
|||
|
|
@ -659,6 +659,7 @@ LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool u
|
|||
p.allow_multiselect = mAllowMultiSelect;
|
||||
p.show_empty_message = mShowEmptyMessage;
|
||||
p.show_item_link_overlays = mShowItemLinkOverlays;
|
||||
p.root = NULL;
|
||||
|
||||
return LLUICtrlFactory::create<LLFolderView>(p);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1563,6 +1563,7 @@ void LLPanelObjectInventory::reset()
|
|||
p.listener = LLTaskInvFVBridge::createObjectBridge(this, NULL);
|
||||
p.folder_indentation = -14; // subtract space normally reserved for folder expanders
|
||||
p.view_model = &mInventoryViewModel;
|
||||
p.root = NULL;
|
||||
mFolders = LLUICtrlFactory::create<LLFolderView>(p);
|
||||
// this ensures that we never say "searching..." or "no items found"
|
||||
//TODO RN: make this happen by manipulating filter object directly
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
#include "llcallingcard.h"
|
||||
#include "llconsole.h"
|
||||
#include "llcontainerview.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "lldebugview.h"
|
||||
#include "lldrawable.h"
|
||||
#include "lleventnotifier.h"
|
||||
|
|
@ -1268,6 +1269,8 @@ bool idle_startup()
|
|||
display_startup();
|
||||
LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
|
||||
|
||||
LLConversationLog::getInstance();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@
|
|||
#include "llfloaterbump.h"
|
||||
#include "llfloaterbvhpreview.h"
|
||||
#include "llfloatercamera.h"
|
||||
#include "llfloaterconversationlog.h"
|
||||
#include "llfloaterconversationpreview.h"
|
||||
#include "llfloaterdeleteenvpreset.h"
|
||||
#include "llfloaterdisplayname.h"
|
||||
#include "llfloatereditdaycycle.h"
|
||||
|
|
@ -189,6 +191,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCamera>);
|
||||
LLFloaterReg::add("chat_bar", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLNearbyChat>);
|
||||
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
|
||||
LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);
|
||||
|
||||
LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>);
|
||||
|
||||
|
|
@ -262,6 +265,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("picks", "floater_picks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>);
|
||||
LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>);
|
||||
LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewAnim>, "preview");
|
||||
LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationPreview>);
|
||||
LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewGesture>, "preview");
|
||||
LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewNotecard>, "preview");
|
||||
LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLPreviewLSL>, "preview");
|
||||
|
|
|
|||
|
|
@ -2438,6 +2438,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
|||
from_id,
|
||||
name,
|
||||
buffer,
|
||||
IM_OFFLINE == offline,
|
||||
LLStringUtil::null,
|
||||
dialog,
|
||||
parent_estate_id,
|
||||
|
|
@ -2477,7 +2478,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
|||
if (!gIMMgr->isNonFriendSessionNotified(session_id))
|
||||
{
|
||||
std::string message = LLTrans::getString("IM_unblock_only_groups_friends");
|
||||
gIMMgr->addMessage(session_id, from_id, name, message);
|
||||
gIMMgr->addMessage(session_id, from_id, name, message, IM_OFFLINE == offline);
|
||||
gIMMgr->addNotifiedNonFriendSessionID(session_id);
|
||||
}
|
||||
|
||||
|
|
@ -2490,6 +2491,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
|||
from_id,
|
||||
name,
|
||||
buffer,
|
||||
IM_OFFLINE == offline,
|
||||
LLStringUtil::null,
|
||||
dialog,
|
||||
parent_estate_id,
|
||||
|
|
@ -2830,6 +2832,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
|
|||
from_id,
|
||||
name,
|
||||
buffer,
|
||||
IM_OFFLINE == offline,
|
||||
ll_safe_string((char*)binary_bucket),
|
||||
IM_SESSION_INVITE,
|
||||
parent_estate_id,
|
||||
|
|
|
|||
|
|
@ -3964,6 +3964,7 @@ void LLVivoxVoiceClient::messageEvent(
|
|||
session->mCallerID,
|
||||
session->mName.c_str(),
|
||||
message.c_str(),
|
||||
false,
|
||||
LLStringUtil::null, // default arg
|
||||
IM_NOTHING_SPECIAL, // default arg
|
||||
0, // default arg
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
|
||||
<floater
|
||||
can_resize="true"
|
||||
positioning="cascading"
|
||||
height="400"
|
||||
min_height="100"
|
||||
min_width="390"
|
||||
layout="topleft"
|
||||
name="floater_conversation_log"
|
||||
save_rect="true"
|
||||
single_instance="true"
|
||||
reuse_instance="true"
|
||||
title="CONVERSATION LOG"
|
||||
width="450">
|
||||
<panel
|
||||
follows="left|top|right"
|
||||
height="27"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="buttons_panel"
|
||||
top="0">
|
||||
<filter_editor
|
||||
follows="left|top|right"
|
||||
height="23"
|
||||
layout="topleft"
|
||||
left="8"
|
||||
label="Filter People"
|
||||
max_length_chars="300"
|
||||
name="people_filter_input"
|
||||
text_color="Black"
|
||||
text_pad_left="10"
|
||||
top="4"
|
||||
width="364" />
|
||||
<menu_button
|
||||
follows="right"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_overlay="Conv_toolbar_sort"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
menu_filename="menu_conversation_log_view.xml"
|
||||
menu_position="bottomleft"
|
||||
name="conversation_view_btn"
|
||||
top="3"
|
||||
width="31" />
|
||||
<menu_button
|
||||
follows="right"
|
||||
height="25"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_overlay="OptionsMenu_Off"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
layout="topleft"
|
||||
left_pad="2"
|
||||
name="conversations_gear_btn"
|
||||
top="3"
|
||||
width="31" />
|
||||
</panel>
|
||||
<panel
|
||||
follows="all"
|
||||
height="370"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
name="buttons_panel"
|
||||
right="-5"
|
||||
top_pad="5">
|
||||
<conversation_log_list
|
||||
opaque="true"
|
||||
allow_select="true"
|
||||
follows="all"
|
||||
height="360"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
keep_selection_visible_on_reshape="true"
|
||||
item_pad="2"
|
||||
multi_select="false"
|
||||
name="conversation_log_list"
|
||||
right="-3"
|
||||
top="5" />
|
||||
</panel>
|
||||
</floater>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
legacy_header_height="18"
|
||||
can_resize="true"
|
||||
default_tab_group="1"
|
||||
height="361"
|
||||
layout="topleft"
|
||||
min_height="243"
|
||||
min_width="234"
|
||||
name="preview_conversation"
|
||||
title="CONVERSATION:"
|
||||
width="400">
|
||||
<floater.string
|
||||
name="Title">
|
||||
CONVERSATION: [NAME]
|
||||
</floater.string>
|
||||
<text
|
||||
type="string"
|
||||
length="1"
|
||||
follows="left|top"
|
||||
font="SansSerif"
|
||||
height="19"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="desc txt"
|
||||
top="22"
|
||||
width="90">
|
||||
Description:
|
||||
</text>
|
||||
<line_editor
|
||||
border_style="line"
|
||||
border_thickness="1"
|
||||
enabled="false"
|
||||
follows="left|top|right"
|
||||
font="SansSerif"
|
||||
height="22"
|
||||
layout="topleft"
|
||||
left_pad="0"
|
||||
max_length_bytes="127"
|
||||
name="description"
|
||||
width="296" />
|
||||
<chat_history
|
||||
font="SansSerifSmall"
|
||||
follows="all"
|
||||
visible="true"
|
||||
height="310"
|
||||
name="chat_history"
|
||||
parse_highlights="true"
|
||||
parse_urls="true"
|
||||
left="5"
|
||||
width="390">
|
||||
</chat_history>
|
||||
</floater>
|
||||
|
|
@ -56,6 +56,7 @@
|
|||
image_overlay="Conv_toolbar_sort"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
menu_filename="menu_participant_view.xml"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="sort_btn"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<toggleable_menu
|
||||
layout="topleft"
|
||||
name="Conversation Context Menu">
|
||||
<menu_item_call
|
||||
label="IM..."
|
||||
layout="topleft"
|
||||
name="IM">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="im" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_im" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Voice call..."
|
||||
layout="topleft"
|
||||
name="Call">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="call" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_call" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Open chat history..."
|
||||
layout="topleft"
|
||||
name="Chat history">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="chat_history" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_view_chat_history" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="View Profile"
|
||||
layout="topleft"
|
||||
name="View Profile">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="view_profile" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_view_profile" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Offer Teleport"
|
||||
name="teleport">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="offer_teleport"/>
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_offer_teleport"/>
|
||||
</menu_item_call>
|
||||
<menu_item_separator />
|
||||
<menu_item_check
|
||||
label="Add friend/Remove friend"
|
||||
layout="topleft"
|
||||
name="Friend_add_remove">
|
||||
<menu_item_check.on_click
|
||||
function="Calllog.Action"
|
||||
parameter="add_rem_friend" />
|
||||
<menu_item_check.on_check
|
||||
function="Calllog.Check"
|
||||
parameter="is_friend" />
|
||||
<menu_item_check.on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="add_rem_friend" />
|
||||
</menu_item_check>
|
||||
<menu_item_call
|
||||
label="Invite to group..."
|
||||
layout="topleft"
|
||||
name="Invite">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="invite_to_group"/>
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_invite_to_group" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator />
|
||||
<menu_item_call
|
||||
label="Map"
|
||||
layout="topleft"
|
||||
name="Map">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="show_on_map" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_show_on_map" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Share"
|
||||
layout="topleft"
|
||||
name="Share">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="share" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_share" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Pay"
|
||||
layout="topleft"
|
||||
name="Pay">
|
||||
<on_click
|
||||
function="Calllog.Action"
|
||||
parameter="pay" />
|
||||
<on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_pay" />
|
||||
</menu_item_call>
|
||||
<menu_item_check
|
||||
label="Block/Unblock"
|
||||
layout="topleft"
|
||||
name="Block/Unblock">
|
||||
<menu_item_check.on_click
|
||||
function="Calllog.Action"
|
||||
parameter="block"/>
|
||||
<menu_item_check.on_check
|
||||
function="Calllog.Check"
|
||||
parameter="is_blocked" />
|
||||
<menu_item_check.on_enable
|
||||
function="Calllog.Enable"
|
||||
parameter="can_block" />
|
||||
</menu_item_check>
|
||||
|
||||
</toggleable_menu>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<toggleable_menu
|
||||
name="menu_conversation_view"
|
||||
left="0" bottom="0" visible="false"
|
||||
mouse_opaque="false">
|
||||
<menu_item_check
|
||||
label="Sort by name"
|
||||
name="sort_by_name">
|
||||
<on_click
|
||||
function="CallLog.Action"
|
||||
parameter="sort_by_name"/>
|
||||
<on_check
|
||||
function="CallLog.Check"
|
||||
parameter="sort_by_name"/>
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Sort by date"
|
||||
name="sort_by_date">
|
||||
<on_click
|
||||
function="CallLog.Action"
|
||||
parameter="sort_by_date" />
|
||||
<on_check
|
||||
function="CallLog.Check"
|
||||
parameter="sort_by_date" />
|
||||
</menu_item_check>
|
||||
<menu_item_separator />
|
||||
<menu_item_check
|
||||
label="Sort friends on top"
|
||||
name="sort_by_friends">
|
||||
<on_click
|
||||
function="CallLog.Action"
|
||||
parameter="sort_friends_on_top" />
|
||||
<on_check
|
||||
function="CallLog.Check"
|
||||
parameter="sort_friends_on_top" />
|
||||
</menu_item_check>
|
||||
</toggleable_menu>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<toggleable_menu
|
||||
layout="topleft"
|
||||
name="participant_manu_view">
|
||||
<menu_item_check
|
||||
label="Open conversation log"
|
||||
name="Conversation"
|
||||
visible="true">
|
||||
<menu_item_check.on_check
|
||||
function="Floater.Visible"
|
||||
parameter="conversation" />
|
||||
<menu_item_check.on_click
|
||||
function="Floater.Toggle"
|
||||
parameter="conversation" />
|
||||
</menu_item_check>
|
||||
</toggleable_menu>
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<panel
|
||||
follows="top|right|left"
|
||||
height="23"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="conversation_log_list_item"
|
||||
top="0"
|
||||
width="380">
|
||||
<icon
|
||||
height="24"
|
||||
follows="top|right|left"
|
||||
image_name="ListItem_Select"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="selected_icon"
|
||||
top="0"
|
||||
visible="false"
|
||||
width="380" />
|
||||
<icon
|
||||
follows="top|right|left"
|
||||
height="24"
|
||||
image_name="ListItem_Over"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
name="hovered_icon"
|
||||
top="0"
|
||||
visible="false"
|
||||
width="380" />
|
||||
<icon
|
||||
default_icon_name="voice_session_icon"
|
||||
follows="top|left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
image_name="Audio_Press"
|
||||
mouse_opaque="true"
|
||||
name="voice_session_icon"
|
||||
top="2"
|
||||
visible="false"
|
||||
width="20" />
|
||||
<icon
|
||||
default_icon_name="incoming_unread_im_icon"
|
||||
follows="top|left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
image_name="Movement_Backward_Off"
|
||||
mouse_opaque="false"
|
||||
name="unread_ims_icon"
|
||||
top="2"
|
||||
visible="false"
|
||||
width="20" />
|
||||
<avatar_icon
|
||||
default_icon_name="Generic_Person"
|
||||
follows="top|left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
mouse_opaque="true"
|
||||
top="2"
|
||||
visible="false"
|
||||
width="20" />
|
||||
<group_icon
|
||||
default_icon_name="Generic_Group"
|
||||
follows="top|left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
mouse_opaque="true"
|
||||
top="2"
|
||||
visible="false"
|
||||
width="20" />
|
||||
<text
|
||||
follows="left|right"
|
||||
font="SansSerifSmall"
|
||||
font.color="DkGray"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
name="conversation_name"
|
||||
parse_urls="false"
|
||||
top="6"
|
||||
use_ellipses="true"
|
||||
width="180" />
|
||||
<text
|
||||
follows="right"
|
||||
font="SansSerifSmall"
|
||||
font.color="DkGray"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
left_pad="5"
|
||||
name="date_time"
|
||||
parse_urls="false"
|
||||
top="6"
|
||||
use_ellipses="true"
|
||||
width="110"/>
|
||||
<button
|
||||
name="delete_btn"
|
||||
layout="topleft"
|
||||
follows="top|right"
|
||||
image_unselected="Toast_CloseBtn"
|
||||
image_selected="Toast_CloseBtn"
|
||||
top="5"
|
||||
left_pad="0"
|
||||
height="14"
|
||||
width="14"
|
||||
tab_stop="false"/>
|
||||
</panel>
|
||||
Loading…
Reference in New Issue