1959 lines
54 KiB
C++
1959 lines
54 KiB
C++
/**
|
|
* @file fsareasearch.cpp
|
|
* @brief Floater to search and list objects in view or is known to the viewer.
|
|
*
|
|
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
|
* Phoenix Firestorm Viewer Source Code
|
|
* Copyright (c) 2012 Techwolf Lupindo
|
|
*
|
|
* 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
|
|
*
|
|
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
|
* http://www.firestormviewer.org
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
|
|
#include "fsareasearch.h"
|
|
|
|
#include "llscrolllistctrl.h"
|
|
#include "lllineeditor.h"
|
|
#include "lltextbox.h"
|
|
#include "llfloaterreg.h"
|
|
#include "llagent.h"
|
|
#include "lltracker.h"
|
|
#include "llviewerobjectlist.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include <boost/algorithm/string/find.hpp> //for boost::ifind_first
|
|
#include "llviewerregion.h"
|
|
#include "llselectmgr.h"
|
|
#include "llcallbacklist.h"
|
|
#include "lltoolpie.h"
|
|
#include "llsaleinfo.h"
|
|
#include "llcheckboxctrl.h"
|
|
#include "llviewermenu.h" // handle_object_touch(), handle_buy()
|
|
#include "llclickaction.h"
|
|
#include "lltabcontainer.h"
|
|
#include "llspinctrl.h"
|
|
#include "lltoolgrab.h"
|
|
#include "fslslbridge.h"
|
|
#include "llcombobox.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "fswsassetblacklist.h"
|
|
#include "llworld.h"
|
|
|
|
|
|
// max number of objects that can be (de-)selected in a single packet.
|
|
const S32 MAX_OBJECTS_PER_PACKET = 255;
|
|
|
|
// time in seconds between refreshes when active
|
|
const F32 REFRESH_INTERVAL = 1.0f;
|
|
|
|
// this is used to prevent refreshing too often and affecting performance.
|
|
const F32 MIN_REFRESH_INTERVAL = 0.25f;
|
|
|
|
// how far the avatar needs to move to trigger a distance update
|
|
const F32 MIN_DISTANCE_MOVED = 1.0f;
|
|
|
|
// timeout to resend object properties request again
|
|
const F32 REQUEST_TIMEOUT = 30.0f;
|
|
|
|
|
|
class FSAreaSearch::FSParcelChangeObserver : public LLParcelObserver
|
|
{
|
|
public:
|
|
FSParcelChangeObserver(FSAreaSearch* area_search_floater) : mAreaSearchFloater(area_search_floater) {}
|
|
|
|
private:
|
|
/*virtual*/ void changed()
|
|
{
|
|
if (mAreaSearchFloater)
|
|
{
|
|
mAreaSearchFloater->checkRegion();
|
|
}
|
|
}
|
|
|
|
FSAreaSearch* mAreaSearchFloater;
|
|
};
|
|
|
|
FSAreaSearch::FSAreaSearch(const LLSD& key) :
|
|
LLFloater(key),
|
|
mActive(false),
|
|
mFilterForSale(false),
|
|
mFilterForSaleMin(0),
|
|
mFilterForSaleMax(999999),
|
|
mFilterPhysicial(false),
|
|
mFilterTemporary(false),
|
|
mRegexSearch(false),
|
|
mFilterClickAction(false),
|
|
mFilterLocked(false),
|
|
mFilterPhantom(false),
|
|
mFilterAttachment(false),
|
|
mFilterMoaP(false),
|
|
mFilterDistance(false),
|
|
mFilterDistanceMin(0),
|
|
mFilterDistanceMax(999999),
|
|
mBeaconColor(),
|
|
mBeaconTextColor(),
|
|
mBeacons(false),
|
|
mExcludeAttachment(true),
|
|
mExcludeTempary(true),
|
|
mExcludePhysics(true),
|
|
mExcludeChildPrims(true),
|
|
mExcludeNeighborRegines(true),
|
|
mColumnDistance(true),
|
|
mColumnName(true),
|
|
mColumnDescription(true),
|
|
mColumnOwner(true),
|
|
mColumnGroup(true),
|
|
mColumnCreator(true),
|
|
mColumnLastOwner(true),
|
|
mRequestQueuePause(false),
|
|
mRequestNeedsSent(false)
|
|
{
|
|
//TODO: Multi-floater support and get rid of the singletin.
|
|
mInstance = this;
|
|
|
|
mFactoryMap["area_search_list_panel"] = LLCallbackMap(createPanelList, this);
|
|
mFactoryMap["area_search_find_panel"] = LLCallbackMap(createPanelFind, this);
|
|
mFactoryMap["area_search_filter_panel"] = LLCallbackMap(createPanelFilter, this);
|
|
mFactoryMap["area_search_advanced_panel"] = LLCallbackMap(createPanelAdvanced, this);
|
|
mFactoryMap["area_search_options_panel"] = LLCallbackMap(createPanelOptions, this);
|
|
|
|
// Register an idle update callback
|
|
gIdleCallbacks.addFunction(idle, this);
|
|
|
|
mParcelChangedObserver = new FSParcelChangeObserver(this);
|
|
LLViewerParcelMgr::getInstance()->addObserver(mParcelChangedObserver);
|
|
}
|
|
|
|
FSAreaSearch::~FSAreaSearch()
|
|
{
|
|
if (!gIdleCallbacks.deleteFunction(idle, this))
|
|
{
|
|
LL_WARNS("FSAreaSearch") << "FSAreaSearch::~FSAreaSearch() failed to delete callback" << LL_ENDL;
|
|
}
|
|
|
|
if (mParcelChangedObserver)
|
|
{
|
|
LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangedObserver);
|
|
delete mParcelChangedObserver;
|
|
mParcelChangedObserver = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL FSAreaSearch::postBuild()
|
|
{
|
|
mTab = getChild<LLTabContainer>("area_searchtab");
|
|
|
|
if (!gSavedSettings.getBOOL("FSAreaSearchAdvanced"))
|
|
{
|
|
LLPanel* advanced_tab = mTab->getPanelByName("area_search_advanced_panel");
|
|
if (advanced_tab)
|
|
{
|
|
mTab->removeTabPanel(advanced_tab);
|
|
}
|
|
}
|
|
|
|
// TODO: add area search settings to the color.xml file
|
|
mBeaconColor = LLUIColorTable::getInstance()->getColor("PathfindingLinksetBeaconColor");
|
|
mBeaconTextColor = LLUIColorTable::getInstance()->getColor("PathfindingDefaultBeaconTextColor");
|
|
mBeaconLineWidth = gSavedSettings.getS32("DebugBeaconLineWidth");
|
|
|
|
return LLFloater::postBuild();
|
|
}
|
|
|
|
void FSAreaSearch::draw()
|
|
{
|
|
LLFloater::draw();
|
|
|
|
if (mBeacons)
|
|
{
|
|
std::vector<LLScrollListItem*> items = mPanelList->getResultList()->getAllData();
|
|
|
|
for (std::vector<LLScrollListItem*>::const_iterator item_it = items.begin();
|
|
item_it != items.end();
|
|
++item_it)
|
|
{
|
|
const LLScrollListItem* item = (*item_it);
|
|
LLViewerObject* objectp = gObjectList.findObject(item->getUUID());
|
|
|
|
if (objectp)
|
|
{
|
|
const std::string &objectName = mObjectDetails[item->getUUID()].description;
|
|
gObjectList.addDebugBeacon(objectp->getPositionAgent(), objectName, mBeaconColor, mBeaconTextColor, mBeaconLineWidth);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//static
|
|
void FSAreaSearch::idle(void* user_data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)user_data;
|
|
self->findObjects();
|
|
self->processRequestQueue();
|
|
}
|
|
|
|
// static
|
|
void* FSAreaSearch::createPanelList(void* data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)data;
|
|
self->mPanelList = new FSPanelAreaSearchList(self);
|
|
return self->mPanelList;
|
|
}
|
|
|
|
// static
|
|
void* FSAreaSearch::createPanelFind(void* data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)data;
|
|
self->mPanelFind = new FSPanelAreaSearchFind(self);
|
|
return self->mPanelFind;
|
|
}
|
|
|
|
// static
|
|
void* FSAreaSearch::createPanelFilter(void* data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)data;
|
|
self->mPanelFilter = new FSPanelAreaSearchFilter(self);
|
|
return self->mPanelFilter;
|
|
}
|
|
|
|
// static
|
|
void* FSAreaSearch::createPanelAdvanced(void* data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)data;
|
|
self->mPanelAdvanced = new FSPanelAreaSearchAdvanced(self);
|
|
return self->mPanelAdvanced;
|
|
}
|
|
|
|
// static
|
|
void* FSAreaSearch::createPanelOptions(void* data)
|
|
{
|
|
FSAreaSearch* self = (FSAreaSearch*)data;
|
|
self->mPanelOptions = new FSPanelAreaSearchOptions(self);
|
|
return self->mPanelOptions;
|
|
}
|
|
|
|
void FSAreaSearch::checkRegion()
|
|
{
|
|
if (mInstance && mActive)
|
|
{
|
|
// Check if we changed region, and if we did, clear the object details cache.
|
|
LLViewerRegion* region = gAgent.getRegion(); // getRegion can return NULL if disconnected.
|
|
if (region && (region != mLastRegion))
|
|
{
|
|
if (!mExcludeNeighborRegines)
|
|
{
|
|
std::vector<LLViewerRegion*> uniqueRegions;
|
|
region->getNeighboringRegions(uniqueRegions);
|
|
if(std::find(uniqueRegions.begin(), uniqueRegions.end(), mLastRegion) != uniqueRegions.end())
|
|
{
|
|
// Crossed into a neighboring regine, no need to clear everything.
|
|
mLastRegion = region;
|
|
return;
|
|
}
|
|
// else teleported into a new regine
|
|
}
|
|
mLastRegion = region;
|
|
mRequested = 0;
|
|
mObjectDetails.clear();
|
|
mRegionRequests.clear();
|
|
mLastProptiesRecievedTimer.start();
|
|
mPanelList->getResultList()->deleteAllItems();
|
|
mPanelList->setCounterText();
|
|
mPanelList->setAgentLastPosition(gAgent.getPositionGlobal());
|
|
mRefresh = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::refreshList(bool cache_clear)
|
|
{
|
|
mActive = true;
|
|
checkRegion();
|
|
if (cache_clear)
|
|
{
|
|
mRequested = 0;
|
|
mObjectDetails.clear();
|
|
mRegionRequests.clear();
|
|
mLastProptiesRecievedTimer.start();
|
|
}
|
|
else
|
|
{
|
|
for (std::map<LLUUID, FSObjectProperties>::iterator object_it = mObjectDetails.begin();
|
|
object_it != mObjectDetails.end();
|
|
++object_it)
|
|
{
|
|
object_it->second.listed = false;
|
|
}
|
|
}
|
|
mPanelList->getResultList()->deleteAllItems();
|
|
mPanelList->setCounterText();
|
|
mPanelList->setAgentLastPosition(gAgent.getPositionGlobal());
|
|
mNamesRequested.clear();
|
|
mRefresh = true;
|
|
findObjects();
|
|
}
|
|
|
|
void FSAreaSearch::findObjects()
|
|
{
|
|
// Only loop through the gObjectList every so often. There is a performance hit if done too often.
|
|
if (!(mActive && ((mRefresh && mLastUpdateTimer.getElapsedTimeF32() > MIN_REFRESH_INTERVAL) || mLastUpdateTimer.getElapsedTimeF32() > REFRESH_INTERVAL)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLViewerRegion* our_region = gAgent.getRegion();
|
|
if (!our_region)
|
|
{
|
|
// Got disconnected or is in the middle of a teleport.
|
|
return;
|
|
}
|
|
|
|
LL_DEBUGS("FSAreaSearch_spammy") << "Doing a FSAreaSearch::findObjects" << LL_ENDL;
|
|
|
|
mLastUpdateTimer.stop(); // stop sets getElapsedTimeF32() time to zero.
|
|
// Pause processing of requestqueue untill done adding new requests.
|
|
mRequestQueuePause = true;
|
|
checkRegion();
|
|
mRefresh = false;
|
|
mSearchableObjects = 0;
|
|
S32 object_count = gObjectList.getNumObjects();
|
|
|
|
for (S32 i = 0; i < object_count; i++)
|
|
{
|
|
LLViewerObject *objectp = gObjectList.getObject(i);
|
|
if (!(objectp && isSearchableObject(objectp, our_region)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
LLUUID object_id = objectp->getID();
|
|
|
|
if (object_id.isNull())
|
|
{
|
|
LL_WARNS("FSAreaSearch") << "WTF?! Selectable object with id of NULL!!" << LL_ENDL;
|
|
continue;
|
|
}
|
|
|
|
mSearchableObjects++;
|
|
|
|
if (mObjectDetails.count(object_id) == 0)
|
|
{
|
|
FSObjectProperties& details = mObjectDetails[object_id];
|
|
details.id = object_id;
|
|
details.local_id = objectp->getLocalID();
|
|
details.region_handle = objectp->getRegion()->getHandle();
|
|
mRequestNeedsSent = true;
|
|
mRequested++;
|
|
}
|
|
else
|
|
{
|
|
FSObjectProperties& details = mObjectDetails[object_id];
|
|
if (details.request == FSObjectProperties::FINISHED)
|
|
{
|
|
matchObject(details, objectp);
|
|
}
|
|
|
|
if (details.request == FSObjectProperties::FAILED)
|
|
{
|
|
// object came back into view
|
|
details.request = FSObjectProperties::NEED;
|
|
details.local_id = objectp->getLocalID();
|
|
details.region_handle = objectp->getRegion()->getHandle();
|
|
mRequestNeedsSent = true;
|
|
mRequested++;
|
|
}
|
|
}
|
|
}
|
|
|
|
mPanelList->updateScrollList();
|
|
|
|
S32 request_count = 0;
|
|
// requests for non-existent objects will never arrive, check and update the queue.
|
|
for (std::map<LLUUID, FSObjectProperties>::iterator object_it = mObjectDetails.begin();
|
|
object_it != mObjectDetails.end();
|
|
++object_it)
|
|
{
|
|
if (object_it->second.request == FSObjectProperties::NEED || object_it->second.request == FSObjectProperties::SENT)
|
|
{
|
|
LLUUID id = object_it->second.id;
|
|
LLViewerObject* objectp = gObjectList.findObject(id);
|
|
if (!objectp)
|
|
{
|
|
object_it->second.request = FSObjectProperties::FAILED;
|
|
mRequested--;
|
|
}
|
|
else
|
|
{
|
|
request_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mRequested != request_count)
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << "Requested mismatch: " << request_count << " actual vs. " << mRequested << LL_ENDL;
|
|
mRequested = request_count;
|
|
}
|
|
|
|
updateCounterText();
|
|
mLastUpdateTimer.start(); // start also reset elapsed time to zero
|
|
mRequestQueuePause = false;
|
|
}
|
|
|
|
bool FSAreaSearch::isSearchableObject(LLViewerObject* objectp, LLViewerRegion* our_region)
|
|
{
|
|
// need to be connected to regine object is in.
|
|
if (!objectp->getRegion())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Land doesn't have object properties
|
|
if (objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Object needs to be selectable to get properties from the server
|
|
if (!objectp->mbCanSelect)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Avatars are spechiel objects that don't have normal properties
|
|
if (objectp->isAvatar())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Excludes
|
|
//-----------------------------------------------------------------------
|
|
|
|
if (mExcludeChildPrims && !(objectp->isRoot() || (objectp->isAttachment() && objectp->isRootEdit())))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (mExcludeNeighborRegines && !(objectp->getRegion() == our_region))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (mExcludeAttachment && objectp->isAttachment())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (mExcludePhysics && objectp->flagUsePhysics())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (mExcludeTempary && objectp->flagTemporaryOnRez())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FSAreaSearch::processRequestQueue()
|
|
{
|
|
if (!mActive || mRequestQueuePause)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mLastProptiesRecievedTimer.getElapsedTimeF32() > REQUEST_TIMEOUT)
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << "Timeout reached, resending requests."<< LL_ENDL;
|
|
S32 request_count = 0;
|
|
S32 failed_count = 0;
|
|
for (std::map<LLUUID, FSObjectProperties>::iterator object_it = mObjectDetails.begin();
|
|
object_it != mObjectDetails.end();
|
|
++object_it)
|
|
{
|
|
if (object_it->second.request == FSObjectProperties::SENT)
|
|
{
|
|
object_it->second.request = FSObjectProperties::NEED;
|
|
mRequestNeedsSent = true;
|
|
request_count++;
|
|
}
|
|
|
|
if (object_it->second.request == FSObjectProperties::FAILED)
|
|
{
|
|
failed_count++;
|
|
}
|
|
}
|
|
|
|
mRegionRequests.clear();
|
|
mLastProptiesRecievedTimer.start();
|
|
|
|
if (!mRequestNeedsSent)
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << "No pending requests found."<< LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << request_count << " pending requests found."<< LL_ENDL;
|
|
}
|
|
|
|
LL_DEBUGS("FSAreaSearch") << failed_count << " failed requests found."<< LL_ENDL;
|
|
}
|
|
|
|
if (!mRequestNeedsSent)
|
|
{
|
|
return;
|
|
}
|
|
mRequestNeedsSent = false;
|
|
|
|
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
|
|
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
|
|
{
|
|
LLViewerRegion* regionp = *iter;
|
|
U64 region_handle = regionp->getHandle();
|
|
if (mRegionRequests[region_handle] > (MAX_OBJECTS_PER_PACKET + 128))
|
|
{
|
|
mRequestNeedsSent = true;
|
|
return;
|
|
}
|
|
|
|
std::vector<U32> request_list;
|
|
bool need_continue = false;
|
|
|
|
for (std::map<LLUUID, FSObjectProperties>::iterator object_it = mObjectDetails.begin();
|
|
object_it != mObjectDetails.end();
|
|
++object_it)
|
|
{
|
|
if (object_it->second.request == FSObjectProperties::NEED && object_it->second.region_handle == region_handle)
|
|
{
|
|
request_list.push_back(object_it->second.local_id);
|
|
object_it->second.request = FSObjectProperties::SENT;
|
|
mRegionRequests[region_handle]++;
|
|
if (mRegionRequests[region_handle] >= ((MAX_OBJECTS_PER_PACKET * 3) - 3))
|
|
{
|
|
requestObjectProperties(request_list, true, regionp);
|
|
requestObjectProperties(request_list, false, regionp);
|
|
mRequestNeedsSent = true;
|
|
need_continue = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (need_continue)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!request_list.empty())
|
|
{
|
|
requestObjectProperties(request_list, true, regionp);
|
|
requestObjectProperties(request_list, false, regionp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::requestObjectProperties(const std::vector<U32>& request_list, bool select, LLViewerRegion* regionp)
|
|
{
|
|
bool start_new_message = true;
|
|
S32 select_count = 0;
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
|
|
for (std::vector<U32>::const_iterator iter = request_list.begin();
|
|
iter != request_list.end(); ++iter)
|
|
{
|
|
if (start_new_message)
|
|
{
|
|
if (select)
|
|
{
|
|
msg->newMessageFast(_PREHASH_ObjectSelect);
|
|
}
|
|
else
|
|
{
|
|
msg->newMessageFast(_PREHASH_ObjectDeselect);
|
|
}
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
select_count++;
|
|
start_new_message = false;
|
|
}
|
|
|
|
msg->nextBlockFast(_PREHASH_ObjectData);
|
|
msg->addU32Fast(_PREHASH_ObjectLocalID, (*iter) );
|
|
select_count++;
|
|
|
|
if(msg->isSendFull(NULL) || select_count >= MAX_OBJECTS_PER_PACKET)
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << "Sent one full " << (select ? "ObjectSelect" : "ObjectDeselect") << " message with " << select_count << " object data blocks." << LL_ENDL;
|
|
msg->sendReliable(regionp->getHost());
|
|
select_count = 0;
|
|
start_new_message = true;
|
|
}
|
|
}
|
|
|
|
if (!start_new_message)
|
|
{
|
|
LL_DEBUGS("FSAreaSearch") << "Sent one partcial " << (select ? "ObjectSelect" : "ObjectDeselect") << " message with " << select_count << " object data blocks." << LL_ENDL;
|
|
msg->sendReliable(regionp->getHost());
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::processObjectProperties(LLMessageSystem* msg)
|
|
{
|
|
// This fuction is called by llviewermessage even if no floater has been created.
|
|
if (!(mInstance && mActive))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLViewerRegion* our_region = gAgent.getRegion();
|
|
bool counter_text_update = false;
|
|
|
|
S32 count = msg->getNumberOfBlocksFast(_PREHASH_ObjectData);
|
|
LL_DEBUGS("FSAreaSearch") << "Got processObjectProperties message with " << count << " object(s)" << LL_ENDL;
|
|
for (S32 i = 0; i < count; i++)
|
|
{
|
|
LLUUID object_id;
|
|
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, object_id, i);
|
|
if (object_id.isNull())
|
|
{
|
|
LL_WARNS("FSAreaSearch") << "Got Object Properties with NULL id" << LL_ENDL;
|
|
continue;
|
|
}
|
|
|
|
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
|
if (!objectp)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FSObjectProperties& details = mObjectDetails[object_id];
|
|
if (details.request != FSObjectProperties::FINISHED)
|
|
{
|
|
// We cache un-requested objects (to avoid having to request them later)
|
|
// and requested objects.
|
|
|
|
details.request = FSObjectProperties::FINISHED;
|
|
mLastProptiesRecievedTimer.start();
|
|
|
|
if (details.id.isNull())
|
|
{
|
|
// Recieved object properties without requesting it.
|
|
details.id = object_id;
|
|
}
|
|
else
|
|
{
|
|
if (mRequested > 0)
|
|
{
|
|
mRequested--;
|
|
}
|
|
mRegionRequests[details.region_handle]--;
|
|
counter_text_update = true;
|
|
}
|
|
|
|
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_CreatorID, details.creator_id, i);
|
|
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, details.owner_id, i);
|
|
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, details.group_id, i);
|
|
msg->getU64Fast(_PREHASH_ObjectData, _PREHASH_CreationDate, details.creation_date, i);
|
|
msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_BaseMask, details.base_mask, i);
|
|
msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_OwnerMask, details.owner_mask, i);
|
|
msg->getU32Fast(_PREHASH_ObjectData,_PREHASH_GroupMask, details.group_mask, i);
|
|
msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_EveryoneMask, details.everyone_mask, i);
|
|
msg->getU32Fast(_PREHASH_ObjectData, _PREHASH_NextOwnerMask, details.next_owner_mask, i);
|
|
details.sale_info.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
|
|
details.ag_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePerms, i);
|
|
details.ag_texture_perms.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTextures, i);
|
|
details.ag_texture_perms_owner.unpackMessage(msg, _PREHASH_ObjectData, _PREHASH_AggregatePermTexturesOwner, i);
|
|
details.category.unpackMultiMessage(msg, _PREHASH_ObjectData, i);
|
|
msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_LastOwnerID, details.last_owner_id, i);
|
|
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, details.name, i);
|
|
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, details.description, i);
|
|
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_TouchName, details.touch_name, i);
|
|
msg->getStringFast(_PREHASH_ObjectData, _PREHASH_SitName, details.sit_name, i);
|
|
|
|
S32 size = msg->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_TextureID);
|
|
if (size > 0)
|
|
{
|
|
S8 packed_buffer[SELECT_MAX_TES * UUID_BYTES];
|
|
msg->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureID, packed_buffer, 0, i, SELECT_MAX_TES * UUID_BYTES);
|
|
|
|
for (S32 buf_offset = 0; buf_offset < size; buf_offset += UUID_BYTES)
|
|
{
|
|
LLUUID tid;
|
|
memcpy(tid.mData, packed_buffer + buf_offset, UUID_BYTES); /* Flawfinder: ignore */
|
|
details.texture_ids.push_back(tid);
|
|
}
|
|
}
|
|
|
|
details.permissions.init(details.creator_id, details.owner_id, details.last_owner_id, details.group_id);
|
|
details.permissions.initMasks(details.base_mask, details.owner_mask, details.everyone_mask, details.group_mask, details.next_owner_mask);
|
|
|
|
// Sets the group owned BOOL and real owner id, group or owner depending if object is group owned.
|
|
details.permissions.getOwnership(details.ownership_id, details.group_owned);
|
|
|
|
LL_DEBUGS("FSAreaSearch_spammy") << "Got properties for object: " << object_id << LL_ENDL;
|
|
|
|
if (isSearchableObject(objectp, our_region))
|
|
{
|
|
matchObject(details, objectp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (counter_text_update)
|
|
{
|
|
updateCounterText();
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::matchObject(FSObjectProperties& details, LLViewerObject* objectp)
|
|
{
|
|
if (details.listed)
|
|
{
|
|
// object allready listed on the scroll list.
|
|
return;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Filters
|
|
//-----------------------------------------------------------------------
|
|
|
|
if (mFilterForSale && !(details.sale_info.isForSale() && (details.sale_info.getSalePrice() >= mFilterForSaleMin && details.sale_info.getSalePrice() <= mFilterForSaleMax)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterDistance)
|
|
{
|
|
S32 distance = dist_vec(mPanelList->getAgentLastPosition(), objectp->getPositionGlobal());// used mAgentLastPosition instead of gAgent->getPositionGlobal for performace
|
|
if (!(distance >= mFilterDistanceMin && distance <= mFilterDistanceMax))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mFilterClickAction)
|
|
{
|
|
switch(mFilterClickActionType)
|
|
{
|
|
case 0: // "(blank)", should not end up here, but just in case
|
|
break;
|
|
case 1: // "any" mouse click action
|
|
if (!(objectp->flagHandleTouch() || objectp->getClickAction() != 0))
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
case 2: // "touch" is a seperate mouse click action flag
|
|
if (!objectp->flagHandleTouch())
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
default: // all other mouse click action types
|
|
if ((mFilterClickActionType - 2) != objectp->getClickAction())
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//TODO: texture id search
|
|
// for (uuid_vec_t::const_iterator texture_it = details.texture_ids.begin();
|
|
// texture_it != details.texture_ids.end(); ++texture_it)
|
|
// {
|
|
// if ( "" == (*texture_it).asString())
|
|
// {
|
|
// }
|
|
// }
|
|
|
|
if (mFilterPhysicial && !objectp->flagUsePhysics())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterTemporary && !objectp->flagTemporaryOnRez())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterLocked && !objectp->flagObjectPermanent())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterPhantom && !objectp->flagPhantom())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterAttachment && !objectp->isAttachment())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (mFilterMoaP)
|
|
{
|
|
bool moap = false;
|
|
U8 texture_count = objectp->getNumTEs();
|
|
for(U8 i = 0; i < texture_count; i++)
|
|
{
|
|
if(objectp->getTE(i)->hasMedia())
|
|
{
|
|
moap = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!moap)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Find text
|
|
//-----------------------------------------------------------------------
|
|
|
|
LLUUID object_id = details.id;
|
|
std::string creator_name;
|
|
std::string owner_name;
|
|
std::string last_owner_name;
|
|
std::string group_name;
|
|
std::string object_name = details.name;
|
|
std::string object_description = details.description;
|
|
|
|
details.name_requested = false;
|
|
getNameFromUUID(details.ownership_id, owner_name, details.group_owned, details.name_requested);
|
|
getNameFromUUID(details.creator_id, creator_name, false, details.name_requested);
|
|
getNameFromUUID(details.last_owner_id, last_owner_name, false, details.name_requested);
|
|
getNameFromUUID(details.group_id, group_name, true, details.name_requested);
|
|
|
|
if (mRegexSearch)
|
|
{
|
|
try
|
|
{
|
|
if (!mSearchName.empty() && !boost::regex_match(object_name, mRegexSearchName))
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchDescription.empty() && !boost::regex_match(object_description, mRegexSearchDescription))
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchOwner.empty() && !boost::regex_match(owner_name, mRegexSearchOwner))
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchGroup.empty() && !boost::regex_match(group_name, mRegexSearchGroup))
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchCreator.empty() && !boost::regex_match(creator_name, mRegexSearchCreator))
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchLastOwner.empty() && !boost::regex_match(last_owner_name, mRegexSearchLastOwner))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Should not end up here due to error checking in Find class. However, some complex regexes may
|
|
// cause excessive resources and boost will throw an execption.
|
|
// Due to the possiablitey of hitting this block a 1000 times per second, only logonce it.
|
|
catch(boost::regex_error& e)
|
|
{
|
|
LL_WARNS_ONCE("FSAreaSearch") << "boost::regex_error error in regex: "<< e.what() << LL_ENDL;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
LL_WARNS_ONCE("FSAreaSearch") << "std::exception error in regex: "<< e.what() << LL_ENDL;
|
|
}
|
|
catch (...)
|
|
{
|
|
LL_WARNS_ONCE("FSAreaSearch") << "Unknown error in regex" << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!mSearchName.empty() && boost::ifind_first(object_name, mSearchName).empty())
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchDescription.empty() && boost::ifind_first(object_description, mSearchDescription).empty())
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchOwner.empty() && boost::ifind_first(owner_name, mSearchOwner).empty())
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchGroup.empty() && boost::ifind_first(group_name, mSearchGroup).empty())
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchCreator.empty() && boost::ifind_first(creator_name, mSearchCreator).empty())
|
|
{
|
|
return;
|
|
}
|
|
if (!mSearchLastOwner.empty() && boost::ifind_first(last_owner_name, mSearchLastOwner).empty())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
// Object passed all above tests, add it to the List tab.
|
|
//-----------------------------------------------------------------------
|
|
|
|
details.listed = true;
|
|
|
|
LLScrollListCell::Params cell_params;
|
|
cell_params.font = LLFontGL::getFontSansSerif();
|
|
|
|
LLScrollListItem::Params row_params;
|
|
row_params.value = object_id.asString();
|
|
|
|
if (mColumnDistance)
|
|
{
|
|
cell_params.column = "distance";
|
|
cell_params.value = llformat("%1.0f m", dist_vec(mPanelList->getAgentLastPosition(), objectp->getPositionGlobal())); // used mAgentLastPosition instead of gAgent->getPositionGlobal for performace
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnName)
|
|
{
|
|
cell_params.column = "name";
|
|
cell_params.value = details.name;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnDescription)
|
|
{
|
|
cell_params.column = "description";
|
|
cell_params.value = details.description;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnOwner)
|
|
{
|
|
cell_params.column = "owner";
|
|
cell_params.value = owner_name;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnGroup)
|
|
{
|
|
cell_params.column = "group";
|
|
cell_params.value = group_name;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnCreator)
|
|
{
|
|
cell_params.column = "creator";
|
|
cell_params.value = creator_name;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
if (mColumnLastOwner)
|
|
{
|
|
cell_params.column = "last_owner";
|
|
cell_params.value = last_owner_name;
|
|
row_params.columns.add(cell_params);
|
|
}
|
|
|
|
LLScrollListItem* list_row = mPanelList->getResultList()->addRow(row_params);
|
|
|
|
if (objectp->flagTemporaryOnRez() || objectp->flagUsePhysics())
|
|
{
|
|
U8 font_style = LLFontGL::NORMAL;
|
|
if (objectp->flagTemporaryOnRez())
|
|
{
|
|
font_style |= LLFontGL::ITALIC;
|
|
}
|
|
if (objectp->flagUsePhysics())
|
|
{
|
|
font_style |= LLFontGL::BOLD;
|
|
}
|
|
|
|
S32 num_colums = list_row->getNumColumns();
|
|
for (S32 i = 0; i < num_colums; i++)
|
|
{
|
|
LLScrollListText* list_cell = (LLScrollListText*)list_row->getColumn(i);
|
|
list_cell->setFontStyle(font_style);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::getNameFromUUID(LLUUID& id, std::string& name, BOOL group, bool& name_requested)
|
|
{
|
|
BOOL is_group;
|
|
|
|
if(!gCacheName->getIfThere(id, name, is_group))
|
|
{
|
|
if(std::find(mNamesRequested.begin(), mNamesRequested.end(), id) == mNamesRequested.end())
|
|
{
|
|
mNamesRequested.push_back(id);
|
|
gCacheName->get(id, group, boost::bind(&FSAreaSearch::callbackLoadFullName, this, _1, _2));
|
|
}
|
|
name_requested = true;
|
|
}
|
|
}
|
|
|
|
void FSAreaSearch::callbackLoadFullName(const LLUUID& id, const std::string& full_name)
|
|
{
|
|
LLViewerRegion* our_region = gAgent.getRegion();
|
|
|
|
for (std::map<LLUUID, FSObjectProperties>::iterator object_it = mObjectDetails.begin();
|
|
object_it != mObjectDetails.end();
|
|
++object_it)
|
|
{
|
|
if (object_it->second.name_requested && !object_it->second.listed)
|
|
{
|
|
LLUUID id = object_it->second.id;
|
|
LLViewerObject* objectp = gObjectList.findObject(id);
|
|
if (objectp && isSearchableObject(objectp, our_region))
|
|
{
|
|
matchObject(object_it->second, objectp);
|
|
}
|
|
}
|
|
}
|
|
|
|
mPanelList->updateName(id, full_name);
|
|
}
|
|
|
|
void FSAreaSearch::updateCounterText()
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["[LISTED]"] = llformat("%d", mPanelList->getResultList()->getItemCount());
|
|
args["[PENDING]"] = llformat("%d", mRequested);
|
|
args["[TOTAL]"] = llformat("%d", mSearchableObjects);
|
|
mPanelList->setCounterText(args);
|
|
}
|
|
|
|
void FSAreaSearch::onCommitLine()
|
|
{
|
|
mSearchName = mPanelFind->mNameLineEditor->getText();
|
|
mSearchDescription = mPanelFind->mDescriptionLineEditor->getText();
|
|
mSearchOwner = mPanelFind->mOwnerLineEditor->getText();
|
|
mSearchGroup = mPanelFind->mGroupLineEditor->getText();
|
|
mSearchCreator = mPanelFind->mCreatorLineEditor->getText();
|
|
mSearchLastOwner = mPanelFind->mLastOwnerLineEditor->getText();
|
|
|
|
if (mRegexSearch)
|
|
{
|
|
if (!mSearchName.empty())
|
|
{
|
|
if (regexTest(mSearchName))
|
|
{
|
|
mRegexSearchName = mSearchName.c_str();
|
|
}
|
|
else
|
|
{
|
|
// empty the search text to prevent error in matchObject
|
|
mSearchName.erase();
|
|
}
|
|
}
|
|
|
|
if (!mSearchDescription.empty())
|
|
{
|
|
if (regexTest(mSearchDescription))
|
|
{
|
|
mRegexSearchDescription = mSearchDescription.c_str();
|
|
}
|
|
else
|
|
{
|
|
mSearchDescription.erase();
|
|
}
|
|
}
|
|
|
|
if (!mSearchOwner.empty())
|
|
{
|
|
if (regexTest(mSearchOwner))
|
|
{
|
|
mRegexSearchOwner = mSearchOwner.c_str();
|
|
}
|
|
else
|
|
{
|
|
mSearchOwner.erase();
|
|
}
|
|
}
|
|
|
|
if (!mSearchGroup.empty())
|
|
{
|
|
if (regexTest(mSearchGroup))
|
|
{
|
|
mRegexSearchGroup = mSearchGroup.c_str();
|
|
}
|
|
else
|
|
{
|
|
mSearchGroup.erase();
|
|
}
|
|
}
|
|
|
|
if (!mSearchCreator.empty())
|
|
{
|
|
if (regexTest(mSearchCreator))
|
|
{
|
|
mRegexSearchCreator = mSearchCreator.c_str();
|
|
}
|
|
else
|
|
{
|
|
mSearchCreator.erase();
|
|
}
|
|
}
|
|
|
|
if (!mSearchLastOwner.empty())
|
|
{
|
|
if (regexTest(mSearchLastOwner))
|
|
{
|
|
mRegexSearchLastOwner = mSearchLastOwner.c_str();
|
|
}
|
|
else
|
|
{
|
|
mSearchLastOwner.erase();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FSAreaSearch::regexTest(std::string text)
|
|
{
|
|
// couple regex patters one can use for testing. The regex will match a UUID.
|
|
// boost::regex pattern("[\\w]{8}-[\\w]{4}-[\\w]{4}-[\\w]{4}-[\\w]{12}");
|
|
// [\p{XDigit}]{8}(-[\p{XDigit}]{4}){3}-[\p{XDigit}]{12}
|
|
// to find all objects that don't belong to a group, use (?!^Name of the group$).* in the group field.
|
|
|
|
try
|
|
{
|
|
std::string test_text = "asdfghjklqwerty1234567890";
|
|
boost::regex pattern(text.c_str());
|
|
boost::regex_match(test_text, pattern);
|
|
}
|
|
catch(boost::regex_error& e)
|
|
{
|
|
LLSD args;
|
|
args["EWHAT"] = e.what();
|
|
LLNotificationsUtil::add("RegExFail", args);
|
|
LL_DEBUGS("FSAreaSearch") << "boost::regex_error error in regex: "<< e.what() << LL_ENDL;
|
|
return false;
|
|
}
|
|
catch(const std::exception& e)
|
|
{
|
|
LLSD args;
|
|
args["EWHAT"] = e.what();
|
|
LLNotificationsUtil::add("RegExFail", args);
|
|
LL_DEBUGS("FSAreaSearch") << "std::exception error in regex: "<< e.what() << LL_ENDL;
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
LLSD args;
|
|
args["EWHAT"] = "Unknown Error.";
|
|
LLNotificationsUtil::add("RegExFail", args);
|
|
LL_DEBUGS("FSAreaSearch") << "Unknown error in regex" << LL_ENDL;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FSAreaSearch::clearSearchText()
|
|
{
|
|
mSearchName.erase();
|
|
mSearchDescription.erase();
|
|
mSearchOwner.erase();
|
|
mSearchGroup.erase();
|
|
mSearchCreator.erase();
|
|
mSearchLastOwner.erase();
|
|
}
|
|
|
|
void FSAreaSearch::onButtonClickedSearch()
|
|
{
|
|
// if the user blanks out a line, onCommitLine is not fired/called.
|
|
// calling this will make sure to update any blanked out lines.
|
|
onCommitLine();
|
|
|
|
mTab->selectFirstTab();
|
|
refreshList(false);
|
|
}
|
|
|
|
void FSAreaSearch::onCommitCheckboxRegex()
|
|
{
|
|
mRegexSearch = mPanelFind->mCheckboxRegex->get();
|
|
|
|
if (mRegexSearch)
|
|
{
|
|
onCommitLine();
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// List panel
|
|
//---------------------------------------------------------------------------
|
|
|
|
FSPanelAreaSearchList::FSPanelAreaSearchList(FSAreaSearch* pointer)
|
|
: LLPanel(),
|
|
mCounterText(0),
|
|
mResultList(0),
|
|
mFSAreaSearch(pointer)
|
|
{
|
|
// Set up context menu.
|
|
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
|
|
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
|
|
|
|
registrar.add("AreaSearch.Action", boost::bind(&FSPanelAreaSearchList::onContextMenuItemClick, this, _2));
|
|
enable_registrar.add("AreaSearch.Enable", boost::bind(&FSPanelAreaSearchList::onContextMenuItemEnable, this, _2));
|
|
|
|
mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
|
|
"menu_fs_area_search.xml", LLContextMenu::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());
|
|
}
|
|
|
|
BOOL FSPanelAreaSearchList::postBuild()
|
|
{
|
|
mResultList = getChild<LLScrollListCtrl>("result_list");
|
|
mResultList->setDoubleClickCallback(boost::bind(&FSPanelAreaSearchList::onDoubleClick, this));
|
|
mResultList->sortByColumn("name", TRUE);
|
|
|
|
mCounterText = getChild<LLTextBox>("counter");
|
|
|
|
mRefreshButton = getChild<LLButton>("Refresh");
|
|
mRefreshButton->setClickedCallback(boost::bind(&FSPanelAreaSearchList::onClickRefresh, this));
|
|
|
|
mCheckboxBeacons = getChild<LLCheckBoxCtrl>("beacons");
|
|
mCheckboxBeacons->setCommitCallback(boost::bind(&FSPanelAreaSearchList::onCommitCheckboxBeacons, this));
|
|
|
|
mAgentLastPosition = gAgent.getPositionGlobal();
|
|
|
|
return LLPanel::postBuild();
|
|
}
|
|
|
|
// virtual
|
|
FSPanelAreaSearchList::~FSPanelAreaSearchList()
|
|
{ }
|
|
|
|
void FSPanelAreaSearchList::onClickRefresh()
|
|
{
|
|
mFSAreaSearch->refreshList(true);
|
|
}
|
|
|
|
void FSPanelAreaSearchList::onCommitCheckboxBeacons()
|
|
{
|
|
mFSAreaSearch->setBeacons(mCheckboxBeacons->get());
|
|
}
|
|
|
|
void FSPanelAreaSearchList::setCounterText()
|
|
{
|
|
mCounterText->setText(getString("ListedPendingTotalBlank"));
|
|
}
|
|
|
|
void FSPanelAreaSearchList::setCounterText(LLStringUtil::format_map_t args)
|
|
{
|
|
mCounterText->setText(getString("ListedPendingTotalFilled", args));
|
|
}
|
|
|
|
void FSPanelAreaSearchList::onDoubleClick()
|
|
{
|
|
LLScrollListItem *item = mResultList->getFirstSelected();
|
|
if (!item) return;
|
|
LLUUID object_id = item->getUUID();
|
|
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
|
if (objectp)
|
|
{
|
|
FSObjectProperties& details = mFSAreaSearch->mObjectDetails[object_id];
|
|
LLTracker::trackLocation(objectp->getPositionGlobal(), details.name, "", LLTracker::LOCATION_ITEM);
|
|
|
|
if (mFSAreaSearch->getPanelAdvanced()->mCheckboxClickBuy->get())
|
|
{
|
|
buyObject(details, objectp);
|
|
}
|
|
|
|
if (mFSAreaSearch->getPanelAdvanced()->mCheckboxClickTouch->get())
|
|
{
|
|
touchObject(objectp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSPanelAreaSearchList::updateScrollList()
|
|
{
|
|
bool agent_moved = false;
|
|
const LLVector3d current_agent_position = gAgent.getPositionGlobal();
|
|
|
|
if (dist_vec(mAgentLastPosition, current_agent_position) > MIN_DISTANCE_MOVED)
|
|
{
|
|
agent_moved = true;
|
|
mAgentLastPosition = current_agent_position;
|
|
}
|
|
|
|
bool deleted = false;
|
|
LLScrollListColumn* distance_column = mResultList->getColumn("distance");
|
|
LLViewerRegion* our_region = gAgent.getRegion();
|
|
|
|
// Iterate over the rows in the list, deleting ones whose object has gone away.
|
|
std::vector<LLScrollListItem*> items = mResultList->getAllData();
|
|
for (std::vector<LLScrollListItem*>::iterator item_it = items.begin();
|
|
item_it != items.end();
|
|
++item_it)
|
|
{
|
|
LLScrollListItem* item = (*item_it);
|
|
LLUUID row_id = item->getUUID();
|
|
LLViewerObject* objectp = gObjectList.findObject(row_id);
|
|
|
|
if ((!objectp) || (!mFSAreaSearch->isSearchableObject(objectp, our_region)))
|
|
{
|
|
// This item's object has been deleted -- remove the row.
|
|
// Removing the row won't throw off our iteration, since we have a local copy of the array.
|
|
// We just need to make sure we don't access this item after the delete.
|
|
mResultList->deleteSingleItem(mResultList->getItemIndex(row_id));
|
|
|
|
mFSAreaSearch->mObjectDetails[row_id].listed = false ;
|
|
deleted = true;
|
|
}
|
|
else
|
|
{
|
|
if (agent_moved && distance_column)
|
|
{
|
|
item->getColumn(distance_column->mIndex)->setValue(LLSD(llformat("%1.0f m", dist_vec(current_agent_position, objectp->getPositionGlobal()))));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (deleted || agent_moved)
|
|
{
|
|
mResultList->updateLayout();
|
|
}
|
|
}
|
|
|
|
void FSPanelAreaSearchList::updateName(LLUUID id, std::string name)
|
|
{
|
|
LLScrollListColumn* creator_column = mResultList->getColumn("creator");
|
|
LLScrollListColumn* owner_column = mResultList->getColumn("owner");
|
|
LLScrollListColumn* group_column = mResultList->getColumn("group");
|
|
LLScrollListColumn* last_owner_column = mResultList->getColumn("last_owner");
|
|
|
|
// Iterate over the rows in the list, updating the ones with matching id.
|
|
std::vector<LLScrollListItem*> items = mResultList->getAllData();
|
|
|
|
for (std::vector<LLScrollListItem*>::iterator item_it = items.begin();
|
|
item_it != items.end();
|
|
++item_it)
|
|
{
|
|
LLScrollListItem* item = (*item_it);
|
|
LLUUID row_id = item->getUUID();
|
|
FSObjectProperties& details = mFSAreaSearch->mObjectDetails[row_id];
|
|
|
|
if (creator_column && (id == details.creator_id))
|
|
{
|
|
LLScrollListText* creator_text = (LLScrollListText*)item->getColumn(creator_column->mIndex);
|
|
creator_text->setText(name);
|
|
}
|
|
|
|
if (owner_column && (id == details.owner_id))
|
|
{
|
|
LLScrollListText* owner_text = (LLScrollListText*)item->getColumn(owner_column->mIndex);
|
|
owner_text->setText(name);
|
|
}
|
|
|
|
if (group_column && (id == details.group_id))
|
|
{
|
|
LLScrollListText* group_text = (LLScrollListText*)item->getColumn(group_column->mIndex);
|
|
group_text->setText(name);
|
|
}
|
|
|
|
if (last_owner_column && (id == details.last_owner_id))
|
|
{
|
|
LLScrollListText* last_owner_text = (LLScrollListText*)item->getColumn(last_owner_column->mIndex);
|
|
last_owner_text->setText(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// virtual
|
|
BOOL FSPanelAreaSearchList::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
|
{
|
|
BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask);
|
|
|
|
// BUG: hitItem is off by three rows up.
|
|
// when fixed, selectByID(item->getValue()) if nothing was selected.
|
|
// LLScrollListItem *item = mResultList->hitItem(x, y);
|
|
// if (item)
|
|
// {
|
|
// mResultList->selectByID(item->getValue());
|
|
//
|
|
// }
|
|
|
|
if (mPopupMenu)
|
|
{
|
|
if (mResultList->getNumSelected() !=0)
|
|
{
|
|
mPopupMenu->show(x, y);
|
|
LLMenuGL::showPopup(this, mPopupMenu, x, y);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
bool FSPanelAreaSearchList::onContextMenuItemEnable(const LLSD& userdata)
|
|
{
|
|
std::string parameter = userdata.asString();
|
|
if (parameter == "one")
|
|
{
|
|
// return true if just one item is selected.
|
|
return (mResultList->getNumSelected() == 1);
|
|
}
|
|
else
|
|
{
|
|
// return true if more then one is selected, but not just one.
|
|
return (mResultList->getNumSelected() > 1);
|
|
}
|
|
}
|
|
|
|
bool FSPanelAreaSearchList::onContextMenuItemClick(const LLSD& userdata)
|
|
{
|
|
std::string action = userdata.asString();
|
|
LL_DEBUGS("FSAreaSearch") << "Right click menu " << action << " was selected." << LL_ENDL;
|
|
|
|
// NOTE that each action command MUST begin with a different letter.
|
|
char c = action.at(0);
|
|
switch(c)
|
|
{
|
|
case 't': // touch
|
|
case 's': // script
|
|
case 'l': // blacklist
|
|
{
|
|
std::vector<LLScrollListItem*> selected = mResultList->getAllSelected();
|
|
|
|
for(std::vector<LLScrollListItem*>::iterator item_it = selected.begin();
|
|
item_it != selected.end(); ++item_it)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 't': // touch
|
|
{
|
|
LLViewerObject* objectp = gObjectList.findObject((*item_it)->getUUID());
|
|
if (objectp)
|
|
{
|
|
touchObject(objectp);
|
|
}
|
|
}
|
|
break;
|
|
case 's': // script
|
|
FSLSLBridge::instance().viewerToLSL("getScriptInfo|" + (*item_it)->getUUID().asString());
|
|
break;
|
|
case 'l': // blacklist
|
|
{
|
|
LLUUID object_id = (*item_it)->getUUID();
|
|
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
|
if (objectp)
|
|
{
|
|
std::string region_name;
|
|
LLViewerRegion* region = objectp->getRegion();
|
|
if (region)
|
|
{
|
|
region_name = objectp->getRegion()->getName();
|
|
}
|
|
FSWSAssetBlacklist::getInstance()->addNewItemToBlacklist(object_id, mFSAreaSearch->mObjectDetails[object_id].name, region_name, LLAssetType::AT_OBJECT);
|
|
gObjectList.killObject(objectp);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'b': // buy
|
|
case 'p': // p_teleport
|
|
{
|
|
LLUUID object_id = mResultList->getFirstSelected()->getUUID();
|
|
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
|
if (objectp)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'b': // buy
|
|
buyObject(mFSAreaSearch->mObjectDetails[object_id], objectp);
|
|
break;
|
|
case 'p': // p_teleport
|
|
gAgent.teleportViaLocation(objectp->getPositionGlobal());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'i': // inspect
|
|
case 'e': // edit
|
|
case 'd': // delete
|
|
case 'r': // return
|
|
{
|
|
// select the objects first
|
|
LLSelectMgr::getInstance()->deselectAll();
|
|
std::vector<LLScrollListItem*> selected = mResultList->getAllSelected();
|
|
|
|
for(std::vector<LLScrollListItem*>::iterator item_it = selected.begin();
|
|
item_it != selected.end(); ++item_it)
|
|
{
|
|
LLUUID object_id = (*item_it)->getUUID();
|
|
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
|
if (objectp)
|
|
{
|
|
LLSelectMgr::getInstance()->selectObjectAndFamily(objectp);
|
|
if ( c == 'r' )
|
|
{
|
|
// need to set permissions for object return
|
|
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->findNode(objectp);
|
|
FSObjectProperties& details = mFSAreaSearch->mObjectDetails[object_id];
|
|
node->mValid = TRUE;
|
|
node->mPermissions->init(details.creator_id, details.owner_id, details.last_owner_id, details.group_id);
|
|
node->mPermissions->initMasks(details.base_mask, details.owner_mask, details.everyone_mask, details.group_mask, details.next_owner_mask);
|
|
node->mAggregatePerm = details.ag_perms;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now act on those selected objects
|
|
switch (c)
|
|
{
|
|
case 'i': // inspect
|
|
LLFloaterReg::showInstance("inspect");
|
|
break;
|
|
case 'e': // edit
|
|
handle_object_edit();
|
|
break;
|
|
case 'd': // delete
|
|
handle_object_delete();
|
|
break;
|
|
case 'r': // return
|
|
handle_object_return();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void FSPanelAreaSearchList::touchObject(LLViewerObject* objectp)
|
|
{
|
|
// *NOTE: Hope the packets arrive safely and in order or else
|
|
// there will be some problems.
|
|
LLPickInfo pick; // default constructor will set sane values.
|
|
send_ObjectGrab_message(objectp, pick, LLVector3::zero);
|
|
send_ObjectDeGrab_message(objectp, pick);
|
|
}
|
|
|
|
void FSPanelAreaSearchList::buyObject(FSObjectProperties& details, LLViewerObject* objectp)
|
|
{
|
|
LLSelectMgr::getInstance()->deselectAll();
|
|
LLSelectMgr::getInstance()->selectObjectAndFamily(objectp);
|
|
LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->findNode(objectp);
|
|
|
|
if (node)
|
|
{
|
|
node->mValid = TRUE;
|
|
node->mPermissions->init(details.creator_id, details.owner_id, details.last_owner_id, details.group_id);
|
|
node->mPermissions->initMasks(details.base_mask, details.owner_mask, details.everyone_mask, details.group_mask, details.next_owner_mask);
|
|
node->mSaleInfo = details.sale_info;
|
|
node->mAggregatePerm = details.ag_perms;
|
|
node->mCategory = details.category;
|
|
node->mName.assign(details.name);
|
|
node->mDescription.assign(details.description);
|
|
|
|
handle_buy();
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("FSAreaSearch") << "No LLSelectNode node" << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Find panel
|
|
//---------------------------------------------------------------------------
|
|
|
|
FSPanelAreaSearchFind::FSPanelAreaSearchFind(FSAreaSearch* pointer)
|
|
: LLPanel(),
|
|
mFSAreaSearch(pointer)
|
|
{
|
|
}
|
|
|
|
BOOL FSPanelAreaSearchFind::postBuild()
|
|
{
|
|
mNameLineEditor = getChild<LLLineEditor>("name_search");
|
|
mNameLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mDescriptionLineEditor = getChild<LLLineEditor>("description_search");
|
|
mDescriptionLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mOwnerLineEditor = getChild<LLLineEditor>("owner_search");
|
|
mOwnerLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mGroupLineEditor = getChild<LLLineEditor>("group_search");
|
|
mGroupLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mCreatorLineEditor = getChild<LLLineEditor>("creator_search");
|
|
mCreatorLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mLastOwnerLineEditor = getChild<LLLineEditor>("last_owner_search");
|
|
mLastOwnerLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch));
|
|
|
|
mCheckboxRegex = getChild<LLCheckBoxCtrl>("regular_expression");
|
|
mCheckboxRegex->setCommitCallback(boost::bind(&FSAreaSearch::onCommitCheckboxRegex, mFSAreaSearch));
|
|
|
|
mSearchButton = getChild<LLButton>("search");
|
|
mSearchButton->setClickedCallback(boost::bind(&FSAreaSearch::onButtonClickedSearch, mFSAreaSearch));
|
|
|
|
mClearButton = getChild<LLButton>("clear");
|
|
mClearButton->setClickedCallback(boost::bind(&FSPanelAreaSearchFind::onButtonClickedClear, this));
|
|
|
|
return LLPanel::postBuild();
|
|
}
|
|
|
|
// virtual
|
|
FSPanelAreaSearchFind::~FSPanelAreaSearchFind()
|
|
{ }
|
|
|
|
void FSPanelAreaSearchFind::onButtonClickedClear()
|
|
{
|
|
mNameLineEditor->clear();
|
|
mDescriptionLineEditor->clear();
|
|
mOwnerLineEditor->clear();
|
|
mGroupLineEditor->clear();
|
|
mCreatorLineEditor->clear();
|
|
mLastOwnerLineEditor->clear();
|
|
mFSAreaSearch->clearSearchText();
|
|
}
|
|
|
|
// handle the "enter" key
|
|
BOOL FSPanelAreaSearchFind::handleKeyHere(KEY key, MASK mask)
|
|
{
|
|
if( KEY_RETURN == key )
|
|
{
|
|
mFSAreaSearch->onButtonClickedSearch();
|
|
return TRUE;
|
|
}
|
|
|
|
return LLPanel::handleKeyHere(key, mask);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Filter panel
|
|
//---------------------------------------------------------------------------
|
|
|
|
FSPanelAreaSearchFilter::FSPanelAreaSearchFilter(FSAreaSearch* pointer)
|
|
: LLPanel(),
|
|
mFSAreaSearch(pointer)
|
|
{
|
|
}
|
|
|
|
BOOL FSPanelAreaSearchFilter::postBuild()
|
|
{
|
|
mCheckboxLocked = getChild<LLCheckBoxCtrl>("filter_locked");
|
|
mCheckboxLocked->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxPhysical = getChild<LLCheckBoxCtrl>("filter_physical");
|
|
mCheckboxPhysical->setEnabled(FALSE);
|
|
mCheckboxPhysical->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxTemporary = getChild<LLCheckBoxCtrl>("filter_temporary");
|
|
mCheckboxTemporary->setEnabled(FALSE);
|
|
mCheckboxTemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxPhantom = getChild<LLCheckBoxCtrl>("filter_phantom");
|
|
mCheckboxPhantom->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxForSale = getChild<LLCheckBoxCtrl>("filter_for_sale");
|
|
mCheckboxForSale->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxAttachment = getChild<LLCheckBoxCtrl>("filter_attachment");
|
|
mCheckboxAttachment->setEnabled(FALSE);
|
|
mCheckboxAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mSpinForSaleMinValue= getChild<LLSpinCtrl>("min_price");
|
|
mSpinForSaleMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
|
|
|
|
mSpinForSaleMaxValue= getChild<LLSpinCtrl>("max_price");
|
|
mSpinForSaleMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
|
|
|
|
mComboClickAction = getChild<LLComboBox>("click_action");
|
|
mComboClickAction->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCombo, this));
|
|
|
|
mCheckboxExcludeAttachment = getChild<LLCheckBoxCtrl>("exclude_attachment");
|
|
mCheckboxExcludeAttachment->set(TRUE);
|
|
mCheckboxExcludeAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxExcludePhysics = getChild<LLCheckBoxCtrl>("exclude_physical");
|
|
mCheckboxExcludePhysics->set(TRUE);
|
|
mCheckboxExcludePhysics->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxExcludeTempary = getChild<LLCheckBoxCtrl>("exclude_temporary");
|
|
mCheckboxExcludeTempary->set(TRUE);
|
|
mCheckboxExcludeTempary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxExcludeChildPrim = getChild<LLCheckBoxCtrl>("exclude_childprim");
|
|
mCheckboxExcludeChildPrim->set(TRUE);
|
|
mCheckboxExcludeChildPrim->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mCheckboxExcludeNeighborRegines = getChild<LLCheckBoxCtrl>("exclude_neighbor_regine");
|
|
mCheckboxExcludeNeighborRegines->set(TRUE);
|
|
mCheckboxExcludeNeighborRegines->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mButtonApply = getChild<LLButton>("apply");
|
|
mButtonApply->setClickedCallback(boost::bind(&FSAreaSearch::onButtonClickedSearch, mFSAreaSearch));
|
|
|
|
mCheckboxDistance = getChild<LLCheckBoxCtrl>("filter_distance");
|
|
mCheckboxDistance->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
mSpinDistanceMinValue = getChild<LLSpinCtrl>("min_distance");
|
|
mSpinDistanceMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
|
|
|
|
mSpinDistanceMaxValue= getChild<LLSpinCtrl>("max_distance");
|
|
mSpinDistanceMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this));
|
|
|
|
mCheckboxMoaP = getChild<LLCheckBoxCtrl>("filter_moap");
|
|
mCheckboxMoaP->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this));
|
|
|
|
return LLPanel::postBuild();
|
|
}
|
|
|
|
// virtual
|
|
FSPanelAreaSearchFilter::~FSPanelAreaSearchFilter()
|
|
{ }
|
|
|
|
void FSPanelAreaSearchFilter::onCommitCheckbox()
|
|
{
|
|
mFSAreaSearch->setFilterLocked(mCheckboxLocked->get());
|
|
mFSAreaSearch->setFilterPhantom(mCheckboxPhantom->get());
|
|
mFSAreaSearch->setFilterForSale(mCheckboxForSale->get());
|
|
mFSAreaSearch->setFilterDistance(mCheckboxDistance->get());
|
|
mFSAreaSearch->setFilterMoaP(mCheckboxMoaP->get());
|
|
|
|
if (mCheckboxExcludePhysics->get())
|
|
{
|
|
mFSAreaSearch->setFilterPhysicial(false);
|
|
mCheckboxPhysical->set(FALSE);
|
|
mCheckboxPhysical->setEnabled(FALSE);
|
|
mFSAreaSearch->setExcludePhysics(true);
|
|
}
|
|
else
|
|
{
|
|
mCheckboxPhysical->setEnabled(TRUE);
|
|
mFSAreaSearch->setExcludePhysics(false);
|
|
}
|
|
mFSAreaSearch->setFilterPhysicial(mCheckboxPhysical->get());
|
|
|
|
if (mCheckboxExcludeTempary->get())
|
|
{
|
|
mFSAreaSearch->setFilterTemporary(false);
|
|
mCheckboxTemporary->set(FALSE);
|
|
mCheckboxTemporary->setEnabled(FALSE);
|
|
mFSAreaSearch->setExcludeTempary(true);
|
|
}
|
|
else
|
|
{
|
|
mCheckboxTemporary->setEnabled(TRUE);
|
|
mFSAreaSearch->setExcludeTempary(false);
|
|
}
|
|
mFSAreaSearch->setFilterTemporary(mCheckboxTemporary->get());
|
|
|
|
if (mCheckboxExcludeAttachment->get())
|
|
{
|
|
mFSAreaSearch->setFilterAttachment(false);
|
|
mCheckboxAttachment->set(FALSE);
|
|
mCheckboxAttachment->setEnabled(FALSE);
|
|
mFSAreaSearch->setExcludeAttachment(true);
|
|
}
|
|
else
|
|
{
|
|
mCheckboxAttachment->setEnabled(TRUE);
|
|
mFSAreaSearch->setExcludeAttachment(false);
|
|
}
|
|
mFSAreaSearch->setFilterAttachment(mCheckboxAttachment->get());
|
|
|
|
mFSAreaSearch->setExcludeChildPrims(mCheckboxExcludeChildPrim->get());
|
|
|
|
mFSAreaSearch->setExcludeNeighborRegines(mCheckboxExcludeNeighborRegines->get());
|
|
}
|
|
|
|
void FSPanelAreaSearchFilter::onCommitSpin()
|
|
{
|
|
mFSAreaSearch->setFilterForSaleMin(mSpinForSaleMinValue->getValue().asInteger());
|
|
mFSAreaSearch->setFilterForSaleMax(mSpinForSaleMaxValue->getValue().asInteger());
|
|
|
|
mFSAreaSearch->setFilterDistanceMin(mSpinDistanceMinValue->getValue().asInteger());
|
|
mFSAreaSearch->setFilterDistanceMax(mSpinDistanceMaxValue->getValue().asInteger());
|
|
}
|
|
|
|
void FSPanelAreaSearchFilter::onCommitCombo()
|
|
{
|
|
if (mComboClickAction->getCurrentIndex() > 0)
|
|
{
|
|
mFSAreaSearch->setFilterClickAction(true);
|
|
mFSAreaSearch->setFilterClickActionType((U8)mComboClickAction->getCurrentIndex());
|
|
}
|
|
else
|
|
{
|
|
mFSAreaSearch->setFilterClickAction(false);
|
|
mFSAreaSearch->setFilterClickActionType(0);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Options tab
|
|
//---------------------------------------------------------------------------
|
|
|
|
FSPanelAreaSearchOptions::FSPanelAreaSearchOptions(FSAreaSearch* pointer)
|
|
: LLPanel(),
|
|
mFSAreaSearch(pointer)
|
|
{
|
|
mCommitCallbackRegistrar.add("AreaSearch.DisplayColumn", boost::bind(&FSPanelAreaSearchOptions::onCommitCheckboxDisplayColumn, this, _2));
|
|
}
|
|
|
|
// virtual
|
|
FSPanelAreaSearchOptions::~FSPanelAreaSearchOptions()
|
|
{ }
|
|
|
|
void FSPanelAreaSearchOptions::onCommitCheckboxDisplayColumn(const LLSD& userdata)
|
|
{
|
|
std::string column_name = userdata.asString();
|
|
if (column_name.empty())
|
|
{
|
|
LL_WARNS("FSAreaSearch") << "Missing action text." << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLScrollListCtrl* result_list = mFSAreaSearch->getPanelList()->getResultList();
|
|
result_list->deleteAllItems();
|
|
LLCheckBoxCtrl* checkboxctrl = getChild<LLCheckBoxCtrl>("show_" + column_name);
|
|
|
|
if (checkboxctrl)
|
|
{
|
|
if (checkboxctrl->get())
|
|
{
|
|
result_list->addColumn(mColumnParms[column_name]);
|
|
}
|
|
else
|
|
{
|
|
mColumnParms[column_name] = result_list->delColumn(column_name);
|
|
}
|
|
}
|
|
|
|
// untill C++ supports variable withen a variablname, have to do this instead.
|
|
// used switch instead of a huge if then else if then else...
|
|
char c = column_name.at(0);
|
|
switch(c)
|
|
{
|
|
case 'd':
|
|
{
|
|
char d = column_name.at(1);
|
|
switch (d)
|
|
{
|
|
case 'i':
|
|
{
|
|
mFSAreaSearch->setColumnDistance(checkboxctrl->get());
|
|
}
|
|
break;
|
|
case 'e':
|
|
{
|
|
mFSAreaSearch->setColumnDescription(checkboxctrl->get());
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 'n':
|
|
{
|
|
mFSAreaSearch->setColumnName(checkboxctrl->get());
|
|
}
|
|
break;
|
|
case 'o':
|
|
{
|
|
mFSAreaSearch->setColumnOwner(checkboxctrl->get());
|
|
}
|
|
break;
|
|
case 'g':
|
|
{
|
|
mFSAreaSearch->setColumnGroup(checkboxctrl->get());
|
|
}
|
|
break;
|
|
case 'c':
|
|
{
|
|
mFSAreaSearch->setColumnCreator(checkboxctrl->get());
|
|
}
|
|
break;
|
|
case 'l':
|
|
{
|
|
mFSAreaSearch->setColumnLastOwner(checkboxctrl->get());
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
result_list->updateLayout();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Advanced tab
|
|
//---------------------------------------------------------------------------
|
|
|
|
FSPanelAreaSearchAdvanced::FSPanelAreaSearchAdvanced(FSAreaSearch* pointer)
|
|
: LLPanel(),
|
|
mFSAreaSearch(pointer)
|
|
{
|
|
}
|
|
|
|
BOOL FSPanelAreaSearchAdvanced::postBuild()
|
|
{
|
|
mCheckboxClickTouch = getChild<LLCheckBoxCtrl>("double_click_touch");
|
|
mCheckboxClickBuy = getChild<LLCheckBoxCtrl>("double_click_buy");
|
|
|
|
return LLPanel::postBuild();
|
|
}
|
|
|
|
// virtual
|
|
FSPanelAreaSearchAdvanced::~FSPanelAreaSearchAdvanced()
|
|
{ }
|
|
|