summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordolphin <dolphin@lindenlab.com>2014-02-04 15:54:41 -0800
committerdolphin <dolphin@lindenlab.com>2014-02-04 15:54:41 -0800
commitd74119ec2bf5d98adce52291a2f82c1fed0aee30 (patch)
tree7e0a65162e557a4a8f925c38446186b4ed6fc30e
parent88d0281121b4913f17931b8f5f537570b9198f29 (diff)
Added an experience tab to the region floater
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llfloaterexperiencepicker.cpp129
-rw-r--r--indra/newview/llfloaterexperiencepicker.h25
-rwxr-xr-xindra/newview/llfloaterregioninfo.cpp162
-rwxr-xr-xindra/newview/llfloaterregioninfo.h31
-rw-r--r--indra/newview/llpanelexperiencelisteditor.cpp213
-rw-r--r--indra/newview/llpanelexperiencelisteditor.h96
-rwxr-xr-xindra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/floater_experience_search.xml2
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_list_editor.xml63
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_experiences.xml74
11 files changed, 780 insertions, 18 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 09746f4b2c..621413a729 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -403,6 +403,7 @@ set(viewer_SOURCE_FILES
llpanelclassified.cpp
llpanelcontents.cpp
llpaneleditwearable.cpp
+ llpanelexperiencelisteditor.cpp
llpanelexperiences.cpp
llpanelface.cpp
llpanelgenerictip.cpp
@@ -989,6 +990,7 @@ set(viewer_HEADER_FILES
llpanelclassified.h
llpanelcontents.h
llpaneleditwearable.h
+ llpanelexperiencelisteditor.h
llpanelexperiences.h
llpanelface.h
llpanelgenerictip.h
diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp
index 6d0ceedb0d..fd2cb31ee4 100644
--- a/indra/newview/llfloaterexperiencepicker.cpp
+++ b/indra/newview/llfloaterexperiencepicker.cpp
@@ -40,6 +40,8 @@
#include "llavatarnamecache.h"
#include "llfloaterexperienceprofile.h"
#include "llcombobox.h"
+#include "llviewercontrol.h"
+#include "lldraghandle.h"
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
@@ -80,7 +82,7 @@ public:
}
}
};
-LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL closeOnSelect )
+LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL closeOnSelect, LLView * frustumOrigin )
{
LLFloaterExperiencePicker* floater =
LLFloaterReg::showTypedInstance<LLFloaterExperiencePicker>("experience_search", key);
@@ -93,14 +95,91 @@ LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t ca
floater->mSelectionCallback = callback;
floater->mCloseOnSelect = closeOnSelect;
floater->setAllowMultiple(allow_multiple);
+
+ if(frustumOrigin)
+ {
+ floater->mFrustumOrigin = frustumOrigin->getHandle();
+ }
+
return floater;
}
+void LLFloaterExperiencePicker::drawFrustum()
+{
+ if(mFrustumOrigin.get())
+ {
+ LLView * frustumOrigin = mFrustumOrigin.get();
+ LLRect origin_rect;
+ frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
+ // draw context cone connecting color picker with color swatch in parent floater
+ LLRect local_rect = getLocalRect();
+ if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable(GL_CULL_FACE);
+ gGL.begin(LLRender::QUADS);
+ {
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+ gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+ gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+ gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+ gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
+
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mTop);
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+ gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
+ gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
+ gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
+ gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
+ gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
+ gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
+ gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
+ }
+ gGL.end();
+ }
+
+ if (gFocusMgr.childHasMouseCapture(getDragHandle()))
+ {
+ mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+ }
+ else
+ {
+ mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
+ }
+ }
+}
+
+void LLFloaterExperiencePicker::draw()
+{
+ drawFrustum();
+ LLFloater::draw();
+}
+
LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
:LLFloater(key)
+ ,mContextConeOpacity (0.f)
+ ,mContextConeInAlpha(0.f)
+ ,mContextConeOutAlpha(0.f)
+ ,mContextConeFadeTime(0.f)
{
+ setDefaultFilters();
+ mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
+ mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
+ mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
@@ -219,7 +298,8 @@ void LLFloaterExperiencePicker::find()
bool LLFloaterExperiencePicker::isSelectButtonEnabled()
{
- return getChild<LLScrollListCtrl>(LIST_RESULTS)->getFirstSelectedIndex() >=0;
+ LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
+ return list->getFirstSelectedIndex() >=0;
}
void LLFloaterExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids )
@@ -306,17 +386,15 @@ void LLFloaterExperiencePicker::filterContent()
search_results->deleteAllItems();
- int maturity = getChild<LLComboBox>(TEXT_MATURITY)->getSelectedValue().asInteger();
LLSD item;
LLSD::array_const_iterator it = experiences.beginArray();
for ( ; it != experiences.endArray(); ++it)
{
const LLSD& experience = *it;
- if(experience[LLExperienceCache::MATURITY].asInteger() > maturity)
+ if(isExperienceHidden(experience))
continue;
-
item["id"]=experience[LLExperienceCache::EXPERIENCE_ID];
LLSD& columns = item["columns"];
columns[0]["column"] = "maturity";
@@ -335,11 +413,7 @@ void LLFloaterExperiencePicker::filterContent()
{
LLStringUtil::format_map_t map;
map["[TEXT]"] = childGetText(TEXT_EDIT);
- LLSD item;
- item["id"] = LLUUID::null;
- item["columns"][1]["column"] = "name";
- item["columns"][1]["value"] = columnSpace+getString("not_found", map);
- search_results->addElement(item);
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("not_found", map));
search_results->setEnabled(false);
getChildView(BTN_OK)->setEnabled(false);
getChildView(BTN_PROFILE)->setEnabled(false);
@@ -364,6 +438,41 @@ void LLFloaterExperiencePicker::onMaturity()
filterContent();
}
+bool LLFloaterExperiencePicker::isExperienceHidden( const LLSD& experience) const
+{
+ bool hide=false;
+ filter_list::const_iterator it = mFilters.begin();
+ for(/**/;it != mFilters.end(); ++it)
+ {
+ if((*it)(experience)){
+ return true;
+ }
+ }
+
+ return hide;
+}
+
+bool LLFloaterExperiencePicker::FilterOverRating( const LLSD& experience )
+{
+ int maturity = getChild<LLComboBox>(TEXT_MATURITY)->getSelectedValue().asInteger();
+ return experience[LLExperienceCache::MATURITY].asInteger() > maturity;
+}
+
+bool LLFloaterExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop )
+{
+ return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0;
+}
+
+void LLFloaterExperiencePicker::setDefaultFilters()
+{
+ mFilters.clear();
+ addFilter(boost::bind(&LLFloaterExperiencePicker::FilterOverRating, this, _1));
+}
+
+
+
+
+
diff --git a/indra/newview/llfloaterexperiencepicker.h b/indra/newview/llfloaterexperiencepicker.h
index 72085b8b32..7f2083c6d9 100644
--- a/indra/newview/llfloaterexperiencepicker.h
+++ b/indra/newview/llfloaterexperiencepicker.h
@@ -40,15 +40,26 @@ public:
// The callback function will be called with an avatar name and UUID.
typedef boost::function<void (const uuid_vec_t&)> select_callback_t;
+ // filter function for experiences, return true if the experience should be hidden.
+ typedef boost::function<bool (const LLSD&)> filter_function;
+ typedef std::vector<filter_function> filter_list;
- static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL closeOnSelect );
+ static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL closeOnSelect, LLView * frustumOrigin);
LLFloaterExperiencePicker(const LLSD& key);
virtual ~LLFloaterExperiencePicker();
BOOL postBuild();
+ void addFilter(filter_function func){mFilters.push_back(func);}
+ template <class IT>
+ void addFilters(IT begin, IT end){mFilters.insert(mFilters.end(), begin, end);}
+ void setDefaultFilters();
+ static bool FilterWithProperty(const LLSD& experience, S32 prop);
+ bool FilterOverRating(const LLSD& experience);
+
+ virtual void draw();
private:
void editKeystroke(LLLineEditor* caller, void* user_data);
@@ -68,13 +79,23 @@ private:
void processResponse( const LLUUID& query_id, const LLSD& content );
void filterContent();
+ bool isExperienceHidden(const LLSD& experience) const ;
std::string getMaturityString(int maturity);
select_callback_t mSelectionCallback;
- bool mCloseOnSelect;
+ filter_list mFilters;
LLUUID mQueryID;
LLSD mResponse;
+ bool mCloseOnSelect;
+
+
+ void drawFrustum();
+ LLHandle <LLView> mFrustumOrigin;
+ F32 mContextConeOpacity;
+ F32 mContextConeInAlpha;
+ F32 mContextConeOutAlpha;
+ F32 mContextConeFadeTime;
};
#endif // LL_LLFLOATEREXPERIENCEPICKER_H
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 66bf49331b..edaca68da3 100755
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -91,6 +91,10 @@
#include "lltrans.h"
#include "llagentui.h"
#include "llmeshrepository.h"
+#include "llpanelexperiencelisteditor.h"
+#include <boost/function.hpp>
+#include "llfloaterexperiencepicker.h"
+#include "llexperiencecache.h"
const S32 TERRAIN_TEXTURE_COUNT = 4;
const S32 CORNER_COUNT = 4;
@@ -214,6 +218,14 @@ BOOL LLFloaterRegionInfo::postBuild()
panel->buildFromFile("panel_region_debug.xml");
mTab->addTabPanel(panel);
+ if(!gAgent.getRegion()->getCapability("RegionExperiences").empty())
+ {
+ panel = new LLPanelRegionExperiences;
+ mInfoPanels.push_back(panel);
+ panel->buildFromFile("panel_region_experiences.xml");
+ mTab->addTabPanel(panel);
+ }
+
gMessageSystem->setHandlerFunc(
"EstateOwnerMessage",
&processEstateOwnerRequest);
@@ -3463,3 +3475,153 @@ void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok)
LLEnvManagerNew::instance().requestRegionSettings();
}
}
+
+BOOL LLPanelRegionExperiences::postBuild()
+{
+ mAllowed = setupList("panel_allowed");
+ mTrusted = setupList("panel_trusted");
+ mBlocked = setupList("panel_blocked");
+ return LLPanelRegionInfo::postBuild();
+}
+
+LLPanelExperienceListEditor* LLPanelRegionExperiences::setupList( const char* control_name )
+{
+ LLPanelExperienceListEditor* child = findChild<LLPanelExperienceListEditor>(control_name);
+ child->getChild<LLTextBox>("text_name")->setText(getString(control_name));
+
+ return child;
+}
+
+
+
+
+boost::signals2::connection LLPanelRegionExperiences::processResponse( LLPanelExperienceListEditor* panel, boost::signals2::connection& conn, const LLSD& content )
+{
+ if(conn.connected())
+ {
+ conn.disconnect();
+ }
+ panel->setExperienceIds(content);
+
+ return panel->setChangedCallback(boost::bind(&LLPanelRegionExperiences::listChanged, this));
+}
+
+
+
+void LLPanelRegionExperiences::processResponse( const LLSD& content )
+{
+ mAllowedConnection=processResponse(mAllowed, mAllowedConnection, content["allowed"]);
+ mBlockedConnection=processResponse(mBlocked, mBlockedConnection, content["blocked"]);
+ mTrustedConnection=processResponse(mTrusted, mTrustedConnection, content["trusted"]);
+ disableButton("apply_btn");
+}
+
+
+class LLRegionExperienceResponder : public LLHTTPClient::Responder
+{
+public:
+ typedef boost::function<void (const LLSD&)> callback_t;
+
+ callback_t mCallback;
+
+ LLRegionExperienceResponder(callback_t callback) : mCallback(callback) { }
+
+ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ mCallback(content);
+ }
+ else
+ {
+ llwarns << "experience responder failed [status:" << status << "]: " << content << llendl;
+ }
+ }
+};
+
+
+void LLPanelRegionExperiences::infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content)
+{
+
+ if(handle.isDead())
+ return;
+
+ LLPanelRegionExperiences* floater = handle.get();
+ if (floater)
+ {
+ floater->processResponse(content);
+ }
+}
+
+
+bool LLPanelRegionExperiences::FilterExisting(const LLSD& experience)
+{
+ LLUUID id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
+ return mAllowed->getExperienceIds().find(id) != mAllowed->getExperienceIds().end() ||
+ mBlocked->getExperienceIds().find(id) != mBlocked->getExperienceIds().end() ||
+ mTrusted->getExperienceIds().find(id) != mTrusted->getExperienceIds().end() ;
+}
+
+
+bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region)
+{
+ BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
+
+ mAllowed->loading();
+ mAllowed->setReadonly(!allow_modify);
+ mAllowed->addFilter(boost::bind(LLFloaterExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID));
+ mAllowed->addFilter(boost::bind(&LLPanelRegionExperiences::FilterExisting, this, _1));
+
+ mBlocked->loading();
+ mBlocked->setReadonly(!allow_modify);
+ mBlocked->addFilter(boost::bind(LLFloaterExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_PRIVILEGED));
+ mBlocked->addFilter(boost::bind(&LLPanelRegionExperiences::FilterExisting, this, _1));
+
+ mTrusted->loading();
+ mTrusted->setReadonly(!allow_modify);
+ mTrusted->addFilter(boost::bind(&LLPanelRegionExperiences::FilterExisting, this, _1));
+
+ std::string url = region->getCapability("RegionExperiences");
+ if (!url.empty())
+ {
+ LLHTTPClient::get(url, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
+ getDerivedHandle<LLPanelRegionExperiences>(), _1)));
+ }
+ return LLPanelRegionInfo::refreshFromRegion(region);
+}
+
+LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel)
+{
+ LLSD ids;
+ const uuid_list_t& id_list = panel->getExperienceIds();
+ for(uuid_list_t::const_iterator it = id_list.begin(); it != id_list.end(); ++it)
+ {
+ ids.append(*it);
+ }
+ return ids;
+}
+
+
+BOOL LLPanelRegionExperiences::sendUpdate()
+{
+ LLViewerRegion* region = gAgent.getRegion();
+ std::string url = region->getCapability("RegionExperiences");
+ if (!url.empty())
+ {
+ LLSD content;
+
+ content["allowed"]=addIds(mAllowed);
+ content["blocked"]=addIds(mBlocked);
+ content["trusted"]=addIds(mTrusted);
+
+ LLHTTPClient::post(url, content, new LLRegionExperienceResponder(boost::bind(&LLPanelRegionExperiences::infoCallback,
+ getDerivedHandle<LLPanelRegionExperiences>(), _1)));
+ }
+
+ return TRUE;
+}
+
+void LLPanelRegionExperiences::listChanged()
+{
+ onChangeAnything();
+}
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index f0499f1903..ccd42f9764 100755
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -60,6 +60,7 @@ class LLPanelRegionDebugInfo;
class LLPanelRegionTerrainInfo;
class LLPanelEstateInfo;
class LLPanelEstateCovenant;
+class LLPanelExperienceListEditor;
class LLEventTimer;
class LLEnvironmentSettings;
@@ -450,4 +451,34 @@ private:
LLComboBox* mDayCyclePresetCombo;
};
+class LLPanelRegionExperiences : public LLPanelRegionInfo
+{
+ LOG_CLASS(LLPanelEnvironmentInfo);
+
+public:
+ LLPanelRegionExperiences(){}
+ /*virtual*/ BOOL postBuild();
+ virtual BOOL sendUpdate();
+
+ static void infoCallback(LLHandle<LLPanelRegionExperiences> handle, const LLSD& content);
+
+ void listChanged();
+ bool refreshFromRegion(LLViewerRegion* region);
+private:
+ void processResponse( const LLSD& content );
+ boost::signals2::connection processResponse( LLPanelExperienceListEditor* panel, boost::signals2::connection& connection, const LLSD& content);
+ void refreshRegionExperiences();
+
+ LLPanelExperienceListEditor* setupList(const char* control_name);
+ static LLSD addIds( LLPanelExperienceListEditor* panel );
+ bool FilterExisting(const LLSD& experience );
+
+ LLPanelExperienceListEditor* mTrusted;
+ boost::signals2::connection mTrustedConnection;
+ LLPanelExperienceListEditor* mAllowed;
+ boost::signals2::connection mAllowedConnection;
+ LLPanelExperienceListEditor* mBlocked;
+ boost::signals2::connection mBlockedConnection;
+};
+
#endif
diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp
new file mode 100644
index 0000000000..374f89afad
--- /dev/null
+++ b/indra/newview/llpanelexperiencelisteditor.cpp
@@ -0,0 +1,213 @@
+/**
+ * @file llpanelexperiencelisteditor.cpp
+ * @brief Editor for building a list of experiences
+ *
+ * $LicenseInfo:firstyear=2014&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanelexperiencelisteditor.h"
+
+#include "llbutton.h"
+#include "llexperiencecache.h"
+#include "llfloaterexperiencepicker.h"
+#include "llfloaterreg.h"
+#include "llhandle.h"
+#include "llscrolllistctrl.h"
+#include "llviewerregion.h"
+#include "llagent.h"
+
+
+static LLRegisterPanelClassWrapper<LLPanelExperienceListEditor> t_panel_experience_list_editor("panel_experience_list_editor");
+
+
+LLPanelExperienceListEditor::LLPanelExperienceListEditor()
+ :mItems(NULL)
+ ,mProfile(NULL)
+ ,mRemove(NULL)
+ ,mChangedCallback(NULL)
+ ,mReadonly(false)
+{
+}
+
+BOOL LLPanelExperienceListEditor::postBuild()
+{
+ mItems = getChild<LLScrollListCtrl>("experience_list");
+ mAdd = getChild<LLButton>("btn_add");
+ mRemove = getChild<LLButton>("btn_remove");
+ mProfile = getChild<LLButton>("btn_profile");
+
+ childSetAction("btn_add", boost::bind(&LLPanelExperienceListEditor::onAdd, this));
+ childSetAction("btn_remove", boost::bind(&LLPanelExperienceListEditor::onRemove, this));
+ childSetAction("btn_profile", boost::bind(&LLPanelExperienceListEditor::onProfile, this));
+
+ mItems->setCommitCallback(boost::bind(&LLPanelExperienceListEditor::checkButtonsEnabled, this));
+
+ checkButtonsEnabled();
+ return TRUE;
+}
+
+const uuid_list_t& LLPanelExperienceListEditor::getExperienceIds() const
+{
+ return mExperienceIds;
+}
+
+void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience_ids )
+{
+ mExperienceIds.insert(experience_ids.begin(), experience_ids.end());
+ onItems();
+}
+
+
+void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids )
+{
+ mExperienceIds.clear();
+ mExperienceIds.insert(experience_ids.beginArray(), experience_ids.endArray());
+ onItems();
+}
+
+void LLPanelExperienceListEditor::addExperience( const LLUUID& id )
+{
+ mExperienceIds.insert(id);
+ onItems();
+}
+void LLPanelExperienceListEditor::onAdd()
+{
+ if(!mPicker.isDead())
+ {
+ mPicker.get()->setFrontmost(TRUE);
+ }
+ else
+ {
+ mKey.generateNewID();
+
+ LLFloaterExperiencePicker* picker=LLFloaterExperiencePicker::show(boost::bind(&LLPanelExperienceListEditor::addExperienceIds, this, _1), mKey, FALSE, TRUE, mAdd);
+ picker->addFilters(mFilters.begin(), mFilters.end());
+
+ mPicker = picker->getDerivedHandle<LLFloaterExperiencePicker>();
+ }
+}
+
+
+void LLPanelExperienceListEditor::onRemove()
+{
+ std::vector<LLScrollListItem*> items= mItems->getAllSelected();
+ std::vector<LLScrollListItem*>::iterator it = items.begin();
+ for(/**/; it != items.end(); ++it)
+ {
+ if((*it) != NULL)
+ {
+ mExperienceIds.erase((*it)->getValue());
+ }
+ }
+ onItems();
+}
+
+void LLPanelExperienceListEditor::onProfile()
+{
+ LLScrollListItem* item = mItems->getFirstSelected();
+ if(item)
+ {
+ LLFloaterReg::showInstance("experience_profile", item->getUUID(), true);
+ }
+}
+
+void LLPanelExperienceListEditor::checkButtonsEnabled()
+{
+ mAdd->setEnabled(!mReadonly);
+ int selected = mItems->getNumSelected();
+ mRemove->setEnabled(!mReadonly && selected>0);
+ mProfile->setEnabled(selected==1);
+}
+
+void LLPanelExperienceListEditor::onItems()
+{
+ mItems->deleteAllItems();
+
+ LLSD item;
+ uuid_list_t::iterator it = mExperienceIds.begin();
+ for(/**/; it != mExperienceIds.end(); ++it)
+ {
+ const LLUUID& experience = *it;
+ item["id"]=experience;
+ LLSD& columns = item["columns"];
+ columns[0]["column"] = "experience_name";
+ columns[0]["value"] = getString("loading");
+ mItems->addElement(item);
+
+ LLExperienceCache::get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
+ getDerivedHandle<LLPanelExperienceListEditor>(), _1));
+ }
+
+
+ if(mItems->getItemCount() == 0)
+ {
+ mItems->setCommentText(getString("no_results"));
+ }
+
+
+ checkButtonsEnabled();
+ if(mChangedCallback)
+ {
+ (*mChangedCallback)();
+ }
+}
+
+void LLPanelExperienceListEditor::experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience )
+{
+ if(!panel.isDead())
+ {
+ panel.get()->onExperienceDetails(experience);
+ }
+}
+
+void LLPanelExperienceListEditor::onExperienceDetails( const LLSD& experience )
+{
+ LLScrollListItem* item = mItems->getItem(experience[LLExperienceCache::EXPERIENCE_ID]);
+ if(!item)
+ return;
+
+ item->getColumn(0)->setValue(experience[LLExperienceCache::NAME]);
+}
+
+LLPanelExperienceListEditor::~LLPanelExperienceListEditor()
+{
+ if(!mPicker.isDead())
+ {
+ mPicker.get()->closeFloater();
+ }
+ delete mChangedCallback;
+}
+
+void LLPanelExperienceListEditor::loading()
+{
+ mItems->clear();
+ mItems->setCommentText( getString("loading"));
+}
+
+void LLPanelExperienceListEditor::setReadonly( bool val )
+{
+ mReadonly = val;
+ setCtrlsEnabled(!mReadonly);
+ checkButtonsEnabled();
+}
diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h
new file mode 100644
index 0000000000..4135f399ce
--- /dev/null
+++ b/indra/newview/llpanelexperiencelisteditor.h
@@ -0,0 +1,96 @@
+/**
+* @file llpanelexperiencelisteditor.cpp
+* @brief Editor for building a list of experiences
+*
+* $LicenseInfo:firstyear=2014&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELEXPERIENCELISTEDITOR_H
+#define LL_LLPANELEXPERIENCELISTEDITOR_H
+
+#include "llpanel.h"
+#include "lluuid.h"
+#include <set>
+
+class LLScrollListCtrl;
+class LLButton;
+class LLFloaterExperiencePicker;
+
+class LLPanelExperienceListEditor : public LLPanel
+{
+public:
+
+ typedef boost::signals2::signal<void () > list_changed_signal_t;
+ // filter function for experiences, return true if the experience should be hidden.
+ typedef boost::function<bool (const LLSD&)> filter_function;
+ typedef std::vector<filter_function> filter_list;
+ typedef LLHandle<LLFloaterExperiencePicker> PickerHandle;
+ LLPanelExperienceListEditor();
+ ~LLPanelExperienceListEditor();
+ BOOL postBuild();
+
+ void loading();
+
+ const uuid_list_t& getExperienceIds()const;
+ void setExperienceIds(const LLSD& experience_ids);
+ void addExperienceIds(const uuid_vec_t& experience_ids);
+
+ void addExperience(const LLUUID& id);
+
+ boost::signals2::connection setChangedCallback(list_changed_signal_t::slot_type cb )
+ {
+ if (!mChangedCallback) mChangedCallback = new list_changed_signal_t();
+ return mChangedCallback->connect(cb);
+ }
+
+ bool getReadonly() const { return mReadonly; }
+ void setReadonly(bool val);
+
+
+ void addFilter(filter_function func){mFilters.push_back(func);}
+private:
+
+ void onItems();
+ void onRemove();
+ void onAdd();
+ void onProfile();
+
+ void checkButtonsEnabled();
+ static void experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience );
+ void onExperienceDetails( const LLSD& experience );
+ void processResponse( const LLSD& content );
+ uuid_list_t mExperienceIds;
+
+
+ LLScrollListCtrl* mItems;
+ filter_list mFilters;
+ LLButton* mAdd;
+ LLButton* mRemove;
+ LLButton* mProfile;
+ PickerHandle mPicker;
+ list_changed_signal_t* mChangedCallback;
+ LLUUID mKey;
+ bool mReadonly;
+
+};
+
+#endif //LL_LLPANELEXPERIENCELISTEDITOR_H
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index f209f16516..454f83f713 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1609,6 +1609,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("UpdateExperience");
capabilityNames.append("IsExperienceAdmin");
capabilityNames.append("IsExperienceContributor");
+ capabilityNames.append("RegionExperiences");
capabilityNames.append("GetMesh");
capabilityNames.append("GetMetadata");
capabilityNames.append("GetObjectCost");
diff --git a/indra/newview/skins/default/xui/en/floater_experience_search.xml b/indra/newview/skins/default/xui/en/floater_experience_search.xml
index 4531b52d67..8b44dada40 100644
--- a/indra/newview/skins/default/xui/en/floater_experience_search.xml
+++ b/indra/newview/skins/default/xui/en/floater_experience_search.xml
@@ -124,7 +124,7 @@
right="-1"
height="239"
top_pad="4"
- follows="all"
+ follows="all"
column_padding="5"
can_resize="true"
name="search_results">
diff --git a/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
new file mode 100644
index 0000000000..acd9471916
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_experience_list_editor.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ layout="topleft"
+ left="0"
+ top="0"
+ width="300"
+ height="100"
+ min_height="100"
+ follows="all"
+ border="true"
+ name="experince_list_editor">
+ <panel.string
+ name="loading">
+ loading...
+ </panel.string>
+ <panel.string
+ name="no_results">
+ (empty)
+ </panel.string>
+ <text
+ layout="topleft"
+ name="text_name"
+ left="3"
+ right="-1"
+ height="12"
+ follows="left|top|right">
+ Experience List
+ </text>
+ <scroll_list
+ draw_heading="false"
+ left="3"
+ width="225"
+ height="77"
+ follows="all"
+ can_resize="false"
+ name="experience_list">
+ <columns
+ width="225"
+ user_resize="false"
+ name="experience_name"
+ label="Name"/>
+ </scroll_list>
+ <button
+ layout="topleft"
+ follows="top|right"
+ top_pad="-77"
+ left_pad="3"
+ width="65"
+ name="btn_add"
+ label="Add..."/>
+ <button
+ layout="topleft"
+ follows="top|right"
+ width="64"
+ name="btn_remove"
+ label="Remove"/>
+ <button
+ layout="topleft"
+ follows="top|right"
+ width="64"
+ name="btn_profile"
+ label="Profile..."/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_region_experiences.xml b/indra/newview/skins/default/xui/en/panel_region_experiences.xml
index d3b3226619..f4d38c0e08 100644
--- a/indra/newview/skins/default/xui/en/panel_region_experiences.xml
+++ b/indra/newview/skins/default/xui/en/panel_region_experiences.xml
@@ -2,14 +2,78 @@
<panel
border="true"
follows="top|left"
- height="510"
+ height="320"
help_topic="panel_region_experience_tab"
- label="Experience"
+ label="Experiences"
+ name="Experiences"
layout="topleft"
left="0"
- name="Experience"
top="320"
- width="530">
-
+ width="480">
+ <panel.string
+ name="panel_allowed">
+ Allowed Experiences
+ </panel.string>
+ <panel.string
+ name="panel_blocked">
+ Blocked Experiences
+ </panel.string>
+ <panel.string
+ name="panel_trusted">
+ Trusted Experiences
+ </panel.string>
+ <layout_stack
+ left="5"
+ layout="topleft"
+ follows="all"
+ top="100"
+ right="-5"
+ height="140"
+ min_height="140"
+ orientation="vertical">
+ <layout_panel
+ height="100"
+ min_height="100"
+ width="530">
+ <panel follows="all"
+ width="530"
+ name="panel_trusted"
+ class="panel_experience_list_editor"
+ filename="panel_experience_list_editor.xml" />
+ </layout_panel>
+ <layout_panel
+ height="100"
+ min_height="100"
+ width="530">
+ <panel
+ label="SOME LABEL"
+ width="530"
+ name="panel_allowed"
+ class="panel_experience_list_editor"
+ filename="panel_experience_list_editor.xml"/>
+ </layout_panel>
+ <layout_panel
+ height="100"
+ min_height="100"
+ width="530">
+ <panel
+ width="530"
+ name="panel_blocked"
+ class="panel_experience_list_editor"
+ filename="panel_experience_list_editor.xml"/>
+ </layout_panel>
+ <layout_panel
+ height="30"
+ min_height="30"
+ max_height="30"
+ width="530">
+ <button
+ layout="topleft"
+ width="85"
+ left="3"
+ label="Apply"
+ name="apply_btn"/>
+ </layout_panel>
+ </layout_stack>
</panel>