Experience log panel

master
dolphin 2014-03-20 16:32:31 -07:00
parent b2591ca63c
commit dba034ee10
12 changed files with 660 additions and 95 deletions

View File

@ -26,3 +26,212 @@
#include "llviewerprecompiledheaders.h"
#include "llexperiencelog.h"
#include "lldispatcher.h"
#include "llsdserialize.h"
#include "llviewergenericmessage.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llerror.h"
#include "lldate.h"
class LLExperienceLogDispatchHandler : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
LLSD message;
sparam_t::const_iterator it = strings.begin();
if(it != strings.end()){
const std::string& llsdRaw = *it++;
std::istringstream llsdData(llsdRaw);
if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
{
llwarns << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << llendl;
}
}
message["public_id"] = invoice;
// Object Name
if(it != strings.end())
{
message["ObjectName"] = *it++;
}
// parcel Name
if(it != strings.end())
{
message["ParcelName"] = *it++;
}
LLExperienceLog::instance().handleExperienceMessage(message);
return true;
}
};
static LLExperienceLogDispatchHandler experience_log_dispatch_handler;
void LLExperienceLog::handleExperienceMessage(LLSD& message)
{
time_t now;
time(&now);
char day[16];/* Flawfinder: ignore */
char time_of_day[16];/* Flawfinder: ignore */
strftime(day, 16, "%Y-%m-%d", localtime(&now));
strftime(time_of_day, 16, " %H:%M:%S", localtime(&now));
message["Time"] = time_of_day;
if(mNotifyNewEvent)
{
notify(message);
}
if(!mEvents.has(day)){
mEvents[day] = LLSD::emptyArray();
}
mEvents[day].append(message);
}
LLExperienceLog::LLExperienceLog()
: mMaxDays(7)
, mPageSize(25)
, mNotifyNewEvent(false)
{
}
void LLExperienceLog::initialize()
{
loadEvents();
if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent"))
{
gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler);
}
}
std::string LLExperienceLog::getFilename()
{
return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml");
}
std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base )
{
std::ostringstream buf;
if(message.has("Permission"))
{
buf << base << message["Permission"].asInteger();
std::string entry;
if(LLTrans::findString(entry, buf.str()))
{
buf.str(entry);
}
else
{
buf.str();
}
}
if(buf.str().empty())
{
buf << base << "Unknown";
buf.str(LLTrans::getString(buf.str(), message));
}
return buf.str();
}
void LLExperienceLog::notify( LLSD& message )
{
message["EventType"] = getPermissionString(message, "ExperiencePermission");
if(message.has("IsAttachment") && message["IsAttachment"].asBoolean())
{
LLNotificationsUtil::add("ExperienceEventAttachment", message);
}
else
{
LLNotificationsUtil::add("ExperienceEvent", message);
}
message.erase("EventType");
}
void LLExperienceLog::saveEvents()
{
eraseExpired();
std::string filename = getFilename();
LLSD settings = LLSD::emptyMap().with("Events", mEvents);
settings["MaxDays"] = (int)mMaxDays;
settings["Notify"] = mNotifyNewEvent;
settings["PageSize"] = (int)mPageSize;
llofstream stream(filename);
LLSDSerialize::toPrettyXML(settings, stream);
}
void LLExperienceLog::loadEvents()
{
LLSD settings = LLSD::emptyMap();
std::string filename = getFilename();
llifstream stream(filename);
LLSDSerialize::fromXMLDocument(settings, stream);
if(settings.has("MaxDays"))
{
mMaxDays = (U32)settings["MaxDays"].asInteger();
}
if(settings.has("Notify"))
{
mNotifyNewEvent = settings["Notify"].asBoolean();
}
if(settings.has("PageSize"))
{
mPageSize = (U32)settings["PageSize"].asInteger();
}
mEvents.clear();
if(mMaxDays > 0 && settings.has("Events"))
{
mEvents = settings["Events"];
}
eraseExpired();
}
LLExperienceLog::~LLExperienceLog()
{
saveEvents();
}
void LLExperienceLog::eraseExpired()
{
while(mEvents.size() > mMaxDays && mMaxDays > 0)
{
mEvents.erase(mEvents.beginMap()->first);
}
}
const LLSD& LLExperienceLog::getEvents() const
{
return mEvents;
}
void LLExperienceLog::clear()
{
mEvents.clear();
}
void LLExperienceLog::setMaxDays( U32 val )
{
mMaxDays = val;
if(mMaxDays > 0)
{
eraseExpired();
}
}

View File

@ -29,5 +29,49 @@
#ifndef LL_LLEXPERIENCELOG_H
#define LL_LLEXPERIENCELOG_H
#include "llsingleton.h"
class LLExperienceLog : public LLSingleton<LLExperienceLog>
{
public:
void initialize();
U32 getMaxDays() const { return mMaxDays; }
void setMaxDays(U32 val);
bool getNotifyNewEvent() const { return mNotifyNewEvent; }
void setNotifyNewEvent(bool val) { mNotifyNewEvent = val; }
U32 getPageSize() const { return mPageSize; }
void setPageSize(U32 val) { mPageSize = val; }
const LLSD& getEvents()const;
void clear();
virtual ~LLExperienceLog();
static void notify(LLSD& message);
static std::string getFilename();
static std::string getPermissionString(const LLSD& message, const std::string& base);
protected:
LLExperienceLog();
void handleExperienceMessage(LLSD& message);
void loadEvents();
void saveEvents();
void eraseExpired();
LLSD mEvents;
U32 mMaxDays;
U32 mPageSize;
bool mNotifyNewEvent;
friend class LLExperienceLogDispatchHandler;
friend class LLSingleton<LLExperienceLog>;
};
#endif // LL_LLEXPERIENCELOG_H

View File

@ -35,6 +35,7 @@
#include "llexperiencecache.h"
#include "llevents.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
@ -115,6 +116,7 @@ BOOL LLFloaterExperiences::postBuild()
#if SHOW_RECENT_TAB
addTab("Recent_Experiences_Tab", false);
#endif //SHOW_RECENT_TAB
getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperienceLog());
resizeToTabs();

View File

@ -248,7 +248,7 @@ void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
}
LLUICtrl* details = getChild<LLUICtrl>("details_edit");
details->setValue(desc.str());
details->setValue(details->getValue().asString()+desc.str());
}
}
@ -497,7 +497,7 @@ void LLFloaterReporter::showFromMenu(EReportType report_type)
}
// static
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name)
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name, const LLUUID& experience_id)
{
LLFloaterReporter* f = LLFloaterReg::showTypedInstance<LLFloaterReporter>("reporter");
@ -510,6 +510,10 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
{
f->setFromAvatarID(object_id);
}
if(experience_id.notNull())
{
f->getExperienceInfo(experience_id);
}
// Need to deselect on close
f->mDeselectOnClose = TRUE;
@ -532,9 +536,9 @@ void LLFloaterReporter::showFromExperience( const LLUUID& experience_id )
// static
void LLFloaterReporter::showFromObject(const LLUUID& object_id)
void LLFloaterReporter::showFromObject(const LLUUID& object_id, const LLUUID& experience_id)
{
show(object_id);
show(object_id, LLStringUtil::null, experience_id);
}
// static

View File

@ -88,7 +88,7 @@ public:
// Enables all buttons
static void showFromMenu(EReportType report_type);
static void showFromObject(const LLUUID& object_id);
static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null);
static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name);
static void showFromExperience(const LLUUID& experience_id);
@ -107,7 +107,7 @@ public:
void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id);
private:
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null);
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null);
void takeScreenshot();
void sendReportViaCaps(std::string url);

View File

@ -27,92 +27,224 @@
#include "llviewerprecompiledheaders.h"
#include "llpanelexperiencelog.h"
#include "lldispatcher.h"
#include "llsdserialize.h"
#include "llviewergenericmessage.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llexperiencelog.h"
#include "llexperiencecache.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llcombobox.h"
#include "llspinctrl.h"
#include "llcheckboxctrl.h"
#include "llfloaterreg.h"
#include "llfloaterreporter.h"
#include "llinventoryfunctions.h"
class LLExperienceLogDispatchHandler : public LLDispatchHandler
#define BTN_PROFILE_XP "btn_profile_xp"
#define BTN_REPORT_XP "btn_report_xp"
static LLPanelInjector<LLPanelExperienceLog> register_experiences_panel("experience_log");
LLPanelExperienceLog::LLPanelExperienceLog( )
: mEventList(NULL)
, mPageSize(25)
, mCurrentPage(0)
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings)
{
LLSD message;
buildFromFile("panel_experience_log.xml");
}
sparam_t::const_iterator it = strings.begin();
if(it != strings.end()){
const std::string& llsdRaw = *it++;
std::istringstream llsdData(llsdRaw);
if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
BOOL LLPanelExperienceLog::postBuild( void )
{
LLExperienceLog* log = LLExperienceLog::getInstance();
mEventList = getChild<LLScrollListCtrl>("experience_log_list");
mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this));
getChild<LLButton>(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
getChild<LLButton>(BTN_REPORT_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this));
getChild<LLButton>("btn_notify")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this));
getChild<LLButton>("btn_next")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this));
getChild<LLButton>("btn_prev")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this));
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("notify_all");
check->set(log->getNotifyNewEvent());
check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this));
LLSpinCtrl* spin = getChild<LLSpinCtrl>("logsizespinner");
spin->set(log->getMaxDays());
spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this));
mPageSize = log->getPageSize();
refresh();
return TRUE;
}
LLPanelExperienceLog* LLPanelExperienceLog::create()
{
return new LLPanelExperienceLog();
}
void LLPanelExperienceLog::refresh()
{
mEventList->deleteAllItems();
const LLSD& events = LLExperienceLog::instance().getEvents();
if(events.size() == 0)
{
mEventList->setCommentText(getString("no_events"));
return;
}
setAllChildrenEnabled(FALSE);
LLSD item;
bool waiting = false;
LLUUID waiting_id;
int itemsToSkip = mPageSize*mCurrentPage;
int items = 0;
bool moreItems = false;
for(LLSD::map_const_iterator day = events.beginMap(); day != events.endMap() ; ++day)
{
const LLSD& dayArray = day->second;
int size = dayArray.size();
if(itemsToSkip > size)
{
itemsToSkip -= size;
continue;
}
if(items >= mPageSize && size > 0)
{
moreItems = true;
break;
}
for(int i = itemsToSkip ; i < dayArray.size(); i++)
{
if(items >= mPageSize)
{
llwarns << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << llendl;
moreItems = true;
break;
}
}
message["public_id"] = invoice;
const LLSD& event = dayArray[i];
LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
const LLSD& experience = LLExperienceCache::get(id);
if(experience.isUndefined()){
waiting = true;
waiting_id = id;
}
if(!waiting)
{
item["id"] = event;
// Object Name
if(it != strings.end())
{
message["ObjectName"] = *it++;
}
// parcel Name
if(it != strings.end())
{
message["ParcelName"] = *it++;
}
LLExperienceLog::instance().handleExperienceMessage(message);
return true;
}
};
static LLExperienceLogDispatchHandler experience_log_dispatch_handler;
void LLExperienceLog::handleExperienceMessage(LLSD& message)
{
std::ostringstream str;
if(message.has("Permission"))
{
str << "ExperiencePermission" << message["Permission"].asInteger();
std::string entry;
if(LLTrans::findString(entry, str.str()))
{
str.str(entry);
}
else
{
str.str();
LLSD& columns = item["columns"];
columns[0]["column"] = "time";
columns[0]["value"] = day->first+event["Time"].asString();
columns[1]["column"] = "event";
columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
columns[2]["column"] = "experience_name";
columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
columns[3]["column"] = "object_name";
columns[3]["value"] = event["ObjectName"].asString();
mEventList->addElement(item);
}
++items;
}
}
if(str.str().empty())
if(waiting)
{
str.str(LLTrans::getString("ExperiencePermissionUnknown", message));
}
message["EventType"] = str.str();
if(message.has("IsAttachment") && message["IsAttachment"].asBoolean())
{
LLNotificationsUtil::add("ExperienceEventAttachment", message);
mEventList->deleteAllItems();
mEventList->setCommentText(getString("loading"));
LLExperienceCache::get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
}
else
{
LLNotificationsUtil::add("ExperienceEvent", message);
setAllChildrenEnabled(TRUE);
mEventList->setEnabled(TRUE);
getChild<LLButton>("btn_next")->setEnabled(moreItems);
getChild<LLButton>("btn_prev")->setEnabled(mCurrentPage>0);
getChild<LLButton>("btn_clear")->setEnabled(mEventList->getItemCount()>0);
onSelectionChanged();
}
}
LLExperienceLog::LLExperienceLog()
void LLPanelExperienceLog::onProfileExperience()
{
LLSD& event = getSelectedEvent();
if(event.isDefined())
{
LLFloaterReg::showInstance("experience_profile", event[LLExperienceCache::EXPERIENCE_ID].asUUID(), true);
}
}
void LLExperienceLog::initialize()
void LLPanelExperienceLog::onReportExperience()
{
gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler);
LLSD& event = getSelectedEvent();
if(event.isDefined())
{
LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID());
}
}
void LLPanelExperienceLog::onNotify()
{
LLSD& event = getSelectedEvent();
if(event.isDefined())
{
LLExperienceLog::instance().notify(event);
}
}
void LLPanelExperienceLog::onNext()
{
mCurrentPage++;
refresh();
}
void LLPanelExperienceLog::onPrev()
{
if(mCurrentPage>0)
{
mCurrentPage--;
refresh();
}
}
void LLPanelExperienceLog::notifyChanged()
{
LLExperienceLog::instance().setNotifyNewEvent(getChild<LLCheckBoxCtrl>("notify_all")->get());
}
void LLPanelExperienceLog::logSizeChanged()
{
int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get());
bool dirty = value > 0 && value < LLExperienceLog::instance().getMaxDays();
LLExperienceLog::instance().setMaxDays(value);
if(dirty)
{
refresh();
}
}
void LLPanelExperienceLog::onSelectionChanged()
{
bool enabled = (1 == mEventList->getNumSelected());
getChild<LLButton>(BTN_REPORT_XP)->setEnabled(enabled);
getChild<LLButton>(BTN_PROFILE_XP)->setEnabled(enabled);
getChild<LLButton>("btn_notify")->setEnabled(enabled);
}
LLSD LLPanelExperienceLog::getSelectedEvent()
{
LLScrollListItem* item = mEventList->getFirstSelected();
if(item)
{
return item->getValue();
}
return LLSD();
}

View File

@ -25,24 +25,38 @@
*/
#ifndef LL_LLPANELEXPERIENCELOG_H
#define LL_LLPANELEXPERIENCELOG_H
#include "llsingleton.h"
#include "llpanel.h"
class LLScrollListCtrl;
class LLExperienceLog : public LLSingleton<LLExperienceLog>
class LLPanelExperienceLog
: public LLPanel
{
friend class LLSingleton<LLExperienceLog>;
protected:
LLExperienceLog();
public:
void initialize();
void handleExperienceMessage(LLSD& message);
LLPanelExperienceLog();
static LLPanelExperienceLog* create();
/*virtual*/ BOOL postBuild(void);
void refresh();
protected:
void logSizeChanged();
void notifyChanged();
void onNext();
void onNotify();
void onPrev();
void onProfileExperience();
void onReportExperience();
void onSelectionChanged();
LLSD getSelectedEvent();
private:
LLScrollListCtrl* mEventList;
U32 mPageSize;
U32 mCurrentPage;
};
#endif // LL_LLPANELEXPERIENCELOG_H

View File

@ -198,7 +198,7 @@
#include "llevents.h"
#include "llstartuplistener.h"
#include "lltoolbarview.h"
#include "llpanelexperiencelog.h"
#include "llexperiencelog.h"
#if LL_WINDOWS
#include "lldxhardware.h"
@ -1303,6 +1303,9 @@ bool idle_startup()
// object is created. I think this must be done after setting the region. JC
gAgent.setPositionAgent(agent_start_position_region);
display_startup();
LLStartUp::initExperiences();
display_startup();
LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
@ -1413,9 +1416,6 @@ bool idle_startup()
LLStartUp::initNameCache();
display_startup();
LLStartUp::initExperiences();
display_startup();
// update the voice settings *after* gCacheName initialization
// so that we can construct voice UI that relies on the name cache
LLVoiceClient::getInstance()->updateSettings();

View File

@ -410,9 +410,9 @@
label="Report Abuse"
layout="topleft"
name="report_btn"
width="288"
width="94"
top_pad="3"
left="10"
left="107"
enabled="true"/>
</layout_panel>
</layout_stack>

View File

@ -7074,7 +7074,7 @@ Unable to acquire a new experience:
icon="notify.tga"
name="ExperienceEvent"
persist="false"
type="notify">
type="notifytip">
An object was allowed to [EventType] by the secondlife:///app/experience/[public_id]/profile experience.
Owner: secondlife:///app/agent/[OwnerID]/inspect
Object Name: [ObjectName]
@ -7085,7 +7085,7 @@ Unable to acquire a new experience:
icon="notify.tga"
name="ExperienceEventAttachment"
persist="false"
type="notify">
type="notifytip">
An attachment was allowed to [EventType] by the secondlife:///app/experience/[public_id]/profile experience.
Owner: secondlife:///app/agent/[OwnerID]/inspect
</notification>

View File

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<panel
layout="topleft"
top="3"
left="3"
width="500"
height="300"
label="EVENTS"
bg_opaque_color="0 0.5 0 0.3"
follows="all">
<string
name="no_events"
value="No events."/>
<string
name="loading"
value="loading..."/>
<layout_stack
layout="topleft"
top="0"
left="4"
right="-1"
bottom="-4"
orientation="vertical"
follows="all">
<layout_panel
layout="topleft"
top="0"
left="1"
right="-1"
height="250"
follows="all">
<scroll_list
draw_heading="true"
left="1"
right="-86"
height="250"
follows="all"
name="experience_log_list">
<columns
width="100"
user_resize="true"
name="time"
label="Time"/>
<columns
width="100"
user_resize="true"
name="event"
label="Event"/>
<columns
width="100"
user_resize="true"
name="experience_name"
label="Experience"/>
<columns
width="100"
user_resize="true"
name="object_name"
label="Object"/>
</scroll_list>
<button
layout="topleft"
follows="top|right"
name="btn_notify"
label="Notify"
top_pad="-225"
left_pad="5"
right="-1"
enabled="false"/>
<button
layout="topleft"
follows="top|right"
name="btn_profile_xp"
label="Profile"
top_pad="5"
right="-1"
enabled="false"/>
<button
layout="topleft"
follows="top|right"
name="btn_report_xp"
label="Report"
top_pad="5"
right="-1"
enabled="false"/>
</layout_panel>
<layout_panel
layout="topleft"
top="0"
left="1"
right="-1"
height="30"
min_height="30"
follows="all"
name="button_panel"
visible="true">
<check_box
top="0"
follows="top|left"
height="26"
label="Notify All Events Days"
width="140"
name="notify_all" />
<spinner
top="5"
control_name="LogDays"
decimal_digits="0"
follows="left|top"
height="23"
increment="1"
initial_value="7"
label_width="30"
layout="topleft"
left_pad="5"
max_val="14"
min_val="0"
name="logsizespinner"
width="40" />
<button
top="5"
left="280"
layout="topleft"
follows="top|left"
name="btn_clear"
label="Clear"
width="80"
enabled="false"/>
<button
top="5"
layout="topleft"
left_pad="5"
width="20"
follows="top|left"
name="btn_prev"
label="&lt;"
enabled="false"/>
<button
top="5"
layout="topleft"
follows="top|left"
name="btn_next"
label="&gt;"
left_pad="5"
width="20"
enabled="false"/>
</layout_panel>
</layout_stack>
</panel>

View File

@ -3992,7 +3992,15 @@ Try enclosing path to the editor with double quotes.
<string name="ExperiencePermission10">control your camera</string>
<string name="ExperiencePermission11">teleport you</string>
<string name="ExperiencePermission12">automatically accept experience permissions</string>
<string name="ExperiencePermissionUnknown">perform an unknown operation: [Permission]</string>
<string name="ExperiencePermissionShortUnknown">perform an unknown operation: [Permission]</string>
<string name="ExperiencePermissionShort1">Take Controls</string>
<string name="ExperiencePermissionShort3">Override Animations</string>
<string name="ExperiencePermissionShort4">Attach</string>
<string name="ExperiencePermissionShort9">Track Camera</string>
<string name="ExperiencePermissionShort10">Control Camera</string>
<string name="ExperiencePermissionShort11">Teleport</string>
<string name="ExperiencePermissionShort12">Permission</string>
<string name="ExperiencePermissionShortUnknown">Unknown: [Permission]</string>
<!-- Conversation log messages -->
<string name="logging_calls_disabled_log_empty">