From 37411bc7ebc5a34e8c9a5c43471291224a3cd35a Mon Sep 17 00:00:00 2001
From: dolphin <dolphin@lindenlab.com>
Date: Fri, 21 Mar 2014 16:58:43 -0700
Subject: Experience log panel is live and updates as new events come in.
 Multiple identical events get collapsed int a single entry.

---
 indra/newview/llexperiencelog.cpp              | 54 +++++++++++++++++++++-----
 indra/newview/llexperiencelog.h                | 10 ++++-
 indra/newview/llpanelexperiencelog.cpp         | 17 ++++++--
 indra/newview/llpanelexperiencelog.h           |  2 +
 indra/newview/skins/default/xui/en/strings.xml |  4 +-
 5 files changed, 71 insertions(+), 16 deletions(-)

diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp
index 110ce46835..5f9fab306b 100644
--- a/indra/newview/llexperiencelog.cpp
+++ b/indra/newview/llexperiencelog.cpp
@@ -69,6 +69,7 @@ public:
 		{
 			message["ParcelName"] = *it++;
 		}
+		message["Count"] = 1;
 
 		LLExperienceLog::instance().handleExperienceMessage(message);
 		return true;
@@ -81,20 +82,37 @@ void LLExperienceLog::handleExperienceMessage(LLSD& message)
 {
 	time_t now;
 	time(&now);
-	char day[16];/* Flawfinder: ignore */
+	char daybuf[16];/* Flawfinder: ignore */
 	char time_of_day[16];/* Flawfinder: ignore */
-	strftime(day, 16, "%Y-%m-%d", localtime(&now));
+	strftime(daybuf, 16, "%Y-%m-%d", localtime(&now));
 	strftime(time_of_day, 16, " %H:%M:%S", localtime(&now));
 	message["Time"] = time_of_day;
 
-	if(mNotifyNewEvent)
+	std::string day = daybuf;
+
+	if(!mEvents.has(day))
 	{
-		notify(message);
-	}
-	if(!mEvents.has(day)){
 		mEvents[day] = LLSD::emptyArray();
 	}
+	LLSD& dayEvents = mEvents[day];
+	if(dayEvents.size() > 0)
+	{
+		LLSD& last = *(dayEvents.rbeginArray());
+		if( last["public_id"].asUUID() == message["public_id"].asUUID() 
+			&& last["ObjectName"].asString() == message["ObjectName"].asString() 
+			&& last["OwnerID"].asUUID() == message["OwnerID"].asUUID()
+			&& last["ParcelName"].asString() == message["ParcelName"].asString()
+			&& last["Permission"].asInteger() == message["Permission"].asInteger())
+		{
+			last["Count"] = last["Count"].asInteger() + 1;
+			last["Time"] = time_of_day;
+			mSignals(last);
+			return;
+		}
+	}
+	message["Time"] = time_of_day;
 	mEvents[day].append(message);
+	mSignals(message);
 }
 
 LLExperienceLog::LLExperienceLog()
@@ -185,15 +203,15 @@ void LLExperienceLog::loadEvents()
 
 	if(settings.has("MaxDays"))
 	{
-		mMaxDays = (U32)settings["MaxDays"].asInteger();
+		setMaxDays((U32)settings["MaxDays"].asInteger());
 	}
 	if(settings.has("Notify"))
 	{
-		mNotifyNewEvent = settings["Notify"].asBoolean();
+		setNotifyNewEvent(settings["Notify"].asBoolean());
 	}
 	if(settings.has("PageSize"))
 	{
-		mPageSize = (U32)settings["PageSize"].asInteger();
+		setPageSize((U32)settings["PageSize"].asInteger());
 	}
 	mEvents.clear();
 	if(mMaxDays > 0 && settings.has("Events"))
@@ -235,3 +253,21 @@ void LLExperienceLog::setMaxDays( U32 val )
 		eraseExpired();
 	}
 }
+
+LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( callback_slot_t cb )
+{
+	return mSignals.connect(cb);
+}
+
+void LLExperienceLog::setNotifyNewEvent( bool val )
+{
+	mNotifyNewEvent = val;
+	if(!val && mNotifyConnection.connected())
+	{
+		mNotifyConnection.disconnect();
+	}
+	else if( val && !mNotifyConnection.connected())
+	{
+		mNotifyConnection = addUpdateSignal(notify);
+	}
+}
diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h
index 26ffab49f9..5bc47c4e8d 100644
--- a/indra/newview/llexperiencelog.h
+++ b/indra/newview/llexperiencelog.h
@@ -34,13 +34,19 @@
 class LLExperienceLog : public LLSingleton<LLExperienceLog>
 {
 public:
+	typedef boost::signals2::signal<void(LLSD&)> 
+		callback_signal_t;
+	typedef callback_signal_t::slot_type callback_slot_t;
+	typedef boost::signals2::connection callback_connection_t;
+	callback_connection_t addUpdateSignal(callback_slot_t cb);
+
 	void initialize();
 
 	U32 getMaxDays() const { return mMaxDays; }
 	void setMaxDays(U32 val);
 
 	bool getNotifyNewEvent() const { return mNotifyNewEvent; }
-	void setNotifyNewEvent(bool val) { mNotifyNewEvent = val; }
+	void setNotifyNewEvent(bool val);
 
 	U32 getPageSize() const { return mPageSize; }
 	void setPageSize(U32 val) { mPageSize = val; }
@@ -63,6 +69,8 @@ protected:
 	void eraseExpired();
 
 	LLSD mEvents;
+	callback_signal_t mSignals;
+	callback_connection_t mNotifyConnection;
 	U32 mMaxDays;
 	U32 mPageSize;
 	bool mNotifyNewEvent;
diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp
index e0e522e276..eeabab4c44 100644
--- a/indra/newview/llpanelexperiencelog.cpp
+++ b/indra/newview/llpanelexperiencelog.cpp
@@ -54,20 +54,22 @@ LLPanelExperienceLog::LLPanelExperienceLog(  )
 	buildFromFile("panel_experience_log.xml");
 }
 
+
 BOOL LLPanelExperienceLog::postBuild( void )
 {
 	LLExperienceLog* log = LLExperienceLog::getInstance();
 	mEventList = getChild<LLScrollListCtrl>("experience_log_list");
 	mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this));
+	mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
 
 	getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log));
 	getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this));
 
 	getChild<LLButton>(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
-	getChild<LLButton>(BTN_REPORT_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this));
-	getChild<LLButton>("btn_notify")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this));
-	getChild<LLButton>("btn_next")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this));
-	getChild<LLButton>("btn_prev")->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this));
+	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());
@@ -80,6 +82,7 @@ BOOL LLPanelExperienceLog::postBuild( void )
 
 	mPageSize = log->getPageSize();
 	refresh();
+	mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this));
 	return TRUE;
 }
 
@@ -90,6 +93,7 @@ LLPanelExperienceLog* LLPanelExperienceLog::create()
 
 void LLPanelExperienceLog::refresh()
 {
+	S32 selected = mEventList->getFirstSelectedIndex();
 	mEventList->deleteAllItems();
 	const LLSD& events = LLExperienceLog::instance().getEvents();
 
@@ -169,6 +173,11 @@ void LLPanelExperienceLog::refresh()
 		getChild<LLButton>("btn_next")->setEnabled(moreItems);
 		getChild<LLButton>("btn_prev")->setEnabled(mCurrentPage>0);
 		getChild<LLButton>("btn_clear")->setEnabled(mEventList->getItemCount()>0);
+		if(selected<0)
+		{
+			selected = 0;
+		}
+		mEventList->selectNthItem(selected);
 		onSelectionChanged();
 	}
 }
diff --git a/indra/newview/llpanelexperiencelog.h b/indra/newview/llpanelexperiencelog.h
index e4edd216d5..4135d9cac9 100644
--- a/indra/newview/llpanelexperiencelog.h
+++ b/indra/newview/llpanelexperiencelog.h
@@ -35,6 +35,7 @@ class LLPanelExperienceLog
 	: public LLPanel 
 {
 public:
+
 	LLPanelExperienceLog();
 
 	static LLPanelExperienceLog* create();
@@ -57,6 +58,7 @@ private:
 	LLScrollListCtrl* mEventList;
 	U32 mPageSize;
 	U32 mCurrentPage;
+	boost::signals2::scoped_connection mNewEvent;
 };
 
 #endif // LL_LLPANELEXPERIENCELOG_H
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 37aaf941af..a17a895b42 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -3986,7 +3986,7 @@ Try enclosing path to the editor with double quotes.
   <string name="Recent_Experiences_Tab">RECENT</string>
   <string name="Owned_Experiences_Tab">OWNED</string>
   <string name="ExperiencePermission1">take over your controls</string>
-  <string name="ExperiencePermission3">override animations on your avatar</string>
+  <string name="ExperiencePermission3">trigger animations on your avatar</string>
   <string name="ExperiencePermission4">attach to your avatar</string>
   <string name="ExperiencePermission9">track your camera</string>
   <string name="ExperiencePermission10">control your camera</string>
@@ -3994,7 +3994,7 @@ Try enclosing path to the editor with double quotes.
   <string name="ExperiencePermission12">automatically accept experience permissions</string>
   <string name="ExperiencePermissionShortUnknown">perform an unknown operation: [Permission]</string>
   <string name="ExperiencePermissionShort1">Take Controls</string>
-  <string name="ExperiencePermissionShort3">Override Animations</string>
+  <string name="ExperiencePermissionShort3">Trigger Animations</string>
   <string name="ExperiencePermissionShort4">Attach</string>
   <string name="ExperiencePermissionShort9">Track Camera</string>
   <string name="ExperiencePermissionShort10">Control Camera</string>
-- 
cgit v1.2.3