/** * @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 //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), mExcludeTemporary(true), mExcludePhysics(true), mExcludeChildPrims(true), mExcludeNeighborRegions(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("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 items = mPanelList->getResultList()->getAllData(); for (std::vector::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 (!mExcludeNeighborRegions) { std::vector uniqueRegions; region->getNeighboringRegions(uniqueRegions); if(std::find(uniqueRegions.begin(), uniqueRegions.end(), mLastRegion) != uniqueRegions.end()) { // Crossed into a neighboring region, no need to clear everything. mLastRegion = region; return; } // else teleported into a new region } 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::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::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 region 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 (mExcludeNeighborRegions && !(objectp->getRegion() == our_region)) { return false; } if (mExcludeAttachment && objectp->isAttachment()) { return false; } if (mExcludePhysics && objectp->flagUsePhysics()) { return false; } if (mExcludeTemporary && 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::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 request_list; bool need_continue = false; for (std::map::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& request_list, bool select, LLViewerRegion* regionp) { bool start_new_message = true; S32 select_count = 0; LLMessageSystem* msg = gMessageSystem; for (std::vector::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::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( "menu_fs_area_search.xml", LLContextMenu::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); } BOOL FSPanelAreaSearchList::postBuild() { mResultList = getChild("result_list"); mResultList->setDoubleClickCallback(boost::bind(&FSPanelAreaSearchList::onDoubleClick, this)); mResultList->sortByColumn("name", TRUE); mCounterText = getChild("counter"); mRefreshButton = getChild("Refresh"); mRefreshButton->setClickedCallback(boost::bind(&FSPanelAreaSearchList::onClickRefresh, this)); mCheckboxBeacons = getChild("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 items = mResultList->getAllData(); for (std::vector::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 items = mResultList->getAllData(); for (std::vector::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 selected = mResultList->getAllSelected(); for(std::vector::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 selected = mResultList->getAllSelected(); for(std::vector::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); if( !node ) break; if( !mFSAreaSearch || mFSAreaSearch->mObjectDetails.end() == mFSAreaSearch->mObjectDetails.find(object_id ) ) break; 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("name_search"); mNameLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mDescriptionLineEditor = getChild("description_search"); mDescriptionLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mOwnerLineEditor = getChild("owner_search"); mOwnerLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mGroupLineEditor = getChild("group_search"); mGroupLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mCreatorLineEditor = getChild("creator_search"); mCreatorLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mLastOwnerLineEditor = getChild("last_owner_search"); mLastOwnerLineEditor->setCommitCallback(boost::bind(&FSAreaSearch::onCommitLine, mFSAreaSearch)); mCheckboxRegex = getChild("regular_expression"); mCheckboxRegex->setCommitCallback(boost::bind(&FSAreaSearch::onCommitCheckboxRegex, mFSAreaSearch)); mSearchButton = getChild("search"); mSearchButton->setClickedCallback(boost::bind(&FSAreaSearch::onButtonClickedSearch, mFSAreaSearch)); mClearButton = getChild("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("filter_locked"); mCheckboxLocked->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxPhysical = getChild("filter_physical"); mCheckboxPhysical->setEnabled(FALSE); mCheckboxPhysical->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxTemporary = getChild("filter_temporary"); mCheckboxTemporary->setEnabled(FALSE); mCheckboxTemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxPhantom = getChild("filter_phantom"); mCheckboxPhantom->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxForSale = getChild("filter_for_sale"); mCheckboxForSale->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxAttachment = getChild("filter_attachment"); mCheckboxAttachment->setEnabled(FALSE); mCheckboxAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mSpinForSaleMinValue= getChild("min_price"); mSpinForSaleMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this)); mSpinForSaleMaxValue= getChild("max_price"); mSpinForSaleMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this)); mComboClickAction = getChild("click_action"); mComboClickAction->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCombo, this)); mCheckboxExcludeAttachment = getChild("exclude_attachment"); mCheckboxExcludeAttachment->set(TRUE); mCheckboxExcludeAttachment->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxExcludePhysics = getChild("exclude_physical"); mCheckboxExcludePhysics->set(TRUE); mCheckboxExcludePhysics->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxExcludetemporary = getChild("exclude_temporary"); mCheckboxExcludetemporary->set(TRUE); mCheckboxExcludetemporary->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxExcludeChildPrim = getChild("exclude_childprim"); mCheckboxExcludeChildPrim->set(TRUE); mCheckboxExcludeChildPrim->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mCheckboxExcludeNeighborRegions = getChild("exclude_neighbor_region"); mCheckboxExcludeNeighborRegions->set(TRUE); mCheckboxExcludeNeighborRegions->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mButtonApply = getChild("apply"); mButtonApply->setClickedCallback(boost::bind(&FSAreaSearch::onButtonClickedSearch, mFSAreaSearch)); mCheckboxDistance = getChild("filter_distance"); mCheckboxDistance->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitCheckbox, this)); mSpinDistanceMinValue = getChild("min_distance"); mSpinDistanceMinValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this)); mSpinDistanceMaxValue= getChild("max_distance"); mSpinDistanceMaxValue->setCommitCallback(boost::bind(&FSPanelAreaSearchFilter::onCommitSpin, this)); mCheckboxMoaP = getChild("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 (mCheckboxExcludetemporary->get()) { mFSAreaSearch->setFilterTemporary(false); mCheckboxTemporary->set(FALSE); mCheckboxTemporary->setEnabled(FALSE); mFSAreaSearch->setExcludetemporary(true); } else { mCheckboxTemporary->setEnabled(TRUE); mFSAreaSearch->setExcludetemporary(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->setExcludeNeighborRegions(mCheckboxExcludeNeighborRegions->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("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("double_click_touch"); mCheckboxClickBuy = getChild("double_click_buy"); return LLPanel::postBuild(); } // virtual FSPanelAreaSearchAdvanced::~FSPanelAreaSearchAdvanced() { }