454 lines
13 KiB
C++
454 lines
13 KiB
C++
/**
|
|
* @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 "llfloaterexperienceprofile.h"
|
|
#include "llfloaterexperiences.h"
|
|
//#include "llfloaterreg.h"
|
|
#include "lluictrlfactory.h"
|
|
#include "llscrolllistctrl.h"
|
|
#include "llviewerregion.h"
|
|
#include "llagent.h"
|
|
#include "llexperiencecache.h"
|
|
#include "llslurl.h"
|
|
#include "llavatarnamecache.h"
|
|
#include "llcombobox.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llfloater.h"
|
|
#include "lltrans.h"
|
|
#include <boost/regex.hpp>
|
|
|
|
#define BTN_FIND "find"
|
|
#define BTN_OK "ok_btn"
|
|
#define BTN_CANCEL "cancel_btn"
|
|
#define BTN_PROFILE "profile_btn"
|
|
#define BTN_LEFT "left_btn"
|
|
#define BTN_RIGHT "right_btn"
|
|
#define TEXT_EDIT "edit"
|
|
#define TEXT_MATURITY "maturity"
|
|
#define LIST_RESULTS "search_results"
|
|
#define PANEL_SEARCH "search_panel"
|
|
|
|
const static std::string columnSpace = " ";
|
|
|
|
/* Singu Note: We do not have injectors, so we'll have to call this function instead
|
|
static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker");
|
|
*/
|
|
|
|
LLPanelExperiencePicker::LLPanelExperiencePicker()
|
|
:LLPanel()
|
|
{
|
|
//buildFromFile("panel_experience_search.xml");
|
|
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_search.xml"); // Singu Note: Use filename in xml
|
|
setDefaultFilters();
|
|
}
|
|
|
|
LLPanelExperiencePicker::~LLPanelExperiencePicker()
|
|
{
|
|
}
|
|
|
|
BOOL LLPanelExperiencePicker::postBuild()
|
|
{
|
|
getChild<LLLineEditor>(TEXT_EDIT)->setKeystrokeCallback(boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1));
|
|
|
|
childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
|
|
getChildView(BTN_FIND)->setEnabled(TRUE);
|
|
|
|
LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>(LIST_RESULTS);
|
|
searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
|
|
searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this));
|
|
getChildView(LIST_RESULTS)->setEnabled(FALSE);
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
|
|
|
|
childSetAction(BTN_OK, boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
|
|
getChildView(BTN_OK)->setEnabled(FALSE);
|
|
childSetAction(BTN_CANCEL, boost::bind(&LLPanelExperiencePicker::onBtnClose, this));
|
|
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);
|
|
|
|
childSetAction(BTN_LEFT, boost::bind(&LLPanelExperiencePicker::onPage, this, -1));
|
|
childSetAction(BTN_RIGHT, boost::bind(&LLPanelExperiencePicker::onPage, this, 1));
|
|
|
|
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)
|
|
{
|
|
getChildView(BTN_FIND)->setEnabled(!caller->getText().empty());
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onBtnFind()
|
|
{
|
|
mCurrentPage=1;
|
|
boost::cmatch what;
|
|
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
|
|
// *TODO: this should be part of LLUrlEntry
|
|
static const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile");
|
|
if (boost::regex_match(text.c_str(), what, expression))
|
|
{
|
|
LLURI uri(text);
|
|
LLSD path_array = uri.pathArray();
|
|
if (path_array.size() == 4)
|
|
{
|
|
std::string exp_id = path_array.get(2).asString();
|
|
LLUUID experience_id(exp_id);
|
|
if (!experience_id.isNull())
|
|
{
|
|
const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
|
|
if(!experience_details.isUndefined())
|
|
{
|
|
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
|
|
if(!experience_name_string.empty())
|
|
{
|
|
getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
|
|
|
|
getChildView(BTN_OK)->setEnabled(FALSE);
|
|
getChildView(BTN_PROFILE)->setEnabled(FALSE);
|
|
|
|
getChildView(BTN_RIGHT)->setEnabled(FALSE);
|
|
getChildView(BTN_LEFT)->setEnabled(FALSE);
|
|
LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
find();
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onList()
|
|
{
|
|
bool enabled = isSelectButtonEnabled();
|
|
getChildView(BTN_OK)->setEnabled(enabled);
|
|
|
|
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();
|
|
|
|
LLExperienceCache::instance().findExperienceByName(text, mCurrentPage,
|
|
boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle<LLPanelExperiencePicker>(), mQueryID, _1));
|
|
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
|
|
|
|
getChildView(BTN_OK)->setEnabled(FALSE);
|
|
getChildView(BTN_PROFILE)->setEnabled(FALSE);
|
|
|
|
getChildView(BTN_RIGHT)->setEnabled(FALSE);
|
|
getChildView(BTN_LEFT)->setEnabled(FALSE);
|
|
}
|
|
|
|
/*static*/
|
|
void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult)
|
|
{
|
|
if (hparent.isDead())
|
|
return;
|
|
|
|
LLPanelExperiencePicker* panel = hparent.get();
|
|
if (panel)
|
|
{
|
|
panel->processResponse(queryId, foundResult);
|
|
}
|
|
}
|
|
|
|
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.getNSName());
|
|
|
|
}
|
|
|
|
void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content )
|
|
{
|
|
if (query_id != mQueryID)
|
|
{
|
|
return;
|
|
}
|
|
|
|
mResponse = content;
|
|
|
|
getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
|
|
getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url"));
|
|
|
|
filterContent();
|
|
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onBtnSelect()
|
|
{
|
|
if (!isSelectButtonEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(mSelectionCallback != nullptr)
|
|
{
|
|
const LLScrollListCtrl* results = getChild<LLScrollListCtrl>(LIST_RESULTS);
|
|
uuid_vec_t experience_ids;
|
|
|
|
getSelectedExperienceIds(results, experience_ids);
|
|
mSelectionCallback(experience_ids);
|
|
getChild<LLScrollListCtrl>(LIST_RESULTS)->deselectAllItems(TRUE);
|
|
if (mCloseOnSelect)
|
|
{
|
|
mCloseOnSelect = FALSE;
|
|
onBtnClose();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
onBtnProfile();
|
|
}
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onBtnClose()
|
|
{
|
|
LLFloater* floater = mSelectionCallback ? static_cast<LLFloater*>(getParent()) : LLFloaterExperiences::findInstance();
|
|
if (floater)
|
|
{
|
|
floater->close();
|
|
}
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onBtnProfile()
|
|
{
|
|
LLScrollListItem* item = getChild<LLScrollListCtrl>(LIST_RESULTS)->getFirstSelected();
|
|
if (item)
|
|
{
|
|
LLFloaterExperienceProfile::showInstance(item->getUUID());
|
|
}
|
|
}
|
|
|
|
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;
|
|
for (const auto& experience : experiences.array())
|
|
{
|
|
if (isExperienceHidden(experience))
|
|
continue;
|
|
|
|
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
|
|
if (experience_name_string.empty())
|
|
{
|
|
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
|
|
}
|
|
|
|
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_name_string;
|
|
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 = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
|
|
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_OK)->setEnabled(false);
|
|
getChildView(BTN_PROFILE)->setEnabled(false);
|
|
}
|
|
else
|
|
{
|
|
getChildView(BTN_OK)->setEnabled(true);
|
|
search_results->setEnabled(true);
|
|
search_results->sortByColumnIndex(1, TRUE);
|
|
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
|
|
if (!search_results->selectItemByLabel(text, TRUE))
|
|
{
|
|
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::FilterWithoutProperties( const LLSD& experience, S32 prop)
|
|
{
|
|
return ((experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == prop);
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
bool LLPanelExperiencePicker::FilterMatching( const LLSD& experience, const LLUUID& id )
|
|
{
|
|
if (experience.isUUID())
|
|
{
|
|
return experience.asUUID() == id;
|
|
}
|
|
return experience[LLExperienceCache::EXPERIENCE_ID].asUUID() == id;
|
|
}
|
|
|
|
void LLPanelExperiencePicker::onPage( S32 direction )
|
|
{
|
|
mCurrentPage += direction;
|
|
if (mCurrentPage < 1)
|
|
{
|
|
mCurrentPage = 1;
|
|
}
|
|
find();
|
|
}
|
|
|