Files
SingularityViewer/indra/newview/llpanelexperiencepicker.cpp

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();
}