summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/llfloaterexperiences.cpp3
-rw-r--r--indra/newview/llpanelexperiencepicker.cpp353
-rw-r--r--indra/newview/llpanelexperiencepicker.h88
-rw-r--r--indra/newview/skins/default/xui/en/panel_experience_search.xml152
5 files changed, 597 insertions, 1 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0a6f935930..fce9b16129 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -407,6 +407,7 @@ set(viewer_SOURCE_FILES
llpaneleditwearable.cpp
llpanelexperiencelisteditor.cpp
llpanelexperiencelog.cpp
+ llpanelexperiencepicker.cpp
llpanelexperiences.cpp
llpanelface.cpp
llpanelgenerictip.cpp
@@ -997,6 +998,7 @@ set(viewer_HEADER_FILES
llpaneleditwearable.h
llpanelexperiencelisteditor.h
llpanelexperiencelog.h
+ llpanelexperiencepicker.h
llpanelexperiences.h
llpanelface.h
llpanelgenerictip.h
diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp
index 1654419826..51e3996f3f 100644
--- a/indra/newview/llfloaterexperiences.cpp
+++ b/indra/newview/llfloaterexperiences.cpp
@@ -36,7 +36,7 @@
#include "llevents.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
-
+#include "llpanelexperiencepicker.h"
#define SHOW_RECENT_TAB (0)
@@ -106,6 +106,7 @@ LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name, bool s
BOOL LLFloaterExperiences::postBuild()
{
+ getChild<LLTabContainer>("xp_tabs")->addTabPanel(new LLPanelExperiencePicker());
addTab("Allowed_Experiences_Tab", true);
addTab("Blocked_Experiences_Tab", false);
addTab("Admin_Experiences_Tab", false);
diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp
new file mode 100644
index 0000000000..4e2ae585cd
--- /dev/null
+++ b/indra/newview/llpanelexperiencepicker.cpp
@@ -0,0 +1,353 @@
+/**
+* @file llpanelexperiencepicker.cpp
+* @brief Implementation of llpanelexperiencepicker
+* @author dolphin@lindenlab.com
+*
+* $LicenseInfo:firstyear=2014&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2014, 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 "llpanelexperiencepicker.h"
+
+
+#include "lllineeditor.h"
+#include "llfloaterreg.h"
+#include "llscrolllistctrl.h"
+#include "llviewerregion.h"
+#include "llagent.h"
+#include "llexperiencecache.h"
+#include "llslurl.h"
+#include "llavatarnamecache.h"
+#include "llfloaterexperienceprofile.h"
+#include "llcombobox.h"
+#include "llviewercontrol.h"
+#include "lldraghandle.h"
+
+#define BTN_FIND "find"
+#define BTN_PROFILE "profile_btn"
+#define TEXT_EDIT "edit"
+#define TEXT_MATURITY "maturity"
+#define LIST_RESULTS "search_results"
+#define PANEL_SEARCH "search_panel"
+
+const static std::string columnSpace = " ";
+
+class LLExperienceSearchResponder : public LLHTTPClient::Responder
+{
+public:
+ LLUUID mQueryID;
+ LLHandle<LLPanelExperiencePicker> mParent;
+
+ LLExperienceSearchResponder(const LLUUID& id, const LLHandle<LLPanelExperiencePicker>& parent) : mQueryID(id), mParent(parent) { }
+
+ void completed(U32 status, const std::string& reason, const LLSD& content)
+ {
+ if (isGoodStatus(status))
+ {
+ if(mParent.isDead())
+ return;
+
+ LLPanelExperiencePicker* panel =mParent.get();
+ if (panel)
+ {
+ panel->processResponse(mQueryID, content);
+ }
+ }
+ else
+ {
+ llwarns << "avatar picker failed [status:" << status << "]: " << content << llendl;
+
+ }
+ }
+};
+
+LLPanelExperiencePicker::LLPanelExperiencePicker()
+ :LLPanel()
+{
+ buildFromFile("panel_experience_search.xml");
+ setDefaultFilters();
+}
+
+LLPanelExperiencePicker::~LLPanelExperiencePicker()
+{
+ gFocusMgr.releaseFocusIfNeeded( this );
+}
+
+BOOL LLPanelExperiencePicker::postBuild()
+{
+ getChild<LLLineEditor>(TEXT_EDIT)->setKeystrokeCallback( boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1, _2),NULL);
+
+ childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
+ getChildView(BTN_FIND)->setEnabled(FALSE);
+
+ LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>(LIST_RESULTS);
+ searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnProfile, this));
+ searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this));
+ getChildView(LIST_RESULTS)->setEnabled(FALSE);
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
+
+ childSetAction(BTN_PROFILE, boost::bind(&LLPanelExperiencePicker::onBtnProfile, this));
+ getChildView(BTN_PROFILE)->setEnabled(FALSE);
+
+ getChild<LLComboBox>(TEXT_MATURITY)->setCurrentByIndex(2);
+ getChild<LLComboBox>(TEXT_MATURITY)->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onMaturity, this));
+ getChild<LLUICtrl>(TEXT_EDIT)->setFocus(TRUE);
+
+ LLPanel* search_panel = getChild<LLPanel>(PANEL_SEARCH);
+ if (search_panel)
+ {
+ // Start searching when Return is pressed in the line editor.
+ search_panel->setDefaultBtn(BTN_FIND);
+ }
+ return TRUE;
+}
+
+void LLPanelExperiencePicker::editKeystroke( class LLLineEditor* caller, void* user_data )
+{
+ getChildView(BTN_FIND)->setEnabled(caller->getText().size() > 0);
+}
+
+void LLPanelExperiencePicker::onBtnFind()
+{
+ find();
+}
+
+void LLPanelExperiencePicker::onList()
+{
+ bool enabled = isSelectButtonEnabled();
+
+ enabled = enabled && getChild<LLScrollListCtrl>(LIST_RESULTS)->getNumSelected() == 1;
+ getChildView(BTN_PROFILE)->setEnabled(enabled);
+}
+
+void LLPanelExperiencePicker::find()
+{
+ std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
+ mQueryID.generate();
+ std::string url;
+ url.reserve(128+text.size());
+
+ LLViewerRegion* region = gAgent.getRegion();
+ url = region->getCapability("FindExperienceByName");
+ if (!url.empty())
+ {
+ url+="?query=";
+ url+=LLURI::escape(text);
+ LLHTTPClient::get(url, new LLExperienceSearchResponder(mQueryID, getDerivedHandle<LLPanelExperiencePicker>()));
+
+ }
+
+
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
+
+ getChildView(BTN_PROFILE)->setEnabled(FALSE);
+}
+
+
+bool LLPanelExperiencePicker::isSelectButtonEnabled()
+{
+ LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
+ return list->getFirstSelectedIndex() >=0;
+}
+
+void LLPanelExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids )
+{
+ std::vector<LLScrollListItem*> items = results->getAllSelected();
+ for(std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); ++it)
+ {
+ LLScrollListItem* item = *it;
+ if (item->getUUID().notNull())
+ {
+ experience_ids.push_back(item->getUUID());
+ }
+ }
+}
+
+void LLPanelExperiencePicker::setAllowMultiple( bool allow_multiple )
+{
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setAllowMultipleSelection(allow_multiple);
+}
+
+
+void name_callback(const LLHandle<LLPanelExperiencePicker>& floater, const LLUUID& experience_id, const LLUUID& agent_id, const LLAvatarName& av_name)
+{
+ if(floater.isDead())
+ return;
+ LLPanelExperiencePicker* picker = floater.get();
+ LLScrollListCtrl* search_results = picker->getChild<LLScrollListCtrl>(LIST_RESULTS);
+
+ LLScrollListItem* item = search_results->getItem(experience_id);
+ if(!item)
+ return;
+
+ item->getColumn(2)->setValue(columnSpace+av_name.getDisplayName());
+
+}
+
+void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content )
+{
+ if(query_id != mQueryID)
+ {
+ return;
+ }
+
+ mResponse = content;
+
+ const LLSD& experiences=mResponse["experience_keys"];
+ LLSD::array_const_iterator it = experiences.beginArray();
+ for ( ; it != experiences.endArray(); ++it)
+ {
+ LLExperienceCache::insert(*it);
+ }
+
+ filterContent();
+
+}
+
+void LLPanelExperiencePicker::onBtnProfile()
+{
+ LLScrollListItem* item = getChild<LLScrollListCtrl>(LIST_RESULTS)->getFirstSelected();
+ if(item)
+ {
+ LLFloaterReg::showInstance("experience_profile", item->getUUID(), true);
+ }
+}
+
+std::string LLPanelExperiencePicker::getMaturityString(int maturity)
+{
+ if(maturity <= SIM_ACCESS_PG)
+ {
+ return getString("maturity_icon_general");
+ }
+ else if(maturity <= SIM_ACCESS_MATURE)
+ {
+ return getString("maturity_icon_moderate");
+ }
+ return getString("maturity_icon_adult");
+}
+
+void LLPanelExperiencePicker::filterContent()
+{
+ LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>(LIST_RESULTS);
+
+ const LLSD& experiences=mResponse["experience_keys"];
+
+ search_results->deleteAllItems();
+
+ LLSD item;
+ LLSD::array_const_iterator it = experiences.beginArray();
+ for ( ; it != experiences.endArray(); ++it)
+ {
+ const LLSD& experience = *it;
+
+ if(isExperienceHidden(experience))
+ continue;
+
+ item["id"]=experience[LLExperienceCache::EXPERIENCE_ID];
+ LLSD& columns = item["columns"];
+ columns[0]["column"] = "maturity";
+ columns[0]["value"] = getMaturityString(experience[LLExperienceCache::MATURITY].asInteger());
+ columns[0]["type"]="icon";
+ columns[0]["halign"]="right";
+ columns[1]["column"] = "experience_name";
+ columns[1]["value"] = columnSpace+experience[LLExperienceCache::NAME].asString();
+ columns[2]["column"] = "owner";
+ columns[2]["value"] = columnSpace+getString("loading");
+ search_results->addElement(item);
+ LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID], boost::bind(name_callback, getDerivedHandle<LLPanelExperiencePicker>(), experience[LLExperienceCache::EXPERIENCE_ID], _1, _2));
+ }
+
+ if (search_results->isEmpty())
+ {
+ LLStringUtil::format_map_t map;
+ std::string search_text = childGetText(TEXT_EDIT);
+ map["[TEXT]"] = search_text;
+ if (search_text.empty())
+ {
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
+ }
+ else
+ {
+ getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("not_found", map));
+ }
+ search_results->setEnabled(false);
+ getChildView(BTN_PROFILE)->setEnabled(false);
+ }
+ else
+ {
+ search_results->setEnabled(true);
+ search_results->sortByColumnIndex(1, TRUE);
+ std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
+ if (!search_results->selectItemByLabel(text, TRUE, 1))
+ {
+ search_results->selectFirstItem();
+ }
+ onList();
+ search_results->setFocus(TRUE);
+ }
+}
+
+void LLPanelExperiencePicker::onMaturity()
+{
+ if(mResponse.has("experience_keys") && mResponse["experience_keys"].beginArray() != mResponse["experience_keys"].endArray())
+ {
+ filterContent();
+ }
+}
+
+bool LLPanelExperiencePicker::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 LLPanelExperiencePicker::FilterOverRating( const LLSD& experience )
+{
+ int maturity = getChild<LLComboBox>(TEXT_MATURITY)->getSelectedValue().asInteger();
+ return experience[LLExperienceCache::MATURITY].asInteger() > maturity;
+}
+
+bool LLPanelExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop)
+{
+ return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0;
+}
+
+bool LLPanelExperiencePicker::FilterWithoutProperty( const LLSD& experience, S32 prop )
+{
+ return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == 0;
+}
+
+void LLPanelExperiencePicker::setDefaultFilters()
+{
+ mFilters.clear();
+ addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating, this, _1));
+}
diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h
new file mode 100644
index 0000000000..166639a14e
--- /dev/null
+++ b/indra/newview/llpanelexperiencepicker.h
@@ -0,0 +1,88 @@
+/**
+* @file llpanelexperiencepicker.h
+* @brief Header file for llpanelexperiencepicker
+* @author dolphin@lindenlab.com
+*
+* $LicenseInfo:firstyear=2014&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2014, 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_LLPANELEXPERIENCEPICKER_H
+#define LL_LLPANELEXPERIENCEPICKER_H
+
+#include "llpanel.h"
+
+class LLScrollListCtrl;
+class LLLineEditor;
+
+
+class LLPanelExperiencePicker : public LLPanel
+{
+public:
+ friend class LLExperienceSearchResponder;
+
+ // 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;
+
+ LLPanelExperiencePicker();
+ virtual ~LLPanelExperiencePicker();
+
+ 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);
+ static bool FilterWithoutProperty(const LLSD& experience, S32 prop);
+ bool FilterOverRating(const LLSD& experience);
+
+private:
+ void editKeystroke(LLLineEditor* caller, void* user_data);
+
+ void onBtnFind();
+ void onBtnProfile();
+ void onList();
+ void onMaturity();
+
+ void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids );
+ void setAllowMultiple(bool allow_multiple);
+
+
+ void find();
+ bool isSelectButtonEnabled();
+ 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;
+ filter_list mFilters;
+ LLUUID mQueryID;
+ LLSD mResponse;
+};
+
+#endif // LL_LLPANELEXPERIENCEPICKER_H
diff --git a/indra/newview/skins/default/xui/en/panel_experience_search.xml b/indra/newview/skins/default/xui/en/panel_experience_search.xml
new file mode 100644
index 0000000000..5593cef591
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_experience_search.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ layout="topleft"
+ top="3"
+ left="3"
+ width="350"
+ height="350"
+ label="SEARCH"
+ bg_opaque_color="0 0.5 0 0.3"
+ follows="all">
+
+ <string
+ name="not_found">
+ &apos;[TEXT]&apos; not found
+ </string>
+ <string
+ name="no_results">
+ No results
+ </string>
+ <string
+ name="searching">
+ Searching...
+ </string>
+ <string
+ name="loading">
+ Loading...
+ </string>
+ <string
+ name="maturity_icon_general">
+ "Parcel_PG_Light"
+ </string>
+ <string
+ name="maturity_icon_moderate">
+ "Parcel_M_Light"
+ </string>
+ <string
+ name="maturity_icon_adult">
+ "Parcel_R_Light"
+ </string>
+ <panel
+ follows="all"
+ left="5"
+ right="-3"
+ bottom="-2"
+ top="18"
+ name="search_panel">
+ <text
+ left="0"
+ follows="top|left|right"
+ right="-1">
+ Enter part of the name:
+ </text>
+ <line_editor
+ left="0"
+ follows="left|top|right"
+ name="edit"
+ height="18"
+ right="-60"/>
+ <button label="Go"
+ follows="top|right"
+ top_pad="-18"
+ left_pad="2"
+ right="-1"
+ height="18"
+ name="find"/>
+ <text
+ top_pad="6"
+ left="0"
+ follows="top|left"
+ width="180">
+ Max Content Rating:
+ </text>
+ <icons_combo_box
+ follows="left|top"
+ height="20"
+ label="Moderate"
+ layout="topleft"
+ name="maturity"
+ top_pad="-13"
+ left_pad="0"
+ right="-1">
+ <icons_combo_box.drop_down_button
+ image_overlay="Parcel_M_Light"
+ image_overlay_alignment="left"
+ imgoverlay_label_space="3"
+ pad_left="3"/>
+ <icons_combo_box.item
+ label="Adult"
+ name="Adult"
+ value="42">
+ <item.columns
+ halign="center"
+ type="icon"
+ value="Parcel_R_Light"
+ width="20"/>
+ </icons_combo_box.item>
+ <icons_combo_box.item
+ label="Moderate"
+ name="Mature"
+ value="21">
+ <item.columns
+ halign="center"
+ type="icon"
+ value="Parcel_M_Light"
+ width="20"/>
+ </icons_combo_box.item>
+ <icons_combo_box.item
+ label="General"
+ name="PG"
+ value="13">
+ <item.columns
+ halign="center"
+ type="icon"
+ value="Parcel_PG_Light"
+ width="20"/>
+ </icons_combo_box.item>
+ </icons_combo_box>
+ <scroll_list
+ draw_heading="true"
+ left="0"
+ right="-1"
+ height="239"
+ top_pad="4"
+ follows="all"
+ column_padding="5"
+ can_resize="true"
+ name="search_results">
+ <columns
+ halign="center"
+ width="24"
+ name="maturity"
+ label=""/>
+ <columns
+ user_resize="true"
+ name="experience_name"
+ label="Name"/>
+ <columns
+ user_resize="true"
+ name="owner"
+ label="Owner"/>
+ </scroll_list>
+
+ <button
+ follows="left|bottom"
+ height="23"
+ label="View Profile"
+ name="profile_btn"
+ top_pad="3"
+ left="0"
+ width="100"/>
+ </panel>
+</panel>