diff options
| author | mobserveur <mobserveur@gmail.com> | 2024-07-23 03:06:59 +0200 | 
|---|---|---|
| committer | mobserveur <mobserveur@gmail.com> | 2024-07-23 03:06:59 +0200 | 
| commit | 17e9bcbf628aa5bda84a36fc7daa9c6041e1bada (patch) | |
| tree | b3002ee1f89bd9d97513de29f9cfe566932d6e97 | |
| parent | 7bb6ea9103228b3bf3b28792d8d73e8616471908 (diff) | |
Legacy search floater
This commit adds the legacy search floater to megapahit
49 files changed, 5410 insertions, 69 deletions
| diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 370d458eb8..c24c850a86 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -118,6 +118,9 @@ void LLTemplateMessageReader::getData(const char *blockname, const char *varname      {          switch( vardata_size )          { +        case 0: +            // This is here to prevent a memcpy from a null value which is undefined behavior. +            break;          case 1:              *((U8*)datap) = *((U8*)vardata.getData());              break; @@ -286,7 +289,7 @@ void LLTemplateMessageReader::getU8(const char *block, const char *var,  void LLTemplateMessageReader::getBOOL(const char *block, const char *var,                                            BOOL &b, S32 blocknum )  { -    U8 value; +    U8 value(0);      getData(block, var, &value, sizeof(U8), blocknum);      b = (BOOL) value;  } @@ -445,7 +448,7 @@ S32 LLTemplateMessageReader::getMessageSize() const  // Returns template for the message contained in buffer  BOOL LLTemplateMessageReader::decodeTemplate(          const U8* buffer, S32 buffer_size,  // inputs -        LLMessageTemplate** msg_template ) // outputs +        LLMessageTemplate** msg_template, bool custom ) // outputs  {      const U8* header = buffer + LL_PACKET_ID_SIZE; @@ -487,6 +490,7 @@ BOOL LLTemplateMessageReader::decodeTemplate(      }      else // bogus packet received (too short)      { +        if (!custom)          LL_WARNS() << "Packet with unusable length received (too short): "                  << buffer_size << LL_ENDL;          return(FALSE); @@ -499,10 +503,11 @@ BOOL LLTemplateMessageReader::decodeTemplate(      }      else      { -        // MAINT-7482 - make viewer more tolerant of unknown messages. +        if (!custom) +        {          LL_WARNS_ONCE() << "Message #" << std::hex << num << std::dec                          << " received but not registered!" << LL_ENDL; -        //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); +        }          return(FALSE);      } @@ -531,7 +536,7 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3  static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages");  // decode a given message -BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) +BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, bool custom )  {      LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); @@ -591,6 +596,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender          }          else          { +            if (!custom)              LL_ERRS() << "Unknown block type" << LL_ENDL;              return FALSE;          } @@ -637,6 +643,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender                      if ((decode_pos + data_size) > mReceiveSize)                      { +                        if (!custom)                          logRanOffEndOfPacket(sender, decode_pos, data_size);                          // default to 0 length variable blocks @@ -673,6 +680,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender                      // so, copy data pointer and set data size to fixed size                      if ((decode_pos + mvci.getSize()) > mReceiveSize)                      { +                        if (!custom)                          logRanOffEndOfPacket(sender, decode_pos, mvci.getSize());                          // default to 0s. @@ -697,10 +705,11 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender      if (mCurrentRMessageData->mMemberBlocks.empty()          && !mCurrentRMessageTemplate->mMemberBlocks.empty())      { -        LL_DEBUGS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL; +        LL_WARNS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL;          return FALSE;      } +    if (!custom)      {          static LLTimer decode_timer; @@ -753,11 +762,12 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender  BOOL LLTemplateMessageReader::validateMessage(const U8* buffer,                                                S32 buffer_size,                                                const LLHost& sender, -                                              bool trusted) +                                              bool trusted, +                                              bool custom)  {      mReceiveSize = buffer_size; -    BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate ); -    if(valid) +    BOOL valid = decodeTemplate(buffer, buffer_size, &mCurrentRMessageTemplate, custom ); +    if(valid && !custom)      {          mCurrentRMessageTemplate->mReceiveCount++;          //LL_DEBUGS() << "MessageRecvd:" @@ -828,3 +838,9 @@ void LLTemplateMessageReader::copyToBuilder(LLMessageBuilder& builder) const      }      builder.copyFromMessageData(*mCurrentRMessageData);  } + +LLMessageTemplate* LLTemplateMessageReader::getTemplate() +{ +    return mCurrentRMessageTemplate; +} + diff --git a/indra/llmessage/lltemplatemessagereader.h b/indra/llmessage/lltemplatemessagereader.h index 1aa5d2e164..772b8fd607 100644 --- a/indra/llmessage/lltemplatemessagereader.h +++ b/indra/llmessage/lltemplatemessagereader.h @@ -99,24 +99,27 @@ public:      virtual void copyToBuilder(LLMessageBuilder&) const;      BOOL validateMessage(const U8* buffer, S32 buffer_size, -                         const LLHost& sender, bool trusted = false); +                         const LLHost& sender, bool trusted = false, bool custom = false);      BOOL readMessage(const U8* buffer, const LLHost& sender);      bool isTrusted() const;      bool isBanned(bool trusted_source) const;      bool isUdpBanned() const; +    BOOL               decodeData(const U8* buffer, const LLHost& sender, bool custom = false); +    LLMessageTemplate* getTemplate(); +  private:      void getData(const char *blockname, const char *varname, void *datap,                   S32 size = 0, S32 blocknum = 0, S32 max_size = S32_MAX);      BOOL decodeTemplate(const U8* buffer, S32 buffer_size,  // inputs -                        LLMessageTemplate** msg_template ); // outputs +                        LLMessageTemplate** msg_template, bool custom = false ); // outputs      void logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ); -    BOOL decodeData(const U8* buffer, const LLHost& sender ); +    //BOOL decodeData(const U8* buffer, const LLHost& sender );      S32 mReceiveSize;      LLMessageTemplate* mCurrentRMessageTemplate; diff --git a/indra/newview/fsfloatersearch.cpp b/indra/newview/fsfloatersearch.cpp new file mode 100644 index 0000000000..f05e996699 --- /dev/null +++ b/indra/newview/fsfloatersearch.cpp @@ -0,0 +1,3212 @@ +/** + * @file fsfloatersearch.cpp + * @brief Firestorm Search Floater + * + * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2012, Cinder Roxley <cinder.roxley@phoenixviewer.com> + * + * 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 "fsfloatersearch.h" + +#include "lldispatcher.h" +#include "llagent.h" +#include "llavataractions.h" +#include "llavatarname.h" +#include "llavatarnamecache.h" +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedflags.h" +#include "llclassifiedinfo.h" +#include "llcombobox.h" +#include "lldateutil.h" +#include "lleventflags.h" +#include "lleventnotifier.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llloadingindicator.h" +#include "lllogininstance.h" +#include "llnotificationsutil.h" +#include "llpanelprofile.h" +#include "llpanelprofileclassifieds.h" +#include "llparcel.h" +#include "llproductinforequest.h" +#include "llqueryflags.h" +#include "llregionhandle.h" +#include "llremoteparcelrequest.h" +#include "lltimer.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewergenericmessage.h" +#include "llviewernetwork.h" +#include "llviewerregion.h" +#include "llworldmapmessage.h" +#include "message.h" +#include <boost/tokenizer.hpp> +#include <boost/algorithm/string.hpp> +#include <string> + +#include <chrono> + +static const S32 MIN_SEARCH_STRING_SIZE = 2; +static const S32 RESULT_PAGE_SIZE = 100; + +// (observeur) Hack to avoid Find to be called several times (due to a bug in llsearchcombobox) +static std::chrono::time_point<std::chrono::system_clock> lastRequestTime; +static const S32 REQUEST_MIN_ELAPSED_TIME = 500; + +std::string filterShortWords(std::string query_string); +void fillSearchComboBox(LLSearchComboBox* search_combo); + +//////////////////////////////////////// +//          Observer Classes          // +//////////////////////////////////////// + +class FSSearchRemoteParcelInfoObserver : public LLRemoteParcelInfoObserver +{ +public: +    FSSearchRemoteParcelInfoObserver(FSFloaterSearch* floater, bool for_events) : LLRemoteParcelInfoObserver(), +        mParent(floater), +        mForEvents(for_events) +    {} + +    ~FSSearchRemoteParcelInfoObserver() +    { +        // remove any in-flight observers +        std::set<LLUUID>::iterator it; +        for (it = mParcelIDs.begin(); it != mParcelIDs.end(); ++it) +        { +            const LLUUID &id = *it; +            LLRemoteParcelInfoProcessor::getInstance()->removeObserver(id, this); +        } +        mParcelIDs.clear(); +    } + +    /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data) +    { +        if (mParent) +        { +            if (mForEvents) +            { +                mParent->displayEventParcelImage(parcel_data); +            } +            else +            { +                mParent->displayParcelDetails(parcel_data); +            } +        } +        mParcelIDs.erase(parcel_data.parcel_id); +        LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_data.parcel_id, this); +    } + +    /*virtual*/ void setParcelID(const LLUUID& parcel_id) +    { +        if (!parcel_id.isNull()) +        { +            mParcelIDs.insert(parcel_id); +            LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this); +            LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); +        } +    } + +    /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) +    { +        LL_WARNS("Search") << "Can't complete remote parcel request. Http Status: " << status << ". Reason : " << reason << LL_ENDL; +    } +private: +    std::set<LLUUID>    mParcelIDs; +    FSFloaterSearch*    mParent; +    bool                mForEvents; +}; + +///// Avatar Properties Observer ///// + +class FSSearchAvatarPropertiesObserver : public LLAvatarPropertiesObserver +{ +public: +    FSSearchAvatarPropertiesObserver(FSFloaterSearch* floater) : LLAvatarPropertiesObserver(), +    mParent(floater) +    {} + +    ~FSSearchAvatarPropertiesObserver() +    { +        // remove any in-flight observers +        std::set<LLUUID>::iterator it; +        for (it = mAvatarIDs.begin(); it != mAvatarIDs.end(); ++it) +        { +            const LLUUID &id = *it; +            LLAvatarPropertiesProcessor::getInstance()->removeObserver(id, this); +        } +        mAvatarIDs.clear(); +    } + +    void processProperties(void* data, EAvatarProcessorType type) +    { +        if (!data) +            return; + +        if (APT_PROPERTIES == type) +        { +            LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data); +            if (avatar_data) +            { +                mParent->displayAvatarDetails(avatar_data); +                LLAvatarPropertiesProcessor::getInstance()->removeObserver(avatar_data->avatar_id, this); +            } +        } +        else if (APT_PROPERTIES_LEGACY == type) +        { +            LLAvatarData avatar_data(*static_cast<LLAvatarLegacyData*>(data)); +            mParent->displayAvatarDetails(&avatar_data); +            LLAvatarPropertiesProcessor::getInstance()->removeObserver(avatar_data.avatar_id, this); +        } +        if (APT_CLASSIFIED_INFO == type) +        { +            LLAvatarClassifiedInfo* c_info = static_cast<LLAvatarClassifiedInfo*>(data); +            if (c_info) +            { +                mParent->displayClassifiedDetails(c_info); +                LLAvatarPropertiesProcessor::getInstance()->removeObserver(c_info->classified_id, this); +                std::string url = gAgent.getRegionCapability("SearchStatRequest"); +                if (!url.empty()) +                { +                    LL_INFOS("Search") << "Classified stat request via capability" << LL_ENDL; +                    LLSD body; +                    body["classified_id"] = c_info->classified_id; +                    LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, boost::bind(&LLPanelProfileClassified::handleSearchStatResponse, c_info->classified_id, _1)); +                } +            } +        } +    } +private: +    std::set<LLUUID>    mAvatarIDs; +    FSFloaterSearch*    mParent; +}; + +///// Group Info Observer ///// + +class FSSearchGroupInfoObserver : public LLGroupMgrObserver +{ +public: +    FSSearchGroupInfoObserver(const LLUUID& group_id, FSFloaterSearch* parent) : +    LLGroupMgrObserver(group_id), +    mParent(parent) +    { +        LLGroupMgr* groupmgr = LLGroupMgr::getInstance(); +        if (!group_id.isNull() && groupmgr) +        { +            groupmgr->addObserver(this); +            mID = group_id; +            groupmgr->sendGroupPropertiesRequest(group_id); +        } +    } + +    ~FSSearchGroupInfoObserver() +    { +        LLGroupMgr::getInstance()->removeObserver(this); +    } + +    void changed(LLGroupChange gc) +    { +        if (gc == GC_PROPERTIES) +        { +            LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mID); +            mParent->displayGroupDetails(group_data); +            LLGroupMgr::getInstance()->removeObserver(this); +        } +    } +private: +    FSFloaterSearch*    mParent; +    LLUUID              mID; +}; + +///// Silly Classified Clickthrough Class ///// +class FSDispatchClassifiedClickThrough : public LLDispatchHandler +{ +public: +    virtual bool operator()( +        const LLDispatcher* dispatcher, +        const std::string& key, +        const LLUUID& invoice, +        const sparam_t& strings) +    { +        if (strings.size() != 4) return false; +        LLUUID classified_id(strings[0]); +        S32 teleport_clicks = atoi(strings[1].c_str()); +        S32 map_clicks = atoi(strings[2].c_str()); +        S32 profile_clicks = atoi(strings[3].c_str()); + +        LLPanelProfileClassified::setClickThrough( +            classified_id, teleport_clicks, map_clicks, profile_clicks, false); + +        return true; +    } +}; +static FSDispatchClassifiedClickThrough sClassifiedClickThrough; + +SearchQuery::SearchQuery() +: category("category", "") +, query("query") +{} + +//////////////////////////////////////// +//         The floater itself         // +//////////////////////////////////////// + +FSFloaterSearch::FSFloaterSearch(const Params& key) +:   LLFloater(key) +{ +    mRemoteParcelObserver = new FSSearchRemoteParcelInfoObserver(this, false); +    mRemoteParcelEventLocationObserver = new FSSearchRemoteParcelInfoObserver(this, true); +    mAvatarPropertiesObserver = new FSSearchAvatarPropertiesObserver(this); +    mEventNotifierConnection = gEventNotifier.setNewEventCallback(boost::bind(&FSFloaterSearch::displayEventDetails, this, boost::placeholders::_1)); +} + +FSFloaterSearch::~FSFloaterSearch() +{ +    mEventNotifierConnection.disconnect(); +    delete mRemoteParcelObserver; +    delete mRemoteParcelEventLocationObserver; +    delete mAvatarPropertiesObserver; +    gGenericDispatcher.addHandler("classifiedclickthrough", nullptr); +} + +// virtual +void FSFloaterSearch::onOpen(const LLSD& key) +{ +    Params p(key); +    mPanelWeb->loadURL(p.search); +    if (key.has("query")) +    { +        mTabContainer->selectTabPanel(mPanelWeb); +    } +    else if (key.has("tab") && key["tab"].asString() == "groups") +    { +        mTabContainer->selectTabPanel(mPanelGroups); +    } + +    FSSearchPanelBase* current_panel = dynamic_cast<FSSearchPanelBase*>(mTabContainer->getCurrentPanel()); +    if (current_panel) +    { +        current_panel->focusDefaultElement(); +    } +} + +//virtual +void FSFloaterSearch::onClose(bool app_quitting) +{ +    if (mTabContainer) +    { +        gSavedSettings.setS32("FSLastSearchTab", mTabContainer->getCurrentPanelIndex()); +    } +} + +BOOL FSFloaterSearch::postBuild() +{ +    childSetAction("people_profile_btn", boost::bind(&FSFloaterSearch::onBtnPeopleProfile, this)); +    childSetAction("people_message_btn", boost::bind(&FSFloaterSearch::onBtnPeopleIM, this)); +    childSetAction("people_friend_btn", boost::bind(&FSFloaterSearch::onBtnPeopleFriend, this)); +    childSetAction("group_profile_btn", boost::bind(&FSFloaterSearch::onBtnGroupProfile, this)); +    childSetAction("group_message_btn", boost::bind(&FSFloaterSearch::onBtnGroupChat, this)); +    childSetAction("group_join_btn", boost::bind(&FSFloaterSearch::onBtnGroupJoin, this)); +    childSetAction("event_reminder_btn", boost::bind(&FSFloaterSearch::onBtnEventReminder, this)); +    childSetAction("teleport_btn", boost::bind(&FSFloaterSearch::onBtnTeleport, this)); +    childSetAction("map_btn", boost::bind(&FSFloaterSearch::onBtnMap, this)); +    resetVerbs(); + +    mPanelPeople        = findChild<FSPanelSearchPeople>("panel_ls_people"); +    mPanelGroups        = findChild<FSPanelSearchGroups>("panel_ls_groups"); +    mPanelPlaces        = findChild<FSPanelSearchPlaces>("panel_ls_places"); +    mPanelEvents        = findChild<FSPanelSearchEvents>("panel_ls_events"); +    mPanelLand          = findChild<FSPanelSearchLand>("panel_ls_land"); +    mPanelClassifieds   = findChild<FSPanelSearchClassifieds>("panel_ls_classifieds"); +    mPanelWeb           = findChild<FSPanelSearchWeb>("panel_ls_web"); + +    mDetailsPanel =     getChild<LLPanel>("panel_ls_details"); +    mDetailTitle =      getChild<LLTextEditor>("title"); +    mDetailDesc =       getChild<LLTextEditor>("desc"); +    mDetailAux1 =       getChild<LLTextEditor>("aux1"); +    mDetailAux2 =       getChild<LLTextEditor>("aux2"); +    mDetailLocation =   getChild<LLTextEditor>("location"); +    mDetailSnapshot =   getChild<LLTextureCtrl>("snapshot"); +    mDetailSnapshotParcel = getChild<LLTextureCtrl>("snapshot_parcel"); +    mDetailMaturity =   getChild<LLIconCtrl>("maturity_icon"); +    mTabContainer =     getChild<LLTabContainer>("ls_tabs"); + +    mTabContainer->setCommitCallback(boost::bind(&FSFloaterSearch::onTabChange, this)); + +    flushDetails(); + +    mDetailsPanel->setVisible(false); + +    mHasSelection = false; + +    if (!mTabContainer->selectTab(gSavedSettings.getS32("FSLastSearchTab"))) +    { +        mTabContainer->selectFirstTab(); +    } + +    return TRUE; +} + +void FSFloaterSearch::onTabChange() +{ +    LL_INFOS() << "onTabChange()()" << LL_ENDL; + +    flushDetails(); + +    LLPanel* active_panel = mTabContainer->getCurrentPanel(); + +    if (active_panel == mPanelWeb) +    { +        mDetailsPanel->setVisible(false); +        mPanelWeb->resetFocusOnLoad(); +    } +    else if (active_panel == mPanelPeople) +    { +        mDetailsPanel->setVisible(mHasSelection); +    } + +    if (active_panel == mPanelPeople || active_panel == mPanelGroups) +    { +        mDetailSnapshotParcel->setVisible(FALSE); +        mDetailSnapshot->setVisible(TRUE); +    } +    else if (active_panel == mPanelPlaces || active_panel == mPanelLand || +        active_panel == mPanelEvents || active_panel == mPanelClassifieds) +    { +        mDetailSnapshot->setVisible(FALSE); +        mDetailSnapshotParcel->setVisible(TRUE); +    } +} + +//static +template <class T> +T* FSFloaterSearch::getSearchPanel(const std::string& panel_name) +{ +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance && search_instance->mTabContainer) +    { +        return dynamic_cast<T*>(search_instance->mTabContainer->getPanelByName(panel_name)); +    } +    else +    { +        return nullptr; +    } +} + +void FSFloaterSearch::onSelectedItem(const LLUUID& selected_item, ESearchCategory type) +{ +    LL_INFOS() << "onSelectedItem()" << LL_ENDL; + +    if (!selected_item.isNull()) +    { +        mSelectedID = selected_item; +        resetVerbs(); +        flushDetails(); +        switch (type) +        { +            case SC_AVATAR: +            { +                LLAvatarPropertiesProcessor::getInstance()->addObserver(selected_item, mAvatarPropertiesObserver); +                LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(selected_item); +            } +                break; +            case SC_GROUP: +                mGroupPropertiesRequest = new FSSearchGroupInfoObserver(selected_item, this); +                break; +            case SC_PLACE: +                mRemoteParcelObserver->setParcelID(selected_item); +                break; +            case SC_CLASSIFIED: +                LLAvatarPropertiesProcessor::getInstance()->addObserver(selected_item, mAvatarPropertiesObserver); +                LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(selected_item); +                gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); +                break; +        } +        setLoadingProgress(true); +    } +} + +void FSFloaterSearch::onSelectedEvent(const S32 selected_event) +{ +    LL_INFOS() << "onSelectedEvent()()" << LL_ENDL; + +    resetVerbs(); +    flushDetails(); + +    gMessageSystem->newMessageFast(_PREHASH_EventInfoRequest); +    gMessageSystem->nextBlockFast(_PREHASH_AgentData); +    gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); +    gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); +    gMessageSystem->nextBlockFast(_PREHASH_EventData); +    gMessageSystem->addU32Fast(_PREHASH_EventID, selected_event); +    gAgent.sendReliableMessage(); +} + +void FSFloaterSearch::displayParcelDetails(const LLParcelData& parcel_data) +{ +    S32 region_x; +    S32 region_y; +    S32 region_z; +    region_x = ll_round(parcel_data.global_x) % REGION_WIDTH_UNITS; +    region_y = ll_round(parcel_data.global_y) % REGION_WIDTH_UNITS; +    region_z = ll_round(parcel_data.global_z); +    // HACK: Flag 0x2 == adult region, +    // Flag 0x1 == mature region, otherwise assume PG +    if (parcel_data.flags & 0x2) +    { +        mDetailMaturity->setValue("Parcel_R_Dark"); +    } +    else if (parcel_data.flags & 0x1) +    { +        mDetailMaturity->setValue("Parcel_M_Dark"); +    } +    else +    { +        mDetailMaturity->setValue("Parcel_PG_Dark"); +    } + +    LLStringUtil::format_map_t map; +    map["DWELL"] = llformat("%.0f", (F64)parcel_data.dwell); +    map["AREA"] = llformat("%d m²", parcel_data.actual_area); +    map["LOCATION"] = llformat("%s (%d, %d, %d)", parcel_data.sim_name.c_str(), region_x, region_y, region_z); + +    mParcelGlobal = LLVector3d(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z); +    mDetailsPanel->setVisible(mTabContainer->getCurrentPanel()->getName() == "panel_ls_places" || mTabContainer->getCurrentPanel()->getName() == "panel_ls_land"); +    mHasSelection = true; +    mDetailMaturity->setVisible(true); +    mDetailTitle->setValue(parcel_data.name); +    mDetailDesc->setValue(parcel_data.desc); +    mDetailAux1->setValue(getString("string.traffic", map)); +    mDetailAux2->setValue(getString("string.area", map)); +    mDetailLocation->setValue(getString("string.location", map)); +    mDetailSnapshotParcel->setValue(parcel_data.snapshot_id); +    childSetVisible("teleport_btn", true); +    childSetVisible("map_btn", true); +    setLoadingProgress(false); +} + +void FSFloaterSearch::displayAvatarDetails(LLAvatarData* avatar_data) +{ +    if (avatar_data) +    { +        LLStringUtil::format_map_t map; +        map["AGE"] = LLDateUtil::ageFromDate(avatar_data->born_on, LLDate::now()); +        if (avatar_data->partner_id.notNull()) +        { +            map["PARTNER"] = LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString(); +            mDetailAux2->setValue(getString("string.partner", map)); +        } + +        mDetailsPanel->setVisible(mTabContainer->getCurrentPanel()->getName() == "panel_ls_people"); +        mHasSelection = true; +        mDetailTitle->setValue(LLTrans::getString("LoadingData")); +        mDetailDesc->setValue(avatar_data->about_text); +        mDetailSnapshot->setValue(avatar_data->image_id); +        mDetailAux1->setValue(avatar_data->hide_age ? "" : getString("string.age", map)); +        LLAvatarNameCache::get(avatar_data->avatar_id, boost::bind(&FSFloaterSearch::avatarNameUpdatedCallback,this, _1, _2)); +        childSetVisible("people_profile_btn", true); +        childSetVisible("people_message_btn", true); +        childSetVisible("people_friend_btn", true); +        getChildView("people_friend_btn")->setEnabled(!LLAvatarActions::isFriend(avatar_data->avatar_id)); +    } +} + +void FSFloaterSearch::displayGroupDetails(LLGroupMgrGroupData*& group_data) +{ +    if (group_data) +    { +        LLStringUtil::format_map_t map; +        map["MEMBER_COUNT"] = llformat("%d",group_data->mMemberCount); +        map["FOUNDER"] = LLSLURL("agent", group_data->mFounderID, "inspect").getSLURLString(); + +        mDetailsPanel->setVisible(mTabContainer->getCurrentPanel()->getName() == "panel_ls_groups"); +        mHasSelection = true; +        mDetailTitle->setValue(LLTrans::getString("LoadingData")); +        mDetailDesc->setValue(group_data->mCharter); +        mDetailSnapshot->setValue(group_data->mInsigniaID); +        mDetailAux1->setValue(getString("string.members", map)); +        mDetailAux2->setValue(getString("string.founder", map)); +        LLGroupData agent_gdatap; +        bool is_member = gAgent.getGroupData(getSelectedID(),agent_gdatap) || gAgent.isGodlike(); +        bool join_btn_enabled = !is_member && group_data->mOpenEnrollment; +        childSetVisible("group_profile_btn", true); +        childSetVisible("group_message_btn", true); +        childSetVisible("group_join_btn", true); +        getChildView("group_join_btn")->setEnabled(join_btn_enabled); +        getChildView("group_message_btn")->setEnabled(is_member); +        gCacheName->getGroup(getSelectedID(), boost::bind(&FSFloaterSearch::groupNameUpdatedCallback, this, _1, _2, _3)); +    } +} + +void FSFloaterSearch::displayClassifiedDetails(LLAvatarClassifiedInfo*& c_info) +{ +    if (c_info) +    { +        if (c_info->flags & CLASSIFIED_FLAG_MATURE) +        { +            mDetailMaturity->setValue("Parcel_M_Dark"); +        } +        else +        { +            mDetailMaturity->setValue("Parcel_PG_Dark"); +        } + +        LLStringUtil::format_map_t map; +        map["LISTING_PRICE"] = llformat("L$%d", c_info->price_for_listing); +        map["SLURL"] = LLSLURL("parcel", c_info->parcel_id, "about").getSLURLString(); + +        mDetailsPanel->setVisible(mTabContainer->getCurrentPanel()->getName() == "panel_ls_classifieds"); +        mHasSelection = true; +        mDetailMaturity->setVisible(true); +        mParcelGlobal = c_info->pos_global; +        mDetailTitle->setValue(c_info->name); +        mDetailDesc->setValue(c_info->description); +        mDetailSnapshotParcel->setValue(c_info->snapshot_id); +        mDetailAux1->setValue(getString("string.listing_price", map)); +        mDetailLocation->setValue(getString("string.slurl", map)); +        childSetVisible("teleport_btn", true); +        childSetVisible("map_btn", true); +        setLoadingProgress(false); +    } +} + +bool FSFloaterSearch::displayEventDetails(LLEventStruct event) +{ +    if (event.flags == EVENT_FLAG_ADULT) +    { +        mDetailMaturity->setValue("Parcel_R_Dark"); +    } +    else if (event.flags == EVENT_FLAG_MATURE) +    { +        mDetailMaturity->setValue("Parcel_M_Dark"); +    } +    else +    { +        mDetailMaturity->setValue("Parcel_PG_Dark"); +    } + +    S32 region_x; +    S32 region_y; +    S32 region_z; +    region_x = (S64)ll_round(event.globalPos.mdV[VX]) % REGION_WIDTH_UNITS; +    region_y = (S64)ll_round(event.globalPos.mdV[VY]) % REGION_WIDTH_UNITS; +    region_z = (S32)ll_round(event.globalPos.mdV[VZ]); +    LLStringUtil::format_map_t map; +    map["DURATION"] = llformat("%d:%.2d", event.duration / 60, event.duration % 60); +    map["LOCATION"] = llformat("%s (%d, %d, %d)", event.simName.c_str(), region_x, region_y, region_z); +    if (event.cover > 0) +    { +        map["COVERCHARGE"] = llformat("L$%d", event.cover); +        mDetailAux2->setValue(getString("string.covercharge", map)); +    } + +    mParcelGlobal = event.globalPos; +    mEventID = event.eventId; +    mDetailsPanel->setVisible(mTabContainer->getCurrentPanel()->getName() == "panel_ls_events"); +    mHasSelection = true; +    mDetailMaturity->setVisible(true); +    mDetailTitle->setValue(event.eventName); +    mDetailDesc->setValue(event.desc); +    mDetailAux1->setValue(getString("string.duration", map)); +    mDetailLocation->setValue(getString("string.location", map)); +    mDetailSnapshotParcel->setValue(LLUUID::null); +    childSetVisible("teleport_btn", true); +    childSetVisible("map_btn", true); +    childSetVisible("event_reminder_btn", true); + +    LLWorldMapMessage::getInstance()->sendNamedRegionRequest(event.simName, boost::bind(&FSFloaterSearch::regionHandleCallback, this, _1, event.globalPos), "", false); +    return true; +} + +void FSFloaterSearch::regionHandleCallback(U64 region_handle, LLVector3d pos_global) +{ +    std::string url = gAgent.getRegionCapability("RemoteParcelRequest"); +    if (!url.empty()) +    { +        auto region_origin = from_region_handle(region_handle); +        LLVector3 pos_region(LLVector3(pos_global - region_origin)); + +        LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, +            LLUUID::null, pos_region, pos_global, mRemoteParcelEventLocationObserver->getObserverHandle()); +    } +    else +    { +        setLoadingProgress(false); +    } +} + +void FSFloaterSearch::displayEventParcelImage(const LLParcelData& parcel_data) +{ +    mDetailSnapshotParcel->setValue(parcel_data.snapshot_id); +    setLoadingProgress(false); +} + +void FSFloaterSearch::avatarNameUpdatedCallback(const LLUUID& id, const LLAvatarName& av_name) +{ +    if (id == getSelectedID()) +    { +        mDetailTitle->setValue(av_name.getCompleteName()); +        setLoadingProgress(false); +    } +    // Otherwise possibly a request for an older selection, ignore it. +} + +void FSFloaterSearch::groupNameUpdatedCallback(const LLUUID& id, const std::string& name, bool is_group) +{ +    if (id == getSelectedID()) +    { +        mDetailTitle->setValue( LLSD(name) ); +        setLoadingProgress(false); +    } +    // Otherwise possibly a request for an older selection, ignore it. +} + +void FSFloaterSearch::setLoadingProgress(bool started) +{ +    LLLoadingIndicator* indicator = getChild<LLLoadingIndicator>("loading"); + +    indicator->setVisible(started); + +    if (started) +    { +        indicator->start(); +    } +    else +    { +        indicator->stop(); +    } +} + +void FSFloaterSearch::resetVerbs() +{ +    childSetVisible("people_profile_btn", false); +    childSetVisible("people_message_btn", false); +    childSetVisible("people_friend_btn", false); +    childSetVisible("group_profile_btn", false); +    childSetVisible("group_message_btn", false); +    childSetVisible("group_join_btn", false); +    childSetVisible("event_reminder_btn", false); +    childSetVisible("teleport_btn", false); +    childSetVisible("map_btn", false); +} + +void FSFloaterSearch::flushDetails() +{ +    LL_INFOS() << "flushDetails()" << LL_ENDL; +    mDetailTitle->setValue(""); +    mDetailDesc->setValue(""); +    mDetailAux1->setValue(""); +    mDetailAux2->setValue(""); +    mDetailLocation->setValue(""); +    mDetailSnapshot->setValue(LLSD()); +    mDetailMaturity->setVisible(false); +    mParcelGlobal.setZero(); +} + +void FSFloaterSearch::onBtnPeopleProfile() +{ +    LLAvatarActions::showProfile(getSelectedID()); +} + +void FSFloaterSearch::onBtnPeopleIM() +{ +    LLAvatarActions::startIM(getSelectedID()); +} + +void FSFloaterSearch::onBtnPeopleFriend() +{ +    LLAvatarActions::requestFriendshipDialog(getSelectedID()); +} + +void FSFloaterSearch::onBtnGroupProfile() +{ +    LLGroupActions::show(getSelectedID()); +} + +void FSFloaterSearch::onBtnGroupChat() +{ +    LLGroupActions::startIM(getSelectedID()); +} + +void FSFloaterSearch::onBtnGroupJoin() +{ +    LLGroupActions::join(getSelectedID()); +} + +void FSFloaterSearch::onBtnTeleport() +{ +    if (!mParcelGlobal.isExactlyZero()) +    { +        gAgent.teleportViaLocation(mParcelGlobal); +        LLFloaterWorldMap::getInstance()->trackLocation(mParcelGlobal); +        /// <FS:CR> What should we do when when we teleport? The default (1) is to close the floater, +        /// the user may elect to minimize the floater (2), or to do nothing (any other setting) +        static LLCachedControl<U32> teleport_action(gSavedSettings, "FSLegacySearchActionOnTeleport"); +        if (teleport_action == 1) +        { +            closeFloater(); +        } +        else if (teleport_action == 2) +        { +            setMinimized(TRUE); +        } +    } +} + +void FSFloaterSearch::onBtnMap() +{ +    if (!mParcelGlobal.isExactlyZero()) +    { +        LLFloaterWorldMap::getInstance()->trackLocation(mParcelGlobal); +        LLFloaterReg::showInstance("world_map", "center"); +    } +} + +void FSFloaterSearch::onBtnEventReminder() +{ +    gEventNotifier.add(mEventID); +} + +//////////////////////////////////////// +//         People Search Panel        // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchPeople> t_panel_fs_search_people("panel_ls_people"); + +FSPanelSearchPeople::FSPanelSearchPeople() : FSSearchPanelBase() +, mQueryID(nullptr) +, mStartSearch(0) +, mResultsReceived(0) +, mResultsContent() +, mAvatarNameCallbackConnection() +{ +} + +FSPanelSearchPeople::~FSPanelSearchPeople() +{ +    if (mAvatarNameCallbackConnection.connected()) +    { +        mAvatarNameCallbackConnection.disconnect(); +    } +} + +BOOL FSPanelSearchPeople::postBuild() +{ +    mSearchComboBox =   findChild<LLSearchComboBox>("people_edit"); +    mSearchResults =    findChild<LLScrollListCtrl>("search_results_people"); +    if (mSearchComboBox) +    { +        mSearchComboBox->setCommitCallback(boost::bind(&FSPanelSearchPeople::onBtnFind, this)); +        fillSearchComboBox(mSearchComboBox); +    } +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchPeople::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +        mSearchResults->setContextMenu(LLScrollListCtrl::MENU_AVATAR); +    } + +    childSetAction("people_next", boost::bind(&FSPanelSearchPeople::onBtnNext, this)); +    childSetAction("people_back", boost::bind(&FSPanelSearchPeople::onBtnBack, this)); +    getChildView("people_next")->setEnabled(FALSE); +    getChildView("people_back")->setEnabled(FALSE); + +    return TRUE; +} + +void FSPanelSearchPeople::focusDefaultElement() +{ +    mSearchComboBox->focusTextEntry(); +} + +void FSPanelSearchPeople::find() +{ +    std::string text = mSearchComboBox->getSimple(); +    boost::trim(text); + +    if (text.size() <= MIN_SEARCH_STRING_SIZE) +    { +        mSearchResults->setCommentText(LLTrans::getString("search_short")); +        return; +    } + +    if (LLUUID::validate(text)) +    { +        LLUUID id(text); + +        mSearchResults->deleteAllItems(); +        mSearchResults->setCommentText(LLTrans::getString("searching")); +        mResultsReceived = 0; +        mNumResultsReturned = 0; + +        if (mAvatarNameCallbackConnection.connected()) +        { +            mAvatarNameCallbackConnection.disconnect(); +        } +        mAvatarNameCallbackConnection = LLAvatarNameCache::get(id, boost::bind(&FSPanelSearchPeople::onAvatarNameCallback, this, _1, _2)); + +        return; +    } + +    LLStringUtil::replaceChar(text, '.', ' '); + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessage("DirFindQuery"); +    gMessageSystem->nextBlock("AgentData"); +    gMessageSystem->addUUID("AgentID", gAgentID); +    gMessageSystem->addUUID("SessionID", gAgentSessionID); +    gMessageSystem->nextBlock("QueryData"); +    gMessageSystem->addUUID("QueryID", getQueryID()); +    gMessageSystem->addString("QueryText", text); +    gMessageSystem->addU32("QueryFlags", DFQ_PEOPLE); +    gMessageSystem->addS32("QueryStart", mStartSearch); +    gAgent.sendReliableMessage(); +    LL_INFOS("Search") << "Firing off search request: " << getQueryID() << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchPeople::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    std::string text = mSearchComboBox->getSimple(); + +    if (!text.empty()) +    { +        LLSearchHistory::getInstance()->addEntry(text); +    } + +    resetSearch(); + +    find(); +} + +void FSPanelSearchPeople::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("people_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchPeople::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("people_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchPeople::resetSearch() +{ +    mStartSearch = 0; +    getChildView("people_back")->setEnabled(FALSE); +    getChildView("people_next")->setEnabled(FALSE); +} + +S32 FSPanelSearchPeople::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("people_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchPeople::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedItem(mSearchResults->getSelectedValue(), FSFloaterSearch::SC_AVATAR); +    } +} + +// static +void FSPanelSearchPeople::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID query_id; +    std::string first_name; +    std::string last_name; +    LLUUID agent_id; + +    msg->getUUIDFast(_PREHASH_QueryData,    _PREHASH_QueryID,   query_id); +    msg->getUUIDFast(_PREHASH_AgentData,    _PREHASH_AgentID,   agent_id); + +    // This result is not for us. +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_INFOS("Search") << "received search results - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchPeople* self = FSFloaterSearch::getSearchPanel<FSPanelSearchPeople>("panel_ls_people"); + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->getQueryID()) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_people"); + +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } + +    // Check for status messages +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_PLACES_FOUNDNONE) +        { +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("people_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_SHORTSTRING) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_short")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_BANNEDWORD) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_banned")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_SEARCHDISABLED) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +    } + +    bool found_one = false; +    S32 num_new_rows = msg->getNumberOfBlocksFast(_PREHASH_QueryReplies); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("people_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } + +    self->mResultsReceived += num_new_rows; +    num_new_rows = self->showNextButton(num_new_rows); + +    for (S32 i = 0; i < num_new_rows; i++) +    { +        msg->getStringFast( _PREHASH_QueryReplies,  _PREHASH_FirstName, first_name, i); +        msg->getStringFast( _PREHASH_QueryReplies,  _PREHASH_LastName,  last_name, i); +        msg->getUUIDFast(   _PREHASH_QueryReplies,  _PREHASH_AgentID,   agent_id, i); +        //msg->getU8Fast(   _PREHASH_QueryReplies,  _PREHASH_Online,    online, i); + +        if (agent_id.isNull()) +        { +            LL_INFOS("Search") << "Null result returned for QueryID: " << query_id << LL_ENDL; +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("people_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +        } +        else +        { +            LL_DEBUGS("Search") << "Got: " << first_name << " " << last_name << " AgentID: " << agent_id << LL_ENDL; +            search_results->setEnabled(TRUE); +            found_one = true; + +            std::string avatar_name; +            avatar_name = LLCacheName::buildFullName(first_name, last_name); + +            LLSD content; +            LLSD element; + +            element["id"] = agent_id; + +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"]   = "icon"; +            element["columns"][0]["value"]  = "icon_avatar_offline.tga"; + +            element["columns"][1]["column"] = "username"; +            element["columns"][1]["value"]  = avatar_name; + +            content["name"] = avatar_name; + +            search_results->addElement(element, ADD_BOTTOM); +            self->mResultsContent[agent_id.asString()] = content; +        } +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +void FSPanelSearchPeople::onAvatarNameCallback(const LLUUID& id, const LLAvatarName& av_name) +{ +    if (mAvatarNameCallbackConnection.connected()) +    { +        mAvatarNameCallbackConnection.disconnect(); +    } + +    LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("search_results_people"); + +    if (av_name.getAccountName() != "(?\?\?).(?\?\?)") +    { +        LLSD content; +        LLSD data; +        data["id"] = id; + +        data["columns"][0]["column"] = "icon"; +        data["columns"][0]["type"] = "icon"; +        data["columns"][0]["value"] = "icon_avatar_offline.tga"; + +        data["columns"][1]["name"] = "username"; +        data["columns"][1]["value"] = av_name.getUserName(); + +        content["name"] = av_name.getUserName(); + +        search_results->addElement(data); + +        mResultsContent[id.asString()] = content; +        mResultsReceived = 1; +        mNumResultsReturned = 1; + +        search_results->setEnabled(TRUE); +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        onSelectItem(); +    } +    else +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = getChild<LLUICtrl>("people_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } +} + +//////////////////////////////////////// +//         Groups Search Panel        // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchGroups> t_panel_fs_search_groups("panel_ls_groups"); + +FSPanelSearchGroups::FSPanelSearchGroups() : FSSearchPanelBase() +, mQueryID(nullptr) +, mStartSearch(0) +, mResultsReceived(0) +, mResultsContent() +{ +} + +FSPanelSearchGroups::~FSPanelSearchGroups() +{ +} + +BOOL FSPanelSearchGroups::postBuild() +{ +    mSearchComboBox =   findChild<LLSearchComboBox>("groups_edit"); +    mSearchResults =    findChild<LLScrollListCtrl>("search_results_groups"); +    if (mSearchComboBox) +    { +        mSearchComboBox->setCommitCallback(boost::bind(&FSPanelSearchGroups::onBtnFind, this)); +        fillSearchComboBox(mSearchComboBox); +    } +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchGroups::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +    } + +    childSetAction("groups_next", boost::bind(&FSPanelSearchGroups::onBtnNext, this)); +    childSetAction("groups_back", boost::bind(&FSPanelSearchGroups::onBtnBack, this)); +    getChildView("groups_next")->setEnabled(FALSE); +    getChildView("groups_back")->setEnabled(FALSE); + +    lastRequestTime = std::chrono::system_clock::now(); + +    return TRUE; +} + +void FSPanelSearchGroups::focusDefaultElement() +{ +    mSearchComboBox->focusTextEntry(); +} + +void FSPanelSearchGroups::find() +{ +    std::string text = filterShortWords(mSearchComboBox->getSimple()); +    if (text.size() == 0) +    { +        mSearchResults->setCommentText(LLTrans::getString("search_short")); +        return; +    } + +    static LLUICachedControl<bool> inc_pg("ShowPGSims", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureSims", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultSims", 0); +    if (!(inc_pg || inc_mature || inc_adult)) +    { +        LLNotificationsUtil::add("NoContentToSearch"); +        return; +    } +    U32 scope = 0; +    if (gAgent.wantsPGOnly()) +    { +        scope |= DFQ_PG_SIMS_ONLY; +    } +    bool adult_enabled = gAgent.canAccessAdult(); +    bool mature_enabled = gAgent.canAccessMature(); +    if (inc_pg) +    { +        scope |= DFQ_INC_PG; +    } +    if (inc_mature && mature_enabled) +    { +        scope |= DFQ_INC_MATURE; +    } +    if (inc_adult && adult_enabled) +    { +        scope |= DFQ_INC_ADULT; +    } +    scope |= DFQ_GROUPS; + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessage("DirFindQuery"); +    gMessageSystem->nextBlock("AgentData"); +    gMessageSystem->addUUID("AgentID", gAgentID); +    gMessageSystem->addUUID("SessionID", gAgentSessionID); +    gMessageSystem->nextBlock("QueryData"); +    gMessageSystem->addUUID("QueryID", getQueryID()); +    gMessageSystem->addString("QueryText", text); +    gMessageSystem->addU32("QueryFlags", scope); +    gMessageSystem->addS32("QueryStart", mStartSearch); +    gAgent.sendReliableMessage(); +    LL_DEBUGS("Search") << "Firing off search request: " << getQueryID() << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchGroups::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    std::string text = mSearchComboBox->getSimple(); +    if (!text.empty()) +    { +        LLSearchHistory::getInstance()->addEntry(text); +    } + +    resetSearch(); + +    find(); +} + +void FSPanelSearchGroups::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("groups_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchGroups::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("groups_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchGroups::resetSearch() +{ +    mStartSearch = 0; +    getChildView("groups_back")->setEnabled(FALSE); +    getChildView("groups_next")->setEnabled(FALSE); +} + +S32 FSPanelSearchGroups::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("groups_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchGroups::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedItem(mSearchResults->getSelectedValue(), FSFloaterSearch::SC_GROUP); +    } +} + +// static +void FSPanelSearchGroups::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID query_id; +    LLUUID group_id; +    LLUUID agent_id; +    std::string group_name; +    S32 members; +    F32 search_order; + +    msg->getUUIDFast(   _PREHASH_QueryData, _PREHASH_QueryID,   query_id); +    msg->getUUIDFast(   _PREHASH_AgentData, _PREHASH_AgentID,   agent_id); + +    // Not for us +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_DEBUGS("Search") << "received directory request - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchGroups* self = FSFloaterSearch::getSearchPanel<FSPanelSearchGroups>("panel_ls_groups"); + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->mQueryID) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_groups"); + +    // Clear "Searching" label on first results +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } + +    // Check for status messages +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_PLACES_FOUNDNONE) +        { +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("groups_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +            return; +        } +        else if(status & STATUS_SEARCH_PLACES_SHORTSTRING) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_short")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_BANNEDWORD) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_banned")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_SEARCHDISABLED) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +    } + +    bool found_one = false; +    S32 num_new_rows = msg->getNumberOfBlocksFast(_PREHASH_QueryReplies); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("groups_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } + +    self->mResultsReceived += num_new_rows; +    num_new_rows = self->showNextButton(num_new_rows); + +    for (S32 i = 0; i < num_new_rows; i++) +    { +        msg->getUUIDFast(   _PREHASH_QueryReplies,  _PREHASH_GroupID,       group_id,   i); +        msg->getStringFast( _PREHASH_QueryReplies,  _PREHASH_GroupName,     group_name, i); +        msg->getS32Fast(    _PREHASH_QueryReplies,  _PREHASH_Members,       members,    i); +        msg->getF32Fast(    _PREHASH_QueryReplies,  _PREHASH_SearchOrder,   search_order,i); +        if (group_id.isNull()) +        { +            LL_DEBUGS("Search") << "No results returned for QueryID: " << query_id << LL_ENDL; +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("groups_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +        } +        else +        { +            LL_DEBUGS("Search") << "Got: " << group_name << " GroupID: " << group_id << LL_ENDL; +            search_results->setEnabled(TRUE); +            found_one = true; + +            LLSD content; +            LLSD element; + +            element["id"] = group_id; + +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"]   = "icon"; +            element["columns"][0]["value"]  = "Icon_Group"; + +            element["columns"][1]["column"] = "group_name"; +            element["columns"][1]["value"]  = group_name; + +            element["columns"][2]["column"] = "members"; +            element["columns"][2]["value"]  = members; + +            element["columns"][3]["column"] = "score"; +            element["columns"][3]["value"]  = search_order; + +            content["name"] = group_name; + +            search_results->addElement(element, ADD_BOTTOM); +            self->mResultsContent[group_id.asString()] = content; +        } +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +//////////////////////////////////////// +//         Places Search Panel        // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchPlaces> t_panel_fs_search_places("panel_ls_places"); + +FSPanelSearchPlaces::FSPanelSearchPlaces() : FSSearchPanelBase() +, mQueryID(nullptr) +, mStartSearch(0) +, mResultsReceived(0) +, mResultsContent() +{ +    mCommitCallbackRegistrar.add("CommitSearch", boost::bind(&FSPanelSearchPlaces::find, this)); +} + +FSPanelSearchPlaces::~FSPanelSearchPlaces() +{ +} + +BOOL FSPanelSearchPlaces::postBuild() +{ +    mSearchComboBox =   findChild<LLSearchComboBox>("places_edit"); +    mSearchResults =    findChild<LLScrollListCtrl>("search_results_places"); +    mPlacesCategory =   findChild<LLComboBox>("places_category"); +    if (mSearchComboBox) +    { +        mSearchComboBox->setCommitCallback(boost::bind(&FSPanelSearchPlaces::onBtnFind, this)); +        fillSearchComboBox(mSearchComboBox); +    } +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchPlaces::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +    } +    if (mPlacesCategory) +    { +        mPlacesCategory->add(LLTrans::getString("all_categories"), LLSD("any")); +        mPlacesCategory->addSeparator(); +        for (int category = LLParcel::C_LINDEN; category < LLParcel::C_COUNT; category++) +        { +            LLParcel::ECategory eCategory = (LLParcel::ECategory)category; +            mPlacesCategory->add(LLTrans::getString(LLParcel::getCategoryUIString(eCategory)), LLParcel::getCategoryString(eCategory)); +        } +    } +    childSetAction("places_next", boost::bind(&FSPanelSearchPlaces::onBtnNext, this)); +    childSetAction("places_back", boost::bind(&FSPanelSearchPlaces::onBtnBack, this)); +    getChildView("places_next")->setEnabled(FALSE); +    getChildView("places_back")->setEnabled(FALSE); + +    return TRUE; +} + +void FSPanelSearchPlaces::focusDefaultElement() +{ +    mSearchComboBox->focusTextEntry(); +} + +void FSPanelSearchPlaces::find() +{ +    std::string text = filterShortWords(mSearchComboBox->getSimple()); +    if (text.empty()) +    { +        mSearchResults->setCommentText(LLTrans::getString("search_short")); +        return; +    } + +    static LLUICachedControl<bool> inc_pg("ShowPGSims", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureSims", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultSims", 0); +    if (!(inc_pg || inc_mature || inc_adult)) +    { +        LLNotificationsUtil::add("NoContentToSearch"); +        return; +    } +    S8 category; +    std::string category_string = mPlacesCategory->getSelectedValue(); +    if (category_string == "any") +    { +        category = LLParcel::C_ANY; +    } +    else +    { +        category = LLParcel::getCategoryFromString(category_string); +    } +    U32 scope = 0; +    if (gAgent.wantsPGOnly()) +    { +        scope |= DFQ_PG_SIMS_ONLY; +    } +    bool adult_enabled = gAgent.canAccessAdult(); +    bool mature_enabled = gAgent.canAccessMature(); +    if (inc_pg) +    { +        scope |= DFQ_INC_PG; +    } +    if (inc_mature && mature_enabled) +    { +        scope |= DFQ_INC_MATURE; +    } +    if (inc_adult && adult_enabled) +    { +        scope |= DFQ_INC_ADULT; +    } +    scope |= DFQ_DWELL_SORT; + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessage("DirPlacesQuery"); +    gMessageSystem->nextBlock("AgentData"); +    gMessageSystem->addUUID("AgentID", gAgentID); +    gMessageSystem->addUUID("SessionID", gAgentSessionID); +    gMessageSystem->nextBlock("QueryData"); +    gMessageSystem->addUUID("QueryID", getQueryID()); +    gMessageSystem->addString("QueryText", text); +    gMessageSystem->addU32("QueryFlags", scope); +    gMessageSystem->addS8("Category", category); +    // TODO: Search filter by region name. +    gMessageSystem->addString("SimName", ""); +    gMessageSystem->addS32("QueryStart", mStartSearch); +    gAgent.sendReliableMessage(); +    LL_INFOS("Search") << "Firing off places search request: " << getQueryID() << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchPlaces::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    std::string text = mSearchComboBox->getSimple(); +    if (!text.empty()) +    { +        LLSearchHistory::getInstance()->addEntry(text); +    } + +    resetSearch(); + +    find(); +} + +void FSPanelSearchPlaces::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("places_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchPlaces::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("places_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchPlaces::resetSearch() +{ +    mStartSearch = 0; +    getChildView("places_back")->setEnabled(FALSE); +    getChildView("places_next")->setEnabled(FALSE); +} + +S32 FSPanelSearchPlaces::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("places_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchPlaces::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedItem(mSearchResults->getSelectedValue(), FSFloaterSearch::SC_PLACE); +    } +} + +// static +void FSPanelSearchPlaces::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID      agent_id; +    LLUUID      query_id; +    LLUUID      parcel_id; +    std::string name; +    BOOL        for_sale; +    BOOL        auction; +    F32         dwell; + +    msg->getUUID("AgentData", "AgentID", agent_id); +    msg->getUUID("QueryData", "QueryID", query_id); + +    // Not for us +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_DEBUGS("Search") << "received directory request - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchPlaces* self = FSFloaterSearch::getSearchPanel<FSPanelSearchPlaces>("panel_ls_places"); + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->getQueryID()) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_places"); + +    // Clear "Searching" label on first results +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } + +    // Check for status messages +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_PLACES_FOUNDNONE) +        { +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("places_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +            return; +        } +        else if(status & STATUS_SEARCH_PLACES_SHORTSTRING) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_short")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_BANNEDWORD) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_banned")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_SEARCHDISABLED) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_ESTATEEMPTY) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +    } + +    bool found_one = false; +    S32 num_new_rows = msg->getNumberOfBlocks("QueryReplies"); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("places_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } + +    self->mResultsReceived += num_new_rows; +    num_new_rows = self->showNextButton(num_new_rows); + +    for (S32 i = 0; i < num_new_rows; i++) +    { +        msg->getUUID(   "QueryReplies", "ParcelID", parcel_id,  i); +        msg->getString( "QueryReplies", "Name",     name,       i); +        msg->getBOOL(   "QueryReplies", "ForSale",  for_sale,i); +        msg->getBOOL(   "QueryReplies", "Auction",  auction,    i); +        msg->getF32(    "QueryReplies", "Dwell",    dwell,      i); +        if (parcel_id.isNull()) +        { +            LL_DEBUGS("Search") << "Null result returned for QueryID: " << query_id << LL_ENDL; +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("places_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +        } +        else +        { +            LL_DEBUGS("Search") << "Got: " << name << " ParcelID: " << parcel_id << LL_ENDL; +            search_results->setEnabled(TRUE); +            found_one = true; + +            LLSD content; +            LLSD element; + +            element["id"] = parcel_id; + +            if (auction) +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_Auction"; +            } +            else if (for_sale) +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_For_Sale"; +            } +            else +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_Place"; +            } + +            element["columns"][1]["column"] = "place_name"; +            element["columns"][1]["value"]  = name; + +            content["name"] = name; + +            std::string buffer = llformat("%.0f", (F64)dwell); +            element["columns"][2]["column"] = "dwell"; +            element["columns"][2]["value"]  = buffer; + +            search_results->addElement(element, ADD_BOTTOM); +            self->mResultsContent[parcel_id.asString()] = content; +        } +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +//////////////////////////////////////// +//          Land Search Panel         // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchLand> t_panel_fs_search_land("panel_ls_land"); + +FSPanelSearchLand::FSPanelSearchLand() : FSSearchPanelBase() +, mQueryID(nullptr) +, mStartSearch(0) +, mResultsReceived(0) +, mResultsContent() +{ +    mCommitCallbackRegistrar.add("CommitSearch", boost::bind(&FSPanelSearchLand::find, this)); +} + +FSPanelSearchLand::~FSPanelSearchLand() +{ +} + +BOOL FSPanelSearchLand::postBuild() +{ +    mSearchResults  = getChild<LLScrollListCtrl>("search_results_land"); +    mPriceEditor    = findChild<LLLineEditor>("price_edit"); +    mAreaEditor     = findChild<LLLineEditor>("area_edit"); +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchLand::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +    } +    if (mPriceEditor) +    { +        mPriceEditor->setCommitOnFocusLost(false); +        mPriceEditor->setCommitCallback(boost::bind(&FSPanelSearchLand::onBtnFind, this)); +    } +    if (mAreaEditor) +    { +        mAreaEditor->setCommitOnFocusLost(false); +        mAreaEditor->setCommitCallback(boost::bind(&FSPanelSearchLand::find, this)); +    } +    childSetAction("land_find", boost::bind(&FSPanelSearchLand::onBtnFind, this)); +    childSetAction("land_next", boost::bind(&FSPanelSearchLand::onBtnNext, this)); +    childSetAction("land_back", boost::bind(&FSPanelSearchLand::onBtnBack, this)); + +    getChildView("land_next")->setEnabled(FALSE); +    getChildView("land_back")->setEnabled(FALSE); + +    return TRUE; +} + +void FSPanelSearchLand::find() +{ +    static LLUICachedControl<bool> inc_pg("ShowPGLand", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureLand", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultLand", 0); +    static LLUICachedControl<bool> limit_price("FindLandPrice", 1); +    static LLUICachedControl<bool> limit_area("FindLandArea", 1); +    if (!(inc_pg || inc_mature || inc_adult)) +    { +        LLNotificationsUtil::add("NoContentToSearch"); +        return; +    } + +    U32 category = ST_ALL; +    const std::string& selection = findChild<LLComboBox>("land_category")->getSelectedValue().asString(); +    if (!selection.empty()) +    { +        if (selection == "Auction") +        { +            category = ST_AUCTION; +        } +        else if (selection == "Mainland") +        { +            category = ST_MAINLAND; +        } +        else if (selection == "Estate") +        { +            category = ST_ESTATE; +        } +    } + +    U32 scope = 0; +    if (gAgent.wantsPGOnly()) +    { +        scope |= DFQ_PG_SIMS_ONLY; +    } +    bool mature_enabled = gAgent.canAccessMature(); +    bool adult_enabled = gAgent.canAccessAdult(); +    if (inc_pg) +    { +        scope |= DFQ_INC_PG; +    } +    if (inc_mature && mature_enabled) +    { +        scope |= DFQ_INC_MATURE; +    } +    if (inc_adult && adult_enabled) +    { +        scope |= DFQ_INC_ADULT; +    } +    const std::string& sort = findChild<LLComboBox>("land_sort_combo")->getSelectedValue().asString(); +    if (!sort.empty()) +    { +        if (sort == "Name") +        { +            scope |= DFQ_NAME_SORT; +        } +        else if (sort == "Price") +        { +            scope |= DFQ_PRICE_SORT; +        } +        else if (sort == "PPM") +        { +            scope |= DFQ_PER_METER_SORT; +        } +        else if (sort == "Area") +        { +            scope |= DFQ_AREA_SORT; +        } +    } +    else +    { +        scope |= DFQ_PRICE_SORT; +    } +    if (childGetValue("ascending_check").asBoolean()) +    { +        scope |= DFQ_SORT_ASC; +    } +    if (limit_price) +    { +        scope |= DFQ_LIMIT_BY_PRICE; +    } +    if (limit_area) +    { +        scope |= DFQ_LIMIT_BY_AREA; +    } +    S32 price = childGetValue("edit_price").asInteger(); +    S32 area = childGetValue("edit_area").asInteger(); + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessage("DirLandQuery"); +    gMessageSystem->nextBlock("AgentData"); +    gMessageSystem->addUUID("AgentID", gAgentID); +    gMessageSystem->addUUID("SessionID", gAgentSessionID); +    gMessageSystem->nextBlock("QueryData"); +    gMessageSystem->addUUID("QueryID", getQueryID()); +    gMessageSystem->addU32("QueryFlags", scope); +    gMessageSystem->addU32("SearchType", category); +    gMessageSystem->addS32("Price", price); +    gMessageSystem->addS32("Area", area); +    gMessageSystem->addS32("QueryStart", mStartSearch); +    gAgent.sendReliableMessage(); +    LL_DEBUGS("Search") << "Firing off places search request: " << getQueryID() << category << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchLand::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    resetSearch(); + +    find(); +} + +void FSPanelSearchLand::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("land_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchLand::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("land_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchLand::resetSearch() +{ +    mStartSearch = 0; +    getChildView("land_back")->setEnabled(FALSE); +    getChildView("land_next")->setEnabled(FALSE); +} + +S32 FSPanelSearchLand::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("land_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchLand::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedItem(mSearchResults->getSelectedValue(), FSFloaterSearch::SC_PLACE); +    } +} + +// static +void FSPanelSearchLand::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID      agent_id; +    LLUUID      query_id; +    LLUUID      parcel_id; +    std::string name; +    std::string land_sku; +    std::string land_type; +    BOOL        auction; +    BOOL        for_sale; +    S32         price; +    S32         area; + +    msg->getUUID("AgentData", "AgentID", agent_id); +    msg->getUUID("QueryData", "QueryID", query_id); + +    // Not for us +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_DEBUGS("Search") << "received directory request - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchLand* self = FSFloaterSearch::getSearchPanel<FSPanelSearchLand>("panel_ls_land"); + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->mQueryID) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_land"); +    // clear "Searching" label on first results +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } + +    static LLUICachedControl<bool> use_price("FindLandPrice", 1); +    static LLUICachedControl<bool> use_area("FindLandArea", 1); +    S32 limit_price = self->childGetValue("edit_price").asInteger(); +    S32 limit_area = self->childGetValue("edit_area").asInteger(); + +    bool found_one = false; +    S32 num_new_rows = msg->getNumberOfBlocks("QueryReplies"); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("events_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } +    self->mResultsReceived += num_new_rows; + +    S32 not_auction = 0; +    for (S32 i = 0; i < num_new_rows; i++) +    { +        msg->getUUID(   "QueryReplies", "ParcelID",     parcel_id,  i); +        msg->getString( "QueryReplies", "Name",         name,       i); +        msg->getBOOL(   "QueryReplies", "Auction",      auction,    i); +        msg->getBOOL(   "QueryReplies", "ForSale",      for_sale,   i); +        msg->getS32(    "QueryReplies", "SalePrice",    price,      i); +        msg->getS32(    "QueryReplies", "ActualArea",   area,       i); +        if (parcel_id.isNull()) +        { +            LL_DEBUGS("Search") << "Null result returned for QueryID: " << query_id << LL_ENDL; +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("no_results")); +        } +        else +        { +            LL_DEBUGS("Search") << "Got: " << name << " ClassifiedID: " << parcel_id << LL_ENDL; +            search_results->setEnabled(TRUE); +            found_one = true; +            if (msg->getSizeFast(_PREHASH_QueryReplies, i, _PREHASH_ProductSKU) > 0) +            { +                msg->getStringFast( _PREHASH_QueryReplies, _PREHASH_ProductSKU, land_sku, i); +                land_type = LLProductInfoRequestManager::instance().getDescriptionForSku(land_sku); +            } +            else +            { +                land_sku.clear(); +                land_type = LLTrans::getString("land_type_unknown"); +            } +            if (parcel_id.isNull()) +            { +                continue; +            } +            if (use_price && (price > limit_price)) +            { +                continue; +            } +            if (use_area && (area < limit_area)) +            { +                continue; +            } + +            LLSD content; +            LLSD element; + +            element["id"] = parcel_id; +            if (auction) +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_Auction"; +            } +            else if (for_sale) +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_For_Sale"; +            } +            else +            { +                element["columns"][0]["column"] = "icon"; +                element["columns"][0]["type"]   = "icon"; +                element["columns"][0]["value"]  = "Icon_Place"; +            } + +            element["columns"][1]["column"] = "land_name"; +            element["columns"][1]["value"]  = name; + +            content["place_name"] = name; + +            std::string buffer = "Auction"; +            if (!auction) +            { +                buffer = llformat("%d", price); +                not_auction++; +            } +            element["columns"][2]["column"] = "price"; +            element["columns"][2]["value"]  = price; + +            element["columns"][3]["column"] = "area"; +            element["columns"][3]["value"]  = area; +            if (!auction) +            { +                F32 ppm; +                if (area > 0) +                { +                    ppm = (F32)price / (F32)area; +                } +                else +                { +                    ppm = 0.f; +                } +                std::string ppm_buffer = llformat("%.1f", ppm); +                element["columns"][4]["column"] = "ppm"; +                element["columns"][4]["value"] = ppm_buffer; +            } +            else +            { +                element["columns"][4]["column"] = "ppm"; +                element["columns"][4]["value"]  = "1.0"; +            } + +            element["columns"][5]["column"] = "land_type"; +            element["columns"][5]["value"]  = land_type; + +            search_results->addElement(element, ADD_BOTTOM); +            self->mResultsContent[parcel_id.asString()] = content; +        } +        // We test against non-auction properties because they don't count towards the page limit. +        self->showNextButton(not_auction); +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +//////////////////////////////////////// +//      Classifieds Search Panel      // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchClassifieds> t_panel_fs_search_classifieds("panel_ls_classifieds"); + +FSPanelSearchClassifieds::FSPanelSearchClassifieds() : FSSearchPanelBase() +, mQueryID(nullptr) +, mStartSearch(0) +, mResultsReceived(0) +, mResultsContent() +{ +    mCommitCallbackRegistrar.add("CommitSearch", boost::bind(&FSPanelSearchClassifieds::find, this)); +} + +FSPanelSearchClassifieds::~FSPanelSearchClassifieds() +{ +} + +BOOL FSPanelSearchClassifieds::postBuild() +{ +    mSearchComboBox = findChild<LLSearchComboBox>("classifieds_edit"); +    mSearchResults = getChild<LLScrollListCtrl>("search_results_classifieds"); +    if (mSearchComboBox) +    { +        mSearchComboBox->setCommitCallback(boost::bind(&FSPanelSearchClassifieds::onBtnFind, this)); +        fillSearchComboBox(mSearchComboBox); +    } +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchClassifieds::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +    } + +    mClassifiedsCategory = getChild<LLComboBox>("classifieds_category"); +    if (mClassifiedsCategory) +    { +        LLClassifiedInfo::cat_map::iterator iter; +        mClassifiedsCategory->add(LLTrans::getString("all_categories"), LLSD(0)); +        mClassifiedsCategory->addSeparator(); +        for (iter = LLClassifiedInfo::sCategories.begin(); +             iter != LLClassifiedInfo::sCategories.end(); +             iter++) +        { +            mClassifiedsCategory->add(LLTrans::getString(iter->second), LLSD((S32)iter->first)); +        } +    } +    childSetAction("classifieds_next", boost::bind(&FSPanelSearchClassifieds::onBtnNext, this)); +    childSetAction("classifieds_back", boost::bind(&FSPanelSearchClassifieds::onBtnBack, this)); + +    getChildView("classifieds_next")->setEnabled(FALSE); +    getChildView("classifieds_back")->setEnabled(FALSE); + +    return TRUE; +} + +void FSPanelSearchClassifieds::focusDefaultElement() +{ +    mSearchComboBox->focusTextEntry(); +} + +void FSPanelSearchClassifieds::find() +{ +    std::string text = filterShortWords(mSearchComboBox->getSimple()); +    if (text.size() == 0) +    { +        mSearchResults->setCommentText(LLTrans::getString("search_short")); +        return; +    } + +    static LLUICachedControl<bool> inc_pg("ShowPGClassifieds", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureClassifieds", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultClassifieds", 0); +    if (!(inc_pg || inc_mature || inc_adult)) +    { +        LLNotificationsUtil::add("NoContentToSearch"); +        return; +    } +    U32 category = mClassifiedsCategory->getValue().asInteger(); +    BOOL auto_renew = FALSE; +    U32 flags = pack_classified_flags_request(auto_renew, inc_pg, inc_mature, inc_adult); + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessageFast(_PREHASH_DirClassifiedQuery); +    gMessageSystem->nextBlockFast(_PREHASH_AgentData); +    gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID); +    gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); +    gMessageSystem->nextBlockFast(_PREHASH_QueryData); +    gMessageSystem->addUUIDFast(_PREHASH_QueryID, getQueryID()); +    gMessageSystem->addStringFast(_PREHASH_QueryText, text); +    gMessageSystem->addU32Fast(_PREHASH_QueryFlags, flags); +    gMessageSystem->addU32Fast(_PREHASH_Category, category); +    gMessageSystem->addS32Fast(_PREHASH_QueryStart, mStartSearch); +    gAgent.sendReliableMessage(); +    LL_DEBUGS("Search") << "Firing off classified ad search request: " << getQueryID() << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchClassifieds::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    std::string text = mSearchComboBox->getSimple(); +    if (!text.empty()) +    { +        LLSearchHistory::getInstance()->addEntry(text); +    } + +    resetSearch(); + +    find(); +} + +void FSPanelSearchClassifieds::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("classifieds_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchClassifieds::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("classifieds_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchClassifieds::resetSearch() +{ +    mStartSearch = 0; +    getChildView("classifieds_back")->setEnabled(FALSE); +    getChildView("classifieds_next")->setEnabled(FALSE); +} + +S32 FSPanelSearchClassifieds::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("classifieds_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchClassifieds::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedItem(mSearchResults->getSelectedValue(), FSFloaterSearch::SC_CLASSIFIED); +    } +} + +// static +void FSPanelSearchClassifieds::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID      agent_id; +    LLUUID      query_id; +    LLUUID      classified_id; +    std::string name; +    U32         creation_date; +    U32         expiration_date; +    S32         price_for_listing; + +    msg->getUUID("AgentData", "AgentID", agent_id); +    msg->getUUID("QueryData", "QueryID", query_id); + +    // Not for us +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_DEBUGS("Search") << "received directory request - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchClassifieds* self = FSFloaterSearch::getSearchPanel<FSPanelSearchClassifieds>("panel_ls_classifieds"); + +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_CLASSIFIEDS_BANNEDWORD) +        { +            LLNotificationsUtil::add("SearchWordBanned"); +        } +    } + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->mQueryID) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_classifieds"); + +    // Clear "Searching" label on first results +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } + +    // Check for status messages +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_PLACES_FOUNDNONE) +        { +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("classifieds_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +            return; +        } +        else if(status & STATUS_SEARCH_PLACES_SHORTSTRING) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_short")); +            return; +        } +        else if (status & STATUS_SEARCH_CLASSIFIEDS_BANNEDWORD) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_banned")); +            return; +        } +        else if (status & STATUS_SEARCH_PLACES_SEARCHDISABLED) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +    } + +    bool found_one = false; +    S32 num_new_rows = msg->getNumberOfBlocks("QueryReplies"); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("classifieds_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } +    self->mResultsReceived += num_new_rows; +    num_new_rows = self->showNextButton(num_new_rows); + +    for (S32 i = 0; i < num_new_rows; i++) +    { +        msg->getUUID(   "QueryReplies", "ClassifiedID",     classified_id,  i); +        msg->getString( "QueryReplies", "Name",             name,           i); +        msg->getU32(    "QueryReplies", "CreationDate",     creation_date,  i); +        msg->getU32(    "QueryReplies", "ExpirationDate",   expiration_date,i); +        msg->getS32(    "QueryReplies", "PriceForListing",  price_for_listing,i); +        if (classified_id.isNull()) +        { +            LL_DEBUGS("Search") << "Null result returned for QueryID: " << query_id << LL_ENDL; +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("classifieds_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +        } +        else +        { +            LL_DEBUGS("Search") << "Got: " << name << " ClassifiedID: " << classified_id << LL_ENDL; +            search_results->setEnabled(TRUE); +            found_one = true; + +            LLSD content; +            LLSD element; + +            element["id"] = classified_id; + +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"]   = "icon"; +            element["columns"][0]["value"]  = "icon_top_pick.tga"; + +            element["columns"][1]["column"] = "classified_name"; +            element["columns"][1]["value"]  = name; + +            element["columns"][2]["column"] = "price"; +            element["columns"][2]["value"]  = price_for_listing; + +            content["name"] = name; + +            search_results->addElement(element, ADD_BOTTOM); +            self->mResultsContent[classified_id.asString()] = content; +        } +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +//////////////////////////////////////// +//        Events Search Panel         // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchEvents> t_panel_fs_search_events("panel_ls_events"); + +FSPanelSearchEvents::FSPanelSearchEvents() : FSSearchPanelBase() +, mQueryID(nullptr) +, mResultsReceived(0) +, mStartSearch(0) +, mDay(0) +, mResultsContent() +{ +    mCommitCallbackRegistrar.add("CommitSearch", boost::bind(&FSPanelSearchEvents::find, this)); +} + +FSPanelSearchEvents::~FSPanelSearchEvents() +{ +} + +BOOL FSPanelSearchEvents::postBuild() +{ +    mSearchComboBox = findChild<LLSearchComboBox>("events_edit"); +    mSearchResults = getChild<LLScrollListCtrl>("search_results_events"); +    mEventsMode = findChild<LLRadioGroup>("events_search_mode"); +    if (mSearchComboBox) +    { +        mSearchComboBox->setCommitCallback(boost::bind(&FSPanelSearchEvents::onBtnFind, this)); +        fillSearchComboBox(mSearchComboBox); +    } +    if (mSearchResults) +    { +        mSearchResults->setCommitCallback(boost::bind(&FSPanelSearchEvents::onSelectItem, this)); +        mSearchResults->setEnabled(FALSE); +        mSearchResults->setCommentText(LLTrans::getString("no_results")); +    } +    if (mEventsMode) +    { +        mEventsMode->setCommitCallback(boost::bind(&FSPanelSearchEvents::onSearchModeChanged, this)); +        mEventsMode->selectFirstItem(); +    } + +    childSetAction("events_next", boost::bind(&FSPanelSearchEvents::onBtnNext, this)); +    childSetAction("events_back", boost::bind(&FSPanelSearchEvents::onBtnBack, this)); +    childSetAction("events_tomorrow", boost::bind(&FSPanelSearchEvents::onBtnTomorrow, this)); +    childSetAction("events_yesterday", boost::bind(&FSPanelSearchEvents::onBtnYesterday, this)); +    childSetAction("events_today", boost::bind(&FSPanelSearchEvents::onBtnToday, this)); + +    getChildView("events_next")->setEnabled(FALSE); +    getChildView("events_back")->setEnabled(FALSE); +    getChildView("events_tomorrow")->setEnabled(FALSE); +    getChildView("events_yesterday")->setEnabled(FALSE); +    getChildView("events_today")->setEnabled(FALSE); +    setDay(0); + +    return TRUE; +} + +void FSPanelSearchEvents::focusDefaultElement() +{ +    mSearchComboBox->focusTextEntry(); +} + +void FSPanelSearchEvents::find() +{ +    std::string text = filterShortWords(mSearchComboBox->getSimple()); + +    static LLUICachedControl<bool> inc_pg("ShowPGEvents", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureEvents", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultEvents", 0); +    if (!(inc_pg || inc_mature || inc_adult)) +    { +        LLNotificationsUtil::add("NoContentToSearch"); +        return; +    } + +    U32 category = findChild<LLComboBox>("events_category")->getSelectedValue().asInteger(); +    U32 scope = DFQ_DATE_EVENTS; +    if (gAgent.wantsPGOnly()) +    { +        scope |= DFQ_PG_SIMS_ONLY; +    } +    bool mature_enabled = gAgent.canAccessMature(); +    bool adult_enabled = gAgent.canAccessAdult(); +    if (inc_pg) +    { +        scope |= DFQ_INC_PG; +    } +    if (inc_mature && mature_enabled) +    { +        scope |= DFQ_INC_MATURE; +    } +    if (inc_adult && adult_enabled) +    { +        scope |= DFQ_INC_ADULT; +    } + +    std::ostringstream string; + +    if ("current" == childGetValue("events_search_mode").asString()) +    { +        string << "u|"; +    } +    else +    { +        string << mDay << "|"; +    } +    string << category << "|"; +    string << text; + +    mResultsReceived = 0; +    if (mQueryID.notNull()) +    { +        mQueryID.setNull(); +    } +    mQueryID.generate(); + +    if (mStartSearch < 0) +    { +        mStartSearch = 0; +    } + +    gMessageSystem->newMessage("DirFindQuery"); +    gMessageSystem->nextBlock("AgentData"); +    gMessageSystem->addUUID("AgentID", gAgentID); +    gMessageSystem->addUUID("SessionID", gAgentSessionID); +    gMessageSystem->nextBlock("QueryData"); +    gMessageSystem->addUUID("QueryID", getQueryID()); +    gMessageSystem->addString("QueryText", string.str()); +    gMessageSystem->addU32("QueryFlags", scope); +    gMessageSystem->addS32("QueryStart", mStartSearch); +    gAgent.sendReliableMessage(); +    LL_INFOS("Search") << "Firing off search request: " << getQueryID() << " Search Text: " << string.str() << LL_ENDL; + +    mSearchResults->deleteAllItems(); +    mSearchResults->setCommentText(LLTrans::getString("searching")); +    mNumResultsReturned = 0; +} + +void FSPanelSearchEvents::onBtnFind() +{ +    std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now(); +    auto elapsed = now - lastRequestTime; +    U64 elapsedMS = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +    if(elapsedMS < REQUEST_MIN_ELAPSED_TIME) return; +    lastRequestTime = now; + +    std::string text = mSearchComboBox->getSimple(); +    if (!text.empty()) +    { +        LLSearchHistory::getInstance()->addEntry(text); +    } + +    resetSearch(); + +    find(); +} + +void FSPanelSearchEvents::onBtnNext() +{ +    mStartSearch += RESULT_PAGE_SIZE; +    getChildView("events_back")->setEnabled(TRUE); + +    find(); +} + +void FSPanelSearchEvents::onBtnBack() +{ +    mStartSearch -= RESULT_PAGE_SIZE; +    getChildView("events_back")->setEnabled(mStartSearch > 0); + +    find(); +} + +void FSPanelSearchEvents::onBtnTomorrow() +{ +    resetSearch(); +    setDay(mDay + 1); + +    find(); +} + +void FSPanelSearchEvents::onBtnYesterday() +{ +    resetSearch(); +    setDay(mDay - 1); + +    find(); +} + +void FSPanelSearchEvents::onBtnToday() +{ +    resetSearch(); +    setDay(0); + +    find(); +} + +void FSPanelSearchEvents::resetSearch() +{ +    mStartSearch = 0; +    getChildView("events_back")->setEnabled(FALSE); +    getChildView("events_next")->setEnabled(FALSE); +} + +void FSPanelSearchEvents::onSearchModeChanged() +{ +    if (mEventsMode->getValue().asString() == "current") +    { +        getChildView("events_yesterday")->setEnabled(FALSE); +        getChildView("events_tomorrow")->setEnabled(FALSE); +        getChildView("events_today")->setEnabled(FALSE); +    } +    else +    { +        getChildView("events_yesterday")->setEnabled(TRUE); +        getChildView("events_tomorrow")->setEnabled(TRUE); +        getChildView("events_today")->setEnabled(TRUE); +    } +} + +void FSPanelSearchEvents::setDay(S32 day) +{ +    mDay = day; +    struct tm* internal_time; + +    time_t utc = time_corrected(); +    utc += day * 24 * 60 * 60; +    internal_time = utc_to_pacific_time(utc, is_daylight_savings()); +    std::string buffer = llformat("%d/%d", 1 + internal_time->tm_mon, internal_time->tm_mday); +    childSetValue("events_date", buffer); +} + +S32 FSPanelSearchEvents::showNextButton(S32 rows) +{ +    bool show_next_button = (mResultsReceived > RESULT_PAGE_SIZE); +    getChildView("events_next")->setEnabled(show_next_button); +    if (show_next_button) +    { +        rows -= (mResultsReceived - RESULT_PAGE_SIZE); +    } +    return rows; +} + +void FSPanelSearchEvents::onSelectItem() +{ +    if (!mSearchResults) +    { +        return; +    } +    S32 event_id = mSearchResults->getSelectedValue(); +    FSFloaterSearch* search_instance = LLFloaterReg::findTypedInstance<FSFloaterSearch>("search"); +    if (search_instance) +    { +        search_instance->FSFloaterSearch::onSelectedEvent(event_id); +    } +} + +// static +void FSPanelSearchEvents::processSearchReply(LLMessageSystem* msg, void**) +{ +    LLUUID      agent_id; +    LLUUID      query_id; +    LLUUID      owner_id; +    std::string name; +    std::string date; + +    msg->getUUID("AgentData", "AgentID", agent_id); +    msg->getUUID("QueryData", "QueryID", query_id); + +    // Not for us +    if (agent_id != gAgentID) +    { +        return; +    } +    LL_DEBUGS("Search") << "received directory request - QueryID: " << query_id << " AgentID: " << agent_id << LL_ENDL; + +    FSPanelSearchEvents* self = FSFloaterSearch::getSearchPanel<FSPanelSearchEvents>("panel_ls_events"); + +    // floater is closed or these are not results from our last request +    if (!self || query_id != self->mQueryID) +    { +        return; +    } + +    LLScrollListCtrl* search_results = self->getChild<LLScrollListCtrl>("search_results_events"); + +    // Clear "Searching" label on first results +    if (self->mNumResultsReturned++ == 0) +    { +        search_results->deleteAllItems(); +    } +    // Check for status messages +    if (msg->getNumberOfBlocks("StatusData")) +    { +        U32 status; +        msg->getU32("StatusData", "Status", status); +        if (status & STATUS_SEARCH_EVENTS_FOUNDNONE) +        { +            LLStringUtil::format_map_t map; +            map["[TEXT]"] = self->getChild<LLUICtrl>("events_edit")->getValue().asString(); +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("not_found", map)); +            return; +        } +        else if(status & STATUS_SEARCH_EVENTS_SHORTSTRING) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_short")); +            return; +        } +        else if (status & STATUS_SEARCH_EVENTS_BANNEDWORD) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_banned")); +            return; +        } +        else if (status & STATUS_SEARCH_EVENTS_SEARCHDISABLED) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_disabled")); +            return; +        } +        else if (status & STATUS_SEARCH_EVENTS_NODATEOFFSET) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_no_date_offset")); +            return; +        } +        else if (status & STATUS_SEARCH_EVENTS_NOCATEGORY) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_no_events_category")); +            return; +        } +        else if (status & STATUS_SEARCH_EVENTS_NOQUERY) +        { +            search_results->setEnabled(FALSE); +            search_results->setCommentText(LLTrans::getString("search_no_query")); +            return; +        } +    } + +    S32 num_new_rows = msg->getNumberOfBlocks("QueryReplies"); +    if (num_new_rows == 0 && self->mResultsReceived == 0) +    { +        LLStringUtil::format_map_t map; +        map["[TEXT]"] = self->getChild<LLUICtrl>("events_edit")->getValue().asString(); +        search_results->setEnabled(FALSE); +        search_results->setCommentText(LLTrans::getString("not_found", map)); +    } + +    self->mResultsReceived += num_new_rows; +    num_new_rows = self->showNextButton(num_new_rows); +    static LLUICachedControl<bool> inc_pg("ShowPGEvents", 1); +    static LLUICachedControl<bool> inc_mature("ShowMatureEvents", 0); +    static LLUICachedControl<bool> inc_adult("ShowAdultEvents", 0); +    bool found_one = false; + +    for (S32 i = 0; i < num_new_rows; i++) +    { +        U32 event_id; +        U32 unix_time; +        U32 event_flags; + +        msg->getUUID(   "QueryReplies", "OwnerID",      owner_id,   i); +        msg->getString( "QueryReplies", "Name",         name,       i); +        msg->getU32(    "QueryReplies", "EventID",      event_id,   i); +        msg->getString( "QueryReplies", "Date",         date,       i); +        msg->getU32(    "QueryReplies", "UnixTime",     unix_time,  i); +        msg->getU32(    "QueryReplies", "EventFlags",   event_flags,i); + +        // Skip empty events... +        if (owner_id.isNull()) +        { +            LL_INFOS("Search") << "Skipped " << event_id << " because of a nullptr owner result" << LL_ENDL; +            continue; +        } +        // Skips events that don't match our scope... +        if (((event_flags & (EVENT_FLAG_ADULT | EVENT_FLAG_MATURE)) == EVENT_FLAG_NONE) && !inc_pg) +        { +            LL_INFOS("Search") << "Skipped " << event_id << " because it was out of scope" << LL_ENDL; +            continue; +        } +        if ((event_flags & EVENT_FLAG_MATURE) && !inc_mature) +        { +            LL_INFOS("Search") << "Skipped " << event_id << " because it was out of scope" << LL_ENDL; +            continue; +        } +        if ((event_flags & EVENT_FLAG_ADULT) && !inc_adult) +        { +            LL_INFOS("Search") << "Skipped " << event_id << " because it was out of scope" << LL_ENDL; +            continue; +        } +        search_results->setEnabled(TRUE); +        found_one = true; + +        LLSD content; +        LLSD element; + +        element["id"] = llformat("%u", event_id); + +        if (event_flags == EVENT_FLAG_ADULT) +        { +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"] = "icon"; +            element["columns"][0]["value"] = "Icon_Legacy_Event_Adult"; +        } +        else if (event_flags == EVENT_FLAG_MATURE) +        { +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"] = "icon"; +            element["columns"][0]["value"] = "Icon_Legacy_Event_Mature"; +        } +        else +        { +            element["columns"][0]["column"] = "icon"; +            element["columns"][0]["type"] = "icon"; +            element["columns"][0]["value"] = "Icon_Legacy_Event_PG"; +        } +        element["columns"][1]["column"] = "name"; +        element["columns"][1]["value"] = name; + +        element["columns"][2]["column"] = "date"; +        element["columns"][2]["value"] = date; + +        element["columns"][3]["column"] = "time"; +        element["columns"][3]["value"] = llformat("%u", unix_time); + +        content["name"] = name; +        content["event_id"] = (S32)event_id; + +        search_results->addElement(element, ADD_BOTTOM); +        std::string event = llformat("%u", event_id); +        self->mResultsContent[event] = content; +    } +    if (found_one) +    { +        search_results->selectFirstItem(); +        search_results->setFocus(TRUE); +        self->onSelectItem(); +    } +} + +//////////////////////////////////////// +//          WebSearch Panel           // +//////////////////////////////////////// + +static LLPanelInjector<FSPanelSearchWeb> t_panel_fs_search_web("panel_ls_web"); + +FSPanelSearchWeb::FSPanelSearchWeb() : FSSearchPanelBase() +, mWebBrowser(nullptr) +, mResetFocusOnLoad(false) +{ +    // Second Life grids use a different URL format now +    mCategoryPaths = LLSD::emptyMap(); +    if (LLGridManager::getInstance()->isInSecondlife()) +    { +        // declare a map that transforms a category name into +        // the parameter list that is used to search that category +        mCategoryPaths["people"]       = "collection_chosen=people"; +        mCategoryPaths["places"]       = "collection_chosen=places"; +        mCategoryPaths["events"]       = "collection_chosen=events"; +        mCategoryPaths["groups"]       = "collection_chosen=groups"; +        mCategoryPaths["destinations"] = "collection_chosen=destinations"; + +        mCategoryPaths["classifieds"]  = "search_type=classified"; +        mCategoryPaths["wiki"]         = "search/wiki";                     // not sure if this is still a thing in the new search + +        mCategoryPaths["all"]          = mCategoryPaths["people"].asString() + "&" + +                                        mCategoryPaths["places"].asString() + "&" + +                                        mCategoryPaths["events"].asString() + "&" + +                                        mCategoryPaths["groups"].asString() + "&" + +                                        mCategoryPaths["destinations"].asString(); +    } +    // OpenSim currently still uses the old URL format +    else +    { +        // declare a map that transforms a category name into +        // the URL suffix that is used to search that category +        mCategoryPaths["all"]          = "search"; +        mCategoryPaths["people"]       = "search/people"; +        mCategoryPaths["places"]       = "search/places"; +        mCategoryPaths["events"]       = "search/events"; +        mCategoryPaths["groups"]       = "search/groups"; +        mCategoryPaths["wiki"]         = "search/wiki"; +        mCategoryPaths["destinations"] = "destinations"; +        mCategoryPaths["classifieds"]  = "classifieds"; +    } +} + +BOOL FSPanelSearchWeb::postBuild() +{ +    mWebBrowser = getChild<LLMediaCtrl>("search_browser"); +    return TRUE; +} + +void FSPanelSearchWeb::loadURL(const SearchQuery &p) +{ +    if (!mWebBrowser || !p.validateBlock()) +    { +        return; +    } + +    // CATEGORY is no longer used as part of the path on Second Life grids +    LLSD subs = LLSD().with("CATEGORY", ""); + +    // on OpenSim grids it probably is currently still being used, so keep the old behavior +    if (!LLGridManager::getInstance()->isInSecondlife()) +    { +        // work out the subdir to use based on the requested category +        LLSD subs = LLSD().with("CATEGORY", (mCategoryPaths.has(p.category.getValue()) ? mCategoryPaths[p.category.getValue()].asString() : mCategoryPaths["all"].asString())); +    } + +    // add the search query string +    subs["QUERY"] = LLURI::escape(p.query.getValue()); + +    // add the permissions token that login.cgi gave us +    // We use "search_token", and fallback to "auth_token" if not present. +    LLSD search_token = LLLoginInstance::getInstance()->getResponse("search_token"); +    if (search_token.asString().empty()) +    { +        search_token = LLLoginInstance::getInstance()->getResponse("auth_token"); +    } +    subs["AUTH_TOKEN"] = search_token.asString(); + +    // add the user's preferred maturity (can be changed via prefs) +    std::string maturity; + +    // on Second Life grids, the maturity level is now a "&maturity" parameter that's not in the provided search URL +    if (LLGridManager::getInstance()->isInSecondlife()) +    { +        if (gAgent.prefersAdult()) +        { +            maturity = "gma";  // PG,Mature,Adult +        } +        else if (gAgent.prefersMature()) +        { +            maturity = "gm";  // PG,Mature +        } +        else +        { +            maturity = "g";  // PG +        } + +        // not used on the SL search anymore, so clear out the respective parameter +        subs["MATURITY"] = ""; +    } +    // OpenSim probably still uses the old maturity variant, so keep the old behavior here +    else +    { +        if (gAgent.prefersAdult()) +        { +            maturity = "42";  // PG,Mature,Adult +        } +        else if (gAgent.prefersMature()) +        { +            maturity = "21";  // PG,Mature +        } +        else +        { +            maturity = "13";  // PG +        } +        subs["MATURITY"] = maturity; +    } + +    // add the user's god status +    subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0"; + +    // Get the search URL and expand all of the substitutions +    // (also adds things like [LANGUAGE], [VERSION], [OS], etc.) + +    // add the maturity and category variables to the new Second Life search URL +    //std::string url = gAgent.getRegion() != nullptr ? gAgent.getRegion()->getSearchServerURL() : gSavedSettings.getString(LLGridManager::getInstance()->isInOpenSim() ? "OpenSimSearchURL" : "SearchURL"); + +    std::string url = gSavedSettings.getString("SearchURL"); + +    if (LLGridManager::getInstance()->isInSecondlife()) +    { +        url.append("&maturity=" + maturity + "&" + mCategoryPaths[p.category.getValue()].asString()); +    } + +    url = LLWeb::expandURLSubstitutions(url, subs); + +    // Finally, load the URL in the webpanel +    mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); +} + +void FSPanelSearchWeb::focusDefaultElement() +{ +    mWebBrowser->setFocus(TRUE); +} + +void FSPanelSearchWeb::draw() +{ +    if (mResetFocusOnLoad) +    { +        focusDefaultElement(); +        mResetFocusOnLoad = false; +    } + +    FSSearchPanelBase::draw(); +} + +//////////////////////////////////////// +//           Local functions          // +//////////////////////////////////////// + +std::string filterShortWords(std::string query_string) +{ +    if (query_string.length() < 1) +    { +        return ""; +    } + +    std::string final_query; +    bool filtered = false; +    boost::char_separator<char> sep(" "); +    boost::tokenizer<boost::char_separator<char> > tokens(query_string, sep); +    boost::tokenizer<boost::char_separator<char> >::iterator iter = tokens.begin(); +    boost::tokenizer<boost::char_separator<char> >::iterator last = tokens.end(); +    boost::tokenizer<boost::char_separator<char> >::iterator temp; +    for (; iter != last; ++iter) +    { +        if ((*iter).length() > MIN_SEARCH_STRING_SIZE) +        { +            final_query.append((*iter)); +            temp = iter; ++temp; +            if (temp != last) +            { +                final_query.append(" "); +            } +        } +        else +        { +            filtered = true; +        } +    } + +    if (filtered) +    { +        LLSD args = LLSD().with("FINALQUERY", final_query); +        LLNotificationsUtil::add("SeachFilteredOnShortWords", args); +    } + +    return final_query; +} + +void fillSearchComboBox(LLSearchComboBox* search_combo) +{ +    if (search_combo == nullptr) +    { +        return; +    } + +    LLSearchHistory::getInstance()->load(); + +    LLSearchHistory::search_history_list_t search_list = +    LLSearchHistory::getInstance()->getSearchHistoryList(); +    LLSearchHistory::search_history_list_t::const_iterator it = search_list.begin(); +    for ( ; search_list.end() != it; ++it) +    { +        LLSearchHistory::LLSearchHistoryItem item = *it; +        search_combo->add(item.search_query); +    } +} diff --git a/indra/newview/fsfloatersearch.h b/indra/newview/fsfloatersearch.h new file mode 100644 index 0000000000..61cef8bab9 --- /dev/null +++ b/indra/newview/fsfloatersearch.h @@ -0,0 +1,404 @@ +/** + * @file fsfloatersearch.h + * @brief Firestorm search definitions + * + * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2012, Cinder Roxley <cinder.roxley@phoenixviewer.com> + * + * 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$ + */ + +#ifndef FS_FLOATERSEARCH_H +#define FS_FLOATERSEARCH_H + +#include "llfloater.h" +#include "lliconctrl.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "llremoteparcelrequest.h" +#include "llavatarpropertiesprocessor.h" +#include "llgroupmgr.h" +#include "llavatarnamecache.h" +#include "llmediactrl.h" +#include "llradiogroup.h" +#include "llsearchcombobox.h" +#include "llscrolllistctrl.h" +#include "lltabcontainer.h" +#include "lleventnotifier.h" + +class FSSearchRemoteParcelInfoObserver; +class LLAvatarPropertiesObserver; +class LLGroupMgrObserver; +class LLSearchEditor; +class LLSearchComboBox; +class FSFloaterSearch; +class LLPanelProfile; +class FSScrollListCtrl; + +struct SearchQuery : public LLInitParam::Block<SearchQuery> +{ +    Optional<std::string> category; +    Optional<std::string> query; + +    SearchQuery(); +}; + +/////////////////////////////// +//       Search Panels       // +/////////////////////////////// + +class FSSearchPanelBase : public LLPanel +{ +public: +    FSSearchPanelBase() : LLPanel() { } +    virtual ~FSSearchPanelBase() = default; +    virtual void focusDefaultElement() { } +}; + +class FSPanelSearchPeople : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchPeople(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +    /*virtual*/ void focusDefaultElement(); + +protected: +    const S32& getNumResultsReturned() const { return mNumResultsReturned; }; +    const S32& getNumResultsReceived() const { return mResultsReceived; }; + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchPeople(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); + +    void find(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    void onAvatarNameCallback(const LLUUID& id, const LLAvatarName& av_name); + +    typedef boost::signals2::connection avatar_name_callback_connection_t; +    avatar_name_callback_connection_t mAvatarNameCallbackConnection; + +    S32         mNumResultsReturned; +    S32         mStartSearch; +    S32         mResultsReceived; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLSearchComboBox*       mSearchComboBox; +    LLScrollListCtrl*       mSearchResults; +}; + +class FSPanelSearchGroups : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchGroups(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +    /*virtual*/ void focusDefaultElement(); + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchGroups(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); + +    void find(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    S32         mNumResultsReturned; +    S32         mStartSearch; +    S32         mResultsReceived; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLSearchComboBox*   mSearchComboBox; +    LLScrollListCtrl*   mSearchResults; +}; + +class FSPanelSearchPlaces : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchPlaces(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +    /*virtual*/ void focusDefaultElement(); + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchPlaces(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); + +    void find(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    S32         mNumResultsReturned; +    S32         mStartSearch; +    S32         mResultsReceived; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLSearchComboBox*   mSearchComboBox; +    LLScrollListCtrl*   mSearchResults; +    LLComboBox*         mPlacesCategory; +}; + +class FSPanelSearchLand : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchLand(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchLand(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); + +    void find(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    S32         mNumResultsReturned; +    S32         mStartSearch; +    S32         mResultsReceived; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLLineEditor*       mPriceEditor; +    LLLineEditor*       mAreaEditor; +    LLScrollListCtrl*   mSearchResults; +}; + +class FSPanelSearchClassifieds : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchClassifieds(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +    /*virtual*/ void focusDefaultElement(); + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchClassifieds(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); + +    void find(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    S32         mNumResultsReturned; +    S32         mStartSearch; +    S32         mResultsReceived; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLSearchComboBox*   mSearchComboBox; +    LLScrollListCtrl*   mSearchResults; +    LLComboBox*         mClassifiedsCategory; +}; + +class FSPanelSearchEvents : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchEvents(); +    static void processSearchReply(LLMessageSystem* msg, void**); + +    /*virtual*/ void focusDefaultElement(); + +private: +    /*virtual*/ BOOL postBuild(); +    virtual ~FSPanelSearchEvents(); + +    void onBtnFind(); +    void onSelectItem(); +    void onBtnNext(); +    void onBtnBack(); +    void onBtnTomorrow(); +    void onBtnYesterday(); +    void onBtnToday(); + +    void find(); +    void setDay(S32 day); +    void onSearchModeChanged(); +    void resetSearch(); +    S32  showNextButton(S32); + +    const LLUUID& getQueryID() const { return mQueryID; } + +    S32         mNumResultsReturned; +    S32         mResultsReceived; +    S32         mStartSearch; +    S32         mDay; +    LLSD        mResultsContent; +    LLUUID      mQueryID; + +    LLSearchComboBox*   mSearchComboBox; +    LLScrollListCtrl*   mSearchResults; +    LLRadioGroup*       mEventsMode; +}; + +class FSPanelSearchWeb : public FSSearchPanelBase +{ +    LOG_CLASS(FSFloaterSearch); +public: +    FSPanelSearchWeb(); +    /*virtual*/ BOOL postBuild(); +    void loadURL(const SearchQuery &query); +    /*virtual*/ void focusDefaultElement(); +    /*virtual*/ void draw(); +    void resetFocusOnLoad() { mResetFocusOnLoad = true; } + +private: +    virtual ~FSPanelSearchWeb() {}; + +    LLMediaCtrl*    mWebBrowser; +    LLSD            mCategoryPaths; + +    bool            mResetFocusOnLoad; +}; + +class FSFloaterSearch : public LLFloater +{ +    LOG_CLASS(FSFloaterSearch); +public: +    typedef enum e_search_category +    { +        SC_AVATAR, +        SC_GROUP, +        SC_PLACE, +        SC_CLASSIFIED +    }   ESearchCategory; + +    struct _Params : public LLInitParam::Block<_Params, LLFloater::Params> +    { +        Optional<SearchQuery> search; +    }; + +    typedef LLSDParamAdapter<_Params> Params; + +    FSFloaterSearch(const Params& key); +    ~FSFloaterSearch(); +    void onOpen(const LLSD& key); +    BOOL postBuild(); + +    void avatarNameUpdatedCallback(const LLUUID& id, const LLAvatarName& av_name); +    void groupNameUpdatedCallback(const LLUUID& id, const std::string& name, bool is_group); +    void onSelectedItem(const LLUUID& selected_item, ESearchCategory type); +    void onSelectedEvent(const S32 selected_event); +    void displayParcelDetails(const LLParcelData& parcel_data); +    void displayClassifiedDetails(LLAvatarClassifiedInfo*& c_info); +    void displayAvatarDetails(LLAvatarData* avatar_data); +    void displayGroupDetails(LLGroupMgrGroupData*& group_data); +    bool displayEventDetails(LLEventStruct event); +    void displayEventParcelImage(const LLParcelData& parcel_data); +    void setLoadingProgress(bool started); + +    template <class T> +    static T* getSearchPanel(const std::string& panel_name); + +private: +    virtual void onClose(bool app_quitting); +    const LLUUID& getSelectedID() { return mSelectedID; } +    LLVector3d  mParcelGlobal; +    LLUUID      mSelectedID; +    U32         mEventID; +    bool        mHasSelection; + +    void resetVerbs(); +    void flushDetails(); +    void onTabChange(); +    void onBtnPeopleProfile(); +    void onBtnPeopleIM(); +    void onBtnPeopleFriend(); +    void onBtnGroupProfile(); +    void onBtnGroupChat(); +    void onBtnGroupJoin(); +    void onBtnEventReminder(); +    void onBtnTeleport(); +    void onBtnMap(); + +    void regionHandleCallback(U64 region_handle, LLVector3d pos_global); + +    FSSearchRemoteParcelInfoObserver* mRemoteParcelObserver; +    FSSearchRemoteParcelInfoObserver* mRemoteParcelEventLocationObserver; +    LLAvatarPropertiesObserver* mAvatarPropertiesObserver; +    LLGroupMgrObserver* mGroupPropertiesRequest; +    boost::signals2::connection mEventNotifierConnection; + +    FSPanelSearchPeople*    mPanelPeople; +    FSPanelSearchGroups*    mPanelGroups; +    FSPanelSearchPlaces*    mPanelPlaces; +    FSPanelSearchEvents*    mPanelEvents; +    FSPanelSearchLand*      mPanelLand; +    FSPanelSearchClassifieds* mPanelClassifieds; +    FSPanelSearchWeb*       mPanelWeb; + +    LLPanel*        mDetailsPanel; +    LLTextEditor*   mDetailTitle; +    LLTextEditor*   mDetailDesc; +    LLTextEditor*   mDetailAux1; +    LLTextEditor*   mDetailAux2; +    LLTextEditor*   mDetailLocation; +    LLTextureCtrl*  mDetailSnapshot; +    LLTextureCtrl*  mDetailSnapshotParcel; +    LLIconCtrl*     mDetailMaturity; +    LLTabContainer* mTabContainer; +}; + +#endif // FS_FLOATERSEARCH_H diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 72bdbb6975..715649e844 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -468,6 +468,8 @@ void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* ms      // Request processed, no longer pending      self->removePendingRequest(c_info.creator_id, APT_CLASSIFIED_INFO);      self->notifyObservers(c_info.creator_id, &c_info, APT_CLASSIFIED_INFO); +    self->removePendingRequest(c_info.classified_id, APT_CLASSIFIED_INFO); +    self->notifyObservers(c_info.classified_id, &c_info, APT_CLASSIFIED_INFO);  } diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index 0a1445419e..c73cc69e62 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -52,6 +52,9 @@ enum EAvatarProcessorType  {      APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request (Truncates data!!!)      APT_PROPERTIES,        // APT_PROPERTIES via http request +    APT_NOTES, +    APT_GROUPS, +    APT_PICKS,      APT_PICK_INFO,      APT_TEXTURES,      APT_CLASSIFIEDS, @@ -105,6 +108,24 @@ struct LLAvatarData      typedef std::pair<LLUUID, std::string> pick_data_t;      typedef std::list< pick_data_t> picks_list_t;      picks_list_t picks_list; +    BOOL        allow_publish; +    LLAvatarData() = default; +    LLAvatarData(const LLAvatarLegacyData& legacy_data) +    { +        agent_id = legacy_data.agent_id; +        avatar_id = legacy_data.avatar_id; +        image_id = legacy_data.image_id; +        fl_image_id = legacy_data.fl_image_id; +        partner_id = legacy_data.partner_id; +        about_text = legacy_data.about_text; +        fl_about_text = legacy_data.fl_about_text; +        born_on = legacy_data.born_on; +        profile_url = legacy_data.profile_url; +        caption_index = legacy_data.caption_index; +        caption_text = legacy_data.caption_text; +        customer_type = legacy_data.customer_type; +        flags = legacy_data.flags; +    }  };  struct LLAvatarData::LLGroupData @@ -140,6 +161,45 @@ struct LLPickData      LLUUID session_id;  }; +struct LLAvatarPicks +{ +    LLUUID agent_id; +    LLUUID target_id; //target id + +    typedef std::pair<LLUUID,std::string> pick_data_t; +    typedef std::list< pick_data_t> picks_list_t; +    picks_list_t picks_list; +}; + +struct LLAvatarNotes +{ +    LLUUID agent_id; +    LLUUID target_id; //target id +    std::string notes; +}; + +struct LLAvatarGroups +{ +    LLUUID agent_id; +    LLUUID avatar_id; //target id +    BOOL list_in_profile; + +    struct LLGroupData; +    typedef std::list<LLGroupData> group_list_t; + +    group_list_t group_list; + +    struct LLGroupData +    { +        U64 group_powers; +        BOOL accept_notices; +        std::string group_title; +        LLUUID group_id; +        std::string group_name; +        LLUUID group_insignia_id; +    }; +}; +  struct LLAvatarClassifieds  {      LLUUID agent_id; diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index d46b49362a..93389bbc0f 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -182,6 +182,23 @@ bool LLEventNotifier::add(U32 eventId, F64 eventEpoch, const std::string& eventD  } +bool LLEventNotifier::add(const LLEventStruct& event) +{ +    if (mNewEventSignal(event)) return false; +    LLEventNotification *new_enp = new LLEventNotification(event.eventId, event.eventEpoch, event.eventDateStr, event.eventName); + +    LL_INFOS() << "Add event " << event.eventName << " id " << event.eventId << " date " << event.eventDateStr << LL_ENDL; +    if(!new_enp->isValid()) +    { +        delete new_enp; +        return false; +    } + +    mEventNotifications[new_enp->getEventID()] = new_enp; +    return true; + +} +  void LLEventNotifier::add(U32 eventId)  { @@ -211,7 +228,21 @@ void LLEventNotifier::processEventInfoReply(LLMessageSystem *msg, void **)      msg->getString("EventData", "Date", eventd_date);      msg->getU32("EventData", "DateUTC", event_time_utc); -    gEventNotifier.add(event_id, (F64)event_time_utc, eventd_date, event_name); +    //gEventNotifier.add(event_id, (F64)event_time_utc, eventd_date, event_name); + +    LLEventStruct event(event_id, (F64)event_time_utc, eventd_date, event_name); +    msg->getString("EventData", "Creator", event.creator); +    msg->getString("EventData", "Category", event.category); +    msg->getString("EventData", "Desc", event.desc); +    msg->getU32("EventData", "Duration", event.duration); +    msg->getU32("EventData", "Cover", event.cover); +    msg->getU32("EventData", "Amount", event.amount); +    msg->getString("EventData", "SimName", event.simName); +    msg->getVector3d("EventData", "GlobalPos", event.globalPos); +    msg->getU32("EventData", "EventFlags", event.flags); + +    gEventNotifier.add(event); +  } @@ -249,16 +280,21 @@ void LLEventNotifier::load(const LLSD& event_options)              substitution["datetime"] = date;              LLStringUtil::format(dateStr, substitution); -            add(response["event_id"].asInteger(), response["event_date_ut"], dateStr, response["event_name"].asString()); +            //add(response["event_id"].asInteger(), response["event_date_ut"], dateStr, response["event_name"].asString()); +            LLEventStruct event(response["event_id"].asInteger(), response["event_date_ut"], dateStr, response["event_name"].asString()); +            add(event);          }          else          { -            add(response["event_id"].asInteger(), response["event_date_ut"], response["event_date"].asString(), response["event_name"].asString()); +            //add(response["event_id"].asInteger(), response["event_date_ut"], response["event_date"].asString(), response["event_name"].asString()); +            LLEventStruct event(response["event_id"].asInteger(), response["event_date_ut"], response["event_date"].asString(), response["event_name"].asString()); +            add(event);          }      }  } +  BOOL LLEventNotifier::hasNotification(const U32 event_id)  {      if (mEventNotifications.find(event_id) != mEventNotifications.end()) @@ -287,21 +323,21 @@ void LLEventNotifier::remove(const U32 event_id)  void LLEventNotifier::serverPushRequest(U32 event_id, bool add)  {      // Push up a message to tell the server we have this notification. -    gMessageSystem->newMessage(add?"EventNotificationAddRequest":"EventNotificationRemoveRequest"); +    gMessageSystem->newMessageFast(add ? _PREHASH_EventNotificationAddRequest : _PREHASH_EventNotificationRemoveRequest);      gMessageSystem->nextBlockFast(_PREHASH_AgentData);      gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );      gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -    gMessageSystem->nextBlock("EventData"); -    gMessageSystem->addU32("EventID", event_id); +    gMessageSystem->nextBlockFast(_PREHASH_EventData); +    gMessageSystem->addU32Fast(_PREHASH_EventID, event_id);      gAgent.sendReliableMessage();  } -LLEventNotification::LLEventNotification(U32 eventId, F64 eventEpoch, const std::string& eventDateStr, const std::string &eventName) : +LLEventNotification::LLEventNotification(U32 eventId, F64 eventEpoch, std::string eventDateStr, std::string eventName) :      mEventID(eventId), -    mEventName(eventName), +    mEventName(std::move(eventName)),      mEventDateEpoch(eventEpoch), -    mEventDateStr(eventDateStr) +    mEventDateStr(std::move(eventDateStr))  {  } diff --git a/indra/newview/lleventnotifier.h b/indra/newview/lleventnotifier.h index b928969d2f..d8ab2bafce 100644 --- a/indra/newview/lleventnotifier.h +++ b/indra/newview/lleventnotifier.h @@ -27,12 +27,31 @@  #ifndef LL_LLEVENTNOTIFIER_H  #define LL_LLEVENTNOTIFIER_H +#include <utility>  #include "llframetimer.h"  #include "v3dmath.h"  class LLEventNotification;  class LLMessageSystem; +typedef struct event_st{ +    U32 eventId = 0; +    F64 eventEpoch = 0.0; +    std::string eventDateStr; +    std::string eventName; +    std::string creator; +    std::string category; +    std::string desc; +    U32 duration = 0; +    U32 cover = 0; +    U32 amount = 0; +    std::string simName; +    LLVector3d globalPos; +    U32 flags = 0; +    event_st(U32 id, F64 epoch, std::string date_str, std::string name) +        : eventId(id), eventEpoch(epoch), eventDateStr(std::move(date_str)), eventName(std::move(name)){} +    event_st() = default; +} LLEventStruct;  class LLEventNotifier  { @@ -41,6 +60,7 @@ public:      virtual ~LLEventNotifier();      void update();  // Notify the user of the event if it's coming up +    bool add(const LLEventStruct& event);      bool add(U32 eventId, F64 eventEpoch, const std::string& eventDateStr, const std::string &eventName);      void add(U32 eventId); @@ -56,6 +76,13 @@ public:      static void processEventInfoReply(LLMessageSystem *msg, void **); +    typedef boost::signals2::signal<bool(LLEventStruct event)> new_event_signal_t; +    new_event_signal_t mNewEventSignal; +    boost::signals2::connection setNewEventCallback(const new_event_signal_t::slot_type& cb) +    { +        return mNewEventSignal.connect(cb); +    }; +  protected:      en_map  mEventNotifications;      LLFrameTimer    mNotificationTimer; @@ -65,7 +92,7 @@ protected:  class LLEventNotification  {  public: -    LLEventNotification(U32 eventId, F64 eventEpoch, const std::string& eventDateStr, const std::string &eventName); +    LLEventNotification(U32 eventId, F64 eventEpoch, std::string eventDateStr, std::string eventName);      U32                 getEventID() const              { return mEventID; } diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h index d1aa5f55e3..76e6eb6808 100644 --- a/indra/newview/llpanelprofileclassifieds.h +++ b/indra/newview/llpanelprofileclassifieds.h @@ -324,8 +324,11 @@ private:      S32 mPriceForListing; +public:      static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); +private: +      typedef std::list<LLPanelProfileClassified*> panel_list_t;      static panel_list_t sAllPanels; diff --git a/indra/newview/llsearchcombobox.h b/indra/newview/llsearchcombobox.h index ff9c74a6a8..891237e92e 100644 --- a/indra/newview/llsearchcombobox.h +++ b/indra/newview/llsearchcombobox.h @@ -61,6 +61,11 @@ public:      ~LLSearchComboBox(); +    /** +     * Sets focus to text box +     */ +    void focusTextEntry(); +  protected:      LLSearchComboBox(const Params&p); @@ -93,11 +98,6 @@ protected:       */      void onSelectionCommit(); -    /** -     * Sets focus to text box -     */ -    void focusTextEntry(); -      LLButton* mSearchButton;  }; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c5a22d08f3..96ff0fceb4 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -215,6 +215,9 @@  #include "lldxhardware.h"  #endif +#include "fsfloatersearch.h" + +  //  // exported globals  // @@ -2779,6 +2782,14 @@ void register_viewer_callbacks(LLMessageSystem* msg)      msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); +        // directory search +    msg->setHandlerFuncFast(_PREHASH_DirPeopleReply, FSPanelSearchPeople::processSearchReply); +    msg->setHandlerFuncFast(_PREHASH_DirPlacesReply, FSPanelSearchPlaces::processSearchReply); +    msg->setHandlerFuncFast(_PREHASH_DirGroupsReply, FSPanelSearchGroups::processSearchReply); +    msg->setHandlerFuncFast(_PREHASH_DirEventsReply, FSPanelSearchEvents::processSearchReply); +    msg->setHandlerFuncFast(_PREHASH_DirLandReply,   FSPanelSearchLand::processSearchReply); +    msg->setHandlerFuncFast(_PREHASH_DirClassifiedReply,  FSPanelSearchClassifieds::processSearchReply); +      msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);      msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);      msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 38fde25ebb..945d75351c 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -174,6 +174,8 @@  #include "llscriptfloater.h"  #include "llsyswellwindow.h" +#include "fsfloatersearch.h" +  // *NOTE: Please add files in alphabetical order to keep merges easy.  // handle secondlife:///app/openfloater/{NAME} URLs @@ -490,7 +492,8 @@ void LLViewerFloaterReg::registerFloaters()      LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterNotRunQueue>);      LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSnapshot>);      LLFloaterReg::add("simple_snapshot", "floater_simple_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSimpleSnapshot>); -    LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>); +    LLFloaterReg::add("search", "floater_fs_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterSearch>); +    //LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSearch>);      LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterProfile>);      LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHowTo>); diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 4d7d331433..c63f7338ed 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -48,6 +48,9 @@  #include "llinitparam.h"  #include "llselectmgr.h" +#include "llfloaterwebcontent.h" +#include "fsfloatersearch.h" +  //  // Constants  // @@ -648,6 +651,12 @@ bool start_chat( EKeystate s )  bool start_gesture( EKeystate s )  { +    LLFloater* focused_floater = gFloaterView->getFocusedFloater(); +    if (focused_floater && (dynamic_cast<LLFloaterWebContent*>(focused_floater) || dynamic_cast<FSFloaterSearch*>(focused_floater))) +    { +        return true; +    } +      LLUICtrl* focus_ctrlp = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());      if (KEYSTATE_UP == s &&          ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 2ca27e0e1a..88ff6a28b4 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -72,6 +72,7 @@  #include "llfloaterpay.h"  #include "llfloaterreporter.h"  #include "llfloatersearch.h" +#include "fsfloatersearch.h"  #include "llfloaterscriptdebug.h"  #include "llfloatersnapshot.h"  #include "llfloatertools.h" diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 16ddc2f89c..b8c9594aa7 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -629,6 +629,18 @@ bool LLGridManager::isInProductionGrid()      return mIsInProductionGrid;  } +bool LLGridManager::isInSecondlife() +{ +    //return (isInSLMain() || isInSLBeta()); +    return true; +} + +bool LLGridManager::isInOpenSim() +{ +    // FIX THIS TO SUPPORT OPENSIM +    return false; +} +  bool LLGridManager::isSystemGrid(const std::string& grid)  {      std::string grid_name = getGrid(grid); diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index 2ed663e038..7d9c70994c 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -174,6 +174,20 @@ class LLGridManager : public LLSingleton<LLGridManager>      //@} +    typedef enum e_grid_platform { +        NOPLATFORM = 0, +        SLMAIN, +        SLBETA, +        OPENSIM, +        HALCYON +    } EGridPlatform; + +    typedef enum e_add_grid { +        ADD_MANUAL = 0, +        ADD_HYPERGRID, +        ADD_LINK +    } EAddGridType; +      /* ================================================================       * @name Selecting the current grid       * @{ @@ -198,6 +212,11 @@ class LLGridManager : public LLSingleton<LLGridManager>      /// Is the selected grid one of the hard-coded default grids (Agni or Aditi)      bool isSystemGrid() { return isSystemGrid(mGrid); } +    /// Is the selected grid Second Life? +    bool isInSecondlife(); + +    bool isInOpenSim(); +      /// Is the selected grid a production grid?      bool isInProductionGrid();      /** diff --git a/indra/newview/skins/default/textures/icon_auction.tga b/indra/newview/skins/default/textures/icon_auction.tgaBinary files differ new file mode 100644 index 0000000000..baf7d0d000 --- /dev/null +++ b/indra/newview/skins/default/textures/icon_auction.tga diff --git a/indra/newview/skins/default/textures/icon_group.tga b/indra/newview/skins/default/textures/icon_group.tgaBinary files differ new file mode 100644 index 0000000000..79cd71689d --- /dev/null +++ b/indra/newview/skins/default/textures/icon_group.tga diff --git a/indra/newview/skins/default/textures/icon_legacy_event.tga b/indra/newview/skins/default/textures/icon_legacy_event.tgaBinary files differ new file mode 100644 index 0000000000..7805dbce60 --- /dev/null +++ b/indra/newview/skins/default/textures/icon_legacy_event.tga diff --git a/indra/newview/skins/default/textures/icon_legacy_event_adult.tga b/indra/newview/skins/default/textures/icon_legacy_event_adult.tgaBinary files differ new file mode 100644 index 0000000000..c344fb1e78 --- /dev/null +++ b/indra/newview/skins/default/textures/icon_legacy_event_adult.tga diff --git a/indra/newview/skins/default/textures/icon_legacy_event_mature.tga b/indra/newview/skins/default/textures/icon_legacy_event_mature.tgaBinary files differ new file mode 100644 index 0000000000..61c879bc92 --- /dev/null +++ b/indra/newview/skins/default/textures/icon_legacy_event_mature.tga diff --git a/indra/newview/skins/default/textures/icon_place.tga b/indra/newview/skins/default/textures/icon_place.tgaBinary files differ new file mode 100644 index 0000000000..e10655c6ec --- /dev/null +++ b/indra/newview/skins/default/textures/icon_place.tga diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_1.png b/indra/newview/skins/default/textures/icons/ProgressLarge_1.pngBinary files differ new file mode 100644 index 0000000000..ff277fc431 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_1.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_10.png b/indra/newview/skins/default/textures/icons/ProgressLarge_10.pngBinary files differ new file mode 100644 index 0000000000..1c94e21d89 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_10.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_11.png b/indra/newview/skins/default/textures/icons/ProgressLarge_11.pngBinary files differ new file mode 100644 index 0000000000..89bea9b474 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_11.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_12.png b/indra/newview/skins/default/textures/icons/ProgressLarge_12.pngBinary files differ new file mode 100644 index 0000000000..da38475ba4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_12.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_2.png b/indra/newview/skins/default/textures/icons/ProgressLarge_2.pngBinary files differ new file mode 100644 index 0000000000..c024275ebe --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_2.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_3.png b/indra/newview/skins/default/textures/icons/ProgressLarge_3.pngBinary files differ new file mode 100644 index 0000000000..87b931e72e --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_3.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_4.png b/indra/newview/skins/default/textures/icons/ProgressLarge_4.pngBinary files differ new file mode 100644 index 0000000000..6dbef74361 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_4.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_5.png b/indra/newview/skins/default/textures/icons/ProgressLarge_5.pngBinary files differ new file mode 100644 index 0000000000..daccf9b375 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_5.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_6.png b/indra/newview/skins/default/textures/icons/ProgressLarge_6.pngBinary files differ new file mode 100644 index 0000000000..cafddcb88d --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_6.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_7.png b/indra/newview/skins/default/textures/icons/ProgressLarge_7.pngBinary files differ new file mode 100644 index 0000000000..8acf6472d4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_7.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_8.png b/indra/newview/skins/default/textures/icons/ProgressLarge_8.pngBinary files differ new file mode 100644 index 0000000000..df0e825cef --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_8.png diff --git a/indra/newview/skins/default/textures/icons/ProgressLarge_9.png b/indra/newview/skins/default/textures/icons/ProgressLarge_9.pngBinary files differ new file mode 100644 index 0000000000..293a7b8f5c --- /dev/null +++ b/indra/newview/skins/default/textures/icons/ProgressLarge_9.png diff --git a/indra/newview/skins/default/textures/megapahit/icon_group.png b/indra/newview/skins/default/textures/megapahit/icon_group.pngBinary files differ new file mode 100644 index 0000000000..f3872dea3f --- /dev/null +++ b/indra/newview/skins/default/textures/megapahit/icon_group.png diff --git a/indra/newview/skins/default/textures/megapahit/icon_land_auction.png b/indra/newview/skins/default/textures/megapahit/icon_land_auction.pngBinary files differ new file mode 100644 index 0000000000..550703968f --- /dev/null +++ b/indra/newview/skins/default/textures/megapahit/icon_land_auction.png diff --git a/indra/newview/skins/default/textures/megapahit/icon_land_forsale.png b/indra/newview/skins/default/textures/megapahit/icon_land_forsale.pngBinary files differ new file mode 100644 index 0000000000..209bb868ea --- /dev/null +++ b/indra/newview/skins/default/textures/megapahit/icon_land_forsale.png diff --git a/indra/newview/skins/default/textures/megapahit/icon_place.png b/indra/newview/skins/default/textures/megapahit/icon_place.pngBinary files differ new file mode 100644 index 0000000000..60cf42424a --- /dev/null +++ b/indra/newview/skins/default/textures/megapahit/icon_place.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 968910d304..11eafcb45d 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -87,7 +87,7 @@ with the same filename but different name    <texture name="BreadCrumbBtn_Left_Off" file_name="widgets/BreadCrumbBtn_Left_Off.png" preload="false"/>    <texture name="BreadCrumbBtn_Left_Over" file_name="widgets/BreadCrumbBtn_Left_Over.png" preload="false"/>    <texture name="BreadCrumbBtn_Left_Press" file_name="widgets/BreadCrumbBtn_Left_Press.png" preload="false"/> -  +    <texture name="BreadCrumbBtn_Middle_Disabled" file_name="widgets/BreadCrumbBtn_Middle_Disabled.png" preload="false"/>    <texture name="BreadCrumbBtn_Middle_Off" file_name="widgets/BreadCrumbBtn_Middle_Off.png" preload="false"/>    <texture name="BreadCrumbBtn_Middle_Over" file_name="widgets/BreadCrumbBtn_Middle_Over.png" preload="false"/> @@ -192,7 +192,7 @@ with the same filename but different name    <texture name="Copy" file_name="icons/Copy.png" preload="false" />    <texture name="CopyBright" file_name="icons/CopyBright.png" preload="false" /> -   +    <texture name="DisclosureArrow_Opened_Off" file_name="widgets/DisclosureArrow_Opened_Off.png" preload="true" />    <texture name="ChatBarHandle" file_name="bottomtray/ChatBarHandle.png" preload="false" /> @@ -244,7 +244,7 @@ with the same filename but different name    <texture name="Group_Notices" file_name="icons/Group_Notices.png" preload="false" />    <texture name="Hand" file_name="icons/hand.png" preload="false" /> -   +    <texture name="Help_Press" file_name="navbar/Help_Press.png" preload="false" />    <texture name="Hierarchy_View_Disabled" file_name="icons/Hierarchy_View_Disabled.png" preload="false" /> @@ -257,16 +257,16 @@ with the same filename but different name    <texture name="Icon_Close_Foreground" file_name="windows/Icon_Close_Foreground.png" preload="true" />    <texture name="Icon_Close_Press" file_name="windows/Icon_Close_Press.png" preload="true" />    <texture name="Icon_Close_Toast" file_name="windows/Icon_Close_Toast.png" preload="true" /> -   +    <texture name="Icon_Copy" file_name="icons/copy_clipboard.png" preload="true" /> -   +    <texture name="Icon_Delete" file_name="icons/delete_icon.png" preload="true" />    <texture name="Icon_Dock_Foreground" file_name="windows/Icon_Dock_Foreground.png" preload="true" />    <texture name="Icon_Dock_Press" file_name="windows/Icon_Dock_Press.png" preload="true" />    <texture name="Icon_File_Upload" file_name="icons/file_upload.png" preload="true" /> -   +    <texture name="Icon_For_Sale" file_name="icons/Icon_For_Sale.png" preload="false" />    <texture name="Icon_Gear_Background" file_name="windows/Icon_Gear_Background.png" preload="false" /> @@ -279,14 +279,14 @@ with the same filename but different name    <texture name="Icon_Minimize_Foreground" file_name="windows/Icon_Minimize_Foreground.png" preload="true" />    <texture name="Icon_Minimize_Press" file_name="windows/Icon_Minimize_Press.png" preload="true" /> -   +    <texture name="Icon_Paste" file_name="icons/paste_clipboard.png" preload="true" />    <texture name="Icon_Restore_Foreground" file_name="windows/Icon_Restore_Foreground.png" preload="false" />    <texture name="Icon_Restore_Press" file_name="windows/Icon_Restore_Press.png" preload="false" />    <texture name="Icon_Snapshot" file_name="icons/snapshot_icon.png" preload="true" /> -   +    <texture name="Icon_Use_Texture" file_name="icons/texture_icon.png" preload="true" />    <texture name="Info" file_name="icons/Info.png" preload="false" /> @@ -320,7 +320,7 @@ with the same filename but different name    <texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.png" preload="false" />    <texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />    <texture name="Inv_Material" file_name="icons/Inv_Material.png" preload="false" /> -  <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />   +  <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />    <texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />    <texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />    <texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" /> @@ -375,7 +375,7 @@ with the same filename but different name    <texture name="Locked_Icon" file_name="icons/Locked_Icon.png" preload="false" />    <texture name="Map_Placeholder_Icon" file_name="icons/map_placeholder.png" preload="true" /> -     +    <texture name="Marketplace_Dropzone_Background" file_name="widgets/Marketplace_Dropzone_Background.png" preload="true" />    <texture name="MarketplaceBtn_Off" file_name="widgets/MarketplaceBtn_Off.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" />    <texture name="MarketplaceBtn_Selected" file_name="widgets/MarketplaceBtn_Selected.png" preload="true" scale.left="30" scale.top="19" scale.right="35" scale.bottom="4" /> @@ -391,7 +391,7 @@ with the same filename but different name    <texture name="ModelImport_Status_Good" file_name="green_checkmark.png" preload="false"/>    <texture name="ModelImport_Status_Warning" file_name="lag_status_warning.tga" preload="false"/>    <texture name="ModelImport_Status_Error" file_name="red_x.png" preload="false"/> -   +    <texture name="MouseLook_View_Off" file_name="bottomtray/Mouselook_View_Off.png" preload="false" />    <texture name="MouseLook_View_On" file_name="bottomtray/Mouselook_View_On.png" preload="false" /> @@ -547,7 +547,7 @@ with the same filename but different name    <texture name="Profile_Perm_Objects_Enabled" file_name="icons/Profile_Perm_Objects_Enabled.png" preload="true"/>    <texture name="Profile_Perm_Online_Disabled" file_name="icons/Profile_Perm_Online_Disabled.png" preload="true"/>    <texture name="Profile_Perm_Online_Enabled" file_name="icons/Profile_Perm_Online_Enabled.png" preload="true"/> -   +    <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />    <texture name="ProgressBarSolid" file_name="widgets/ProgressBarSolid.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />    <texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" /> @@ -740,7 +740,7 @@ with the same filename but different name    <texture name="UpArrow_Off" file_name="icons/UpArrow_Off.png" preload="false" />    <texture name="Video_URL_Off" file_name="icons/Video_URL_Off.png" preload="true" /> -   +    <texture name="Vertical Drag Handle" file_name="widgets/vertical_drag_handle.png" scale.left="2" scale.right="7" scale.bottom="8" scale.top="120"  scale_type="scale_outer"/>      <texture name="VirtualTrackball_Moon_Back" file_name="widgets/track_control_moon_back.png" /> @@ -756,7 +756,7 @@ with the same filename but different name    <texture name="VirtualTrackball_Sphere" file_name="widgets/track_control_sphere.png" />    <texture name="VirtualTrackball_Sun_Back" file_name="widgets/track_control_sun_back.png" />    <texture name="VirtualTrackball_Sun_Front" file_name="widgets/track_control_sun_front.png" /> -     +      <texture name="Volume_Background" file_name="windows/Volume_Background.png" preload="false"             scale.left="6" scale.top="33" scale.right="63" scale.bottom="10" /> @@ -765,7 +765,7 @@ with the same filename but different name    <texture name="VoicePTT_Lvl3" file_name="bottomtray/VoicePTT_Lvl3.png" preload="false" />    <texture name="VoicePTT_Off" file_name="bottomtray/VoicePTT_Off.png" preload="false" />    <texture name="VoicePTT_On" file_name="bottomtray/VoicePTT_On.png" preload="false" /> -   +    <texture name="Wearables_Divider" file_name="windows/Wearables_Divider.png" preload="false" />    <texture name="Add_Icon" file_name="icons/add_icon.png" preload="false" /> @@ -880,7 +880,7 @@ with the same filename but different name    <texture name="buy_off" file_name="widgets/buy_off.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>    <texture name="buy_over" file_name="widgets/buy_over.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/>    <texture name="buy_press" file_name="widgets/buy_press.png" preload="true" scale.left="2" scale.top="15" scale.right="67" scale.bottom="4"/> -   +    <texture name="hint_background" file_name="windows/hint_background.png" preload="false" scale.left="8" scale.top="70" scale.right="195" scale.bottom="11"/>    <texture name="hint_arrow_left" file_name="windows/hint_arrow_left.png" preload="false"/>    <texture name="hint_arrow_right" file_name="windows/hint_arrow_right.png" preload="false"/> @@ -907,4 +907,26 @@ with the same filename but different name    <texture name="Single_Folder_Up" file_name="icons/single_folder_up.png" preload="true"/>    <texture name="Icon_Color_Palette" file_name="icons/Icon_Color_Palette.png" preload="false"/>    <texture name="Icon_Font_Size" file_name="icons/Icon_Font_Size.png" preload="false"/> + +  <texture name="Icon_Place" file_name="megapahit/icon_place.png" preload="false" /> +  <texture name="Icon_Auction" file_name="megapahit/icon_land_auction.png" preload="false" /> +  <texture name="Icon_For_Sale" file_name="megapahit/icon_land_forsale.png" preload="false" /> +  <texture name="Icon_Group" file_name="megapahit/icon_group.png" preload="false" /> +  <texture name="Icon_Legacy_Event_PG" file_name="icons/Parcel_PG_Dark.png" preload="false" /> +  <texture name="Icon_Legacy_Event_Mature" file_name="icons/Parcel_M_Dark.png" preload="false" /> +  <texture name="Icon_Legacy_Event_Adult" file_name="icons/Parcel_R_Dark.png" preload="false" /> + +  <texture name="ProgressLarge_1" file_name="icons/ProgressLarge_1.png" preload="true" /> +  <texture name="ProgressLarge_2" file_name="icons/ProgressLarge_2.png" preload="true" /> +  <texture name="ProgressLarge_3" file_name="icons/ProgressLarge_3.png" preload="true" /> +  <texture name="ProgressLarge_4" file_name="icons/ProgressLarge_4.png" preload="true" /> +  <texture name="ProgressLarge_5" file_name="icons/ProgressLarge_5.png" preload="true" /> +  <texture name="ProgressLarge_6" file_name="icons/ProgressLarge_6.png" preload="true" /> +  <texture name="ProgressLarge_7" file_name="icons/ProgressLarge_7.png" preload="true" /> +  <texture name="ProgressLarge_8" file_name="icons/ProgressLarge_8.png" preload="true" /> +  <texture name="ProgressLarge_9" file_name="icons/ProgressLarge_9.png" preload="true" /> +  <texture name="ProgressLarge_10" file_name="icons/ProgressLarge_10.png" preload="true" /> +  <texture name="ProgressLarge_11" file_name="icons/ProgressLarge_11.png" preload="true" /> +  <texture name="ProgressLarge_12" file_name="icons/ProgressLarge_12.png" preload="true" /> +  </textures> diff --git a/indra/newview/skins/default/xui/en/floater_fs_search.xml b/indra/newview/skins/default/xui/en/floater_fs_search.xml new file mode 100644 index 0000000000..2372bc03ba --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_fs_search.xml @@ -0,0 +1,337 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater +	can_resize="true" +	default_tab_group="1" +	height="590" +	help_topic="search" +	layout="topleft" +	legacy_header_height="0" +	min_height="590" +	min_width="660" +	name="floater_search" +	positioning="centered" +	save_rect="true" +	single_instance="true" +	title="SEARCH" +	width="780"> +	<!-- Strings --> +	<floater.string name="string.location"> +		Location: [LOCATION] +	</floater.string> +	<floater.string name="string.traffic"> +		Traffic: [DWELL] +	</floater.string> +	<floater.string name="string.area"> +		Area: [AREA] +	</floater.string> +	<floater.string name="string.members"> +		Members: [MEMBER_COUNT] +	</floater.string> +	<floater.string name="string.founder"> +		Founder: [FOUNDER] +	</floater.string> +	<floater.string name="string.age"> +		Age: [AGE] +	</floater.string> +	<floater.string name="string.partner"> +		Partner: [PARTNER] +	</floater.string> +	<floater.string name="string.listing_price"> +		Listing Price: [LISTING_PRICE] +	</floater.string> +	<floater.string name="string.slurl"> +		[SLURL] +	</floater.string> +	<floater.string name="string.duration"> +		Duration: [DURATION] +	</floater.string> +	<floater.string name="string.covercharge"> +		Cover: [COVERCHARGE] +	</floater.string> +	<!-- Tab time --> +	<tab_container +		layout="topleft" +		follows="all" +		top="1" +		left="0" +		name="ls_tabs" +		tab_min_width="90" +		tab_position="top" +		width="780" +		height="585"> +		<panel +			class="panel_ls_web" +			filename="panel_fs_search_legacy_web.xml" +			label="Websearch" +			layout="topleft" +			name="panel_ls_web" /> +		<panel +			class="panel_ls_people" +			filename="panel_fs_search_legacy_people.xml" +			label="People" +			layout="topleft" +			name="panel_ls_people" /> +		<panel +			class="panel_ls_groups" +			filename="panel_fs_search_legacy_groups.xml" +			label="Groups" +			layout="topleft" +			name="panel_ls_groups" /> +		<panel +			class="panel_ls_places" +			filename="panel_fs_search_legacy_places.xml" +			label="Places" +			layout="topleft" +			name="panel_ls_places" /> +		<panel +			class="panel_ls_land" +			filename="panel_fs_search_legacy_land.xml" +			label="Land Sales" +			layout="topleft" +			name="panel_ls_land" /> +		<panel +			class="panel_ls_events" +			filename="panel_fs_search_legacy_events.xml" +			label="Events" +			layout="topleft" +			name="panel_ls_events" /> +		<panel +			class="panel_ls_classifieds" +			filename="panel_fs_search_legacy_classifieds.xml" +			label="Classifieds" +			layout="topleft" +			name="panel_ls_classifieds" /> +	</tab_container> +	<!-- Details/Action Panes --> +	<panel +		border="true" +		follows="top|right|bottom" +		height="508" +		layout="topleft" +		left="412" +		top="80" +		width="366" +		name="panel_ls_details"> +		<text_editor +		left="12" +		top="5" +		height="24" +		width="340" +		layout="topleft" +		follows="left|top|right" +		name="title" +		bg_visible="false" +		border_visible="false" +		allow_scroll="false" +		h_pad="0" +		v_pad="0" +		halign="center" +		enabled="false" +		use_ellipses="true" +		font="SansSerifHugeBold" +		value="Undefined name" /> +		<texture_picker +		enabled="false" +		fallback_image="Generic_Person_Large" +		follows="left|top|right" +		height="210" +		layout="topleft" +		left="78" +		name="snapshot" +		top_pad="4" +		width="210"/> +		<texture_picker +		enabled="false" +		fallback_image="default_land_picture.j2c" +		follows="left|top|right" +		height="210" +		layout="topleft" +		left_delta="0" +		name="snapshot_parcel" +		top_delta="0" +		visible="false" +		width="210"/> +		<text_editor +		left="20" +		top_pad="2" +		height="16" +		width="180" +		layout="topleft" +		follows="left|top|right" +		name="aux1" +		bg_visible="false" +		border_visible="false" +		h_pad="0" +		v_pad="0" +		word_wrap="true" +		enabled="false" +		max_length="117" +		allow_scroll="false" +		parse_urls="true" +		value="Auxilary info field 1"/> +		<text_editor +		left_pad="4" +		top_delta="0" +		height="16" +		width="140" +		layout="topleft" +		follows="left|top|right" +		name="aux2" +		bg_visible="false" +		border_visible="false" +		h_pad="0" +		v_pad="0" +		word_wrap="true" +		enabled="false" +		max_length="117" +		allow_scroll="false" +		parse_urls="true" +		value="Auxilary info field 2"/> +		<icon +		follows="top|right" +		height="16" +		image_name="Unknown_Icon" +		layout="topleft" +		left="20" +		top_pad="2" +		name="maturity_icon" +		width="18" /> +		<text_editor +		left_pad="4" +		top_delta="0" +		height="28" +		width="302" +		layout="topleft" +		follows="left|top|right" +		name="location" +		bg_visible="false" +		border_visible="false" +		h_pad="0" +		v_pad="0" +		word_wrap="true" +		enabled="false" +		max_length="117" +		allow_scroll="false" +		parse_urls="true" +		value="Location info field"/> +		<text_editor +		left="20" +		top_pad="12" +		height="154" +		width="324" +		layout="topleft" +		follows="left|top|right" +		name="desc" +		bg_visible="false" +		border_visible="false" +		h_pad="0" +		v_pad="0" +		word_wrap="true" +		parse_urls="true" +		enabled="false" +		max_length="1000" +		trusted_content="false" +		value="You unlock this door with the key of imagination. Beyond it is another dimension: a dimension of sound, a dimension of sight, a dimension of mind. You're moving into a land of both shadow and substance, of things and ideas; you've just crossed over into the Twilight Zone. What you are about to see is real; the litigants on the screen are not actors. They are genuine citizens who, having filed their claims in a real small claims court, have been persuaded to drop their suits there and have them settled here, in this forum... the People's Court."/> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Open Profile" +		name="people_profile_btn" +		top="484" +		left="3" +		width="120" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Send Message" +		name="people_message_btn" +		width="120" +		left_pad="1" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Add Friend" +		name="people_friend_btn" +		width="120" +		left_pad="1" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Open Profile" +		name="group_profile_btn" +		top="484" +		left="3" +		width="120" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Join Chat" +		name="group_message_btn" +		width="120" +		left_pad="1" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Join Group" +		name="group_join_btn" +		width="120" +		left_pad="1" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Teleport" +		name="teleport_btn" +		top="484" +		left="3" +		width="120" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Show on Map" +		name="map_btn" +		width="120" +		left_pad="1" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Remind me" +		name="event_reminder_btn" +		width="120" +		left_pad="1" /> +		<loading_indicator +		left="134" +		top="320" +		follows="left|top|right" +		mouse_opaque="false" +		name="loading" +		images_per_sec="1.0" +		tab_stop="false" +		height="100" +		width="100" +		visible="false" > +			<images> +				<image name="ProgressLarge_1"/> +				<image name="ProgressLarge_2"/> +				<image name="ProgressLarge_3"/> +				<image name="ProgressLarge_4"/> +				<image name="ProgressLarge_5"/> +				<image name="ProgressLarge_6"/> +				<image name="ProgressLarge_7"/> +				<image name="ProgressLarge_8"/> +				<image name="ProgressLarge_9"/> +				<image name="ProgressLarge_10"/> +				<image name="ProgressLarge_11"/> +				<image name="ProgressLarge_12"/> +			</images> +		</loading_indicator> +	</panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml index 2298005d73..3acae704c6 100644 --- a/indra/newview/skins/default/xui/en/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en/floater_world_map.xml @@ -86,7 +86,7 @@        height="22"        width="238"        follows="right|top" -      top="6"      +      top="6"        background_visible="false"        bg_alpha_color="DkGray2">      <text @@ -605,7 +605,7 @@        Location:        </text>        <spinner -        control_name="Teleport_Coordinate_X" +        control_name="teleport_coordinate_x"          decimal_digits="0"          follows="right|bottom"          height="23" @@ -617,11 +617,11 @@          min_val="0"          name="teleport_coordinate_x"          width="44" > -        <spinner.commit_callback  +        <spinner.commit_callback            function="WMap.Coordinates" />        </spinner>        <spinner -        control_name="Teleport_Coordinate_Y" +        control_name="teleport_coordinate_y"          decimal_digits="0"          follows="right|bottom"          height="23" @@ -637,7 +637,7 @@            function="WMap.Coordinates" />        </spinner>        <spinner -        control_name="Teleport_Coordinate_Z" +        control_name="teleport_coordinate_z"          decimal_digits="0"          follows="right|bottom"          height="23" diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_classifieds.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_classifieds.xml new file mode 100644 index 0000000000..66c35558b1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_classifieds.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="false" + follows="all" + height="566" + layout="topleft" + left="1" + width="780" + label="Classifieds" + name="panel_ls_classifieds"> +	<panel +	 border="false" +	 follows="top|left|right" +	 height="53" +	 layout="topleft" +	 left="0" +	 width="780" +	 name="panel_ls_input"> +		<text +		 type="string" +		 length="1" +		 follows="left|top" +		 top_pad="5" +		 layout="topleft" +		 left="6" +		 name="search_text" +		 top="12" +		 height="16" +		 width="156"> +		Enter search terms: +		</text> +		<search_combo_box +		 layout="topleft" +		 follows="left|top|right" +		 height="23" +		 left_delta="0" +		 name="classifieds_edit" +		 top="29" +		 width="651" /> +		<combo_box +		 follows="right|top" +		 layout="topleft" +		 height="23" +		 allow_text_entry="false" +		 top_delta="0" +		 left_pad="2" +		 name="classifieds_category" +		 width="122"> +			<combo_box.commit_callback +			 function="CommitSearch" /> +		</combo_box> +		<check_box +		 control_name="ShowPGClassifieds" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left="660" +		 name="pg_all" +		 top="12" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_PG_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_general" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowMatureClassifieds" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="mature_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_M_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_moderate" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowAdultClassifieds" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="adult_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_R_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_adult" +		 top_delta="-1" +		 width="18"/> +	</panel> +	<!-- Search Pane --> +	<panel +	 border="true" +	 follows="all" +	 height="510" +	 layout="topleft" +	 left="1" +	 width="410" +	 top_pad="1" +	 name="panel_ls_scrolllist"> +		<scroll_list +		 draw_heading="true" +		 follows="all" +		 height="485" +		 layout="topleft" +		 left="0" +		 name="search_results_classifieds" +		 top="0" +		 width="410"> +			<columns +			 label="" +			 name="icon" +			 width="20" /> +			<columns +			 label="Name" +			 name="classified_name" +			 relwidth="0.70" /> +			<columns +			 label="Listing Price" +			 name="price" +			 relwidth="0.3"/> +		</scroll_list> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Back" +	 	 name="classifieds_back" +		 top_pad="2" +		 left="3" +		 width="100" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Next" +		 name="classifieds_next" +		 width="100" +		 left_pad="1" /> +	</panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_events.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_events.xml new file mode 100644 index 0000000000..57cb4990e4 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_events.xml @@ -0,0 +1,258 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="false" + follows="all" + height="566" + layout="topleft" + left="1" + width="780" + label="Events" + name="panel_ls_events"> +	<panel +	 border="false" +	 follows="top|left|right" +	 height="53" +	 layout="topleft" +	 left="0" +	 width="780" +	 name="panel_ls_input"> +		<text +		 type="string" +		 length="1" +		 follows="left|top" +		 top_pad="5" +		 layout="topleft" +		 left="6" +		 name="search_text" +		 top="12" +		 height="16" +		 width="156"> +		 Enter search terms: +		</text> +		<radio_group +		 left_pad="20" +		 height="16" +		 width="300" +		 layout="topleft" +		 name="events_search_mode"> +			<radio_item +			 height="16" +			 label="Ongoing and Upcoming" +			 layout="topleft" +			 name="current" +			 value="current" +			 top_pad="0" +			 width="120" /> +			<radio_item +			 height="16" +			 label="By Date" +			 layout="topleft" +			 name="date" +			 value="date" +			 left_pad="70" +			 width="120" /> +			<radio_group.commit_callback +			 function="CommitSearch" /> +		</radio_group> +		<text +		 type="string" +		 length="1" +		 follows="left|top" +		 top_delta="0" +		 layout="topleft" +		 left_pad="5" +		 name="events_date" +		 font.style="BOLD" +		 height="16" +		 width="80"> +			4/20 +		</text> +		<search_combo_box +		 layout="topleft" +		 follows="left|top|right" +		 height="23" +		 left="6" +		 name="events_edit" +		 top="29" +		 width="651" /> +		<combo_box +		 follows="right|top" +		 layout="topleft" +		 height="23" +		 top_delta="0" +		 left_pad="2" +		 name="events_category" +		 width="122"> +			<combo_box.item label="Any Category" name="any" value="0" /> +			<combo_box.item label="" value="filter_separator" enabled="false" /> +			<combo_box.item label="Discussion" name="discussion" value="18" /> +			<combo_box.item label="Sports" name="sports" value="19" /> +			<combo_box.item label="Live DJ" name="dj" value="30" /> +			<combo_box.item label="Live Music" name="music" value="20" /> +			<!-- <combo_box.item label="???" name="mystery_category" value="21" /> --> +			<combo_box.item label="Commercial" name="commercial" value="22" /> +			<combo_box.item label="Nightlife/Entertainment" name="nightlife" value="23" /> +			<combo_box.item label="Games/Contests" name="games" value="24" /> +			<combo_box.item label="Pageants" name="pageants" value="25" /> +			<combo_box.item label="Education" name="education" value="26" /> +			<combo_box.item label="Arts and Culture" name="arts" value="27" /> +			<combo_box.item label="Charity/Support Groups" name="charity" value="28" /> +			<combo_box.item label="Miscellaneous" name="misc" value="29" /> +			<combo_box.commit_callback +			 function="CommitSearch" /> +		</combo_box> +		<check_box +		 control_name="ShowPGEvents" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left="660" +		 name="pg_all" +		 top="12" +		 width="15" > +		<check_box.commit_callback +		 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_PG_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_general" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowMatureEvents" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="mature_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_M_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_moderate" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowAdultEvents" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="adult_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_R_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_adult" +		 top_delta="-1" +		 width="18"/> +	</panel> +	<!-- Search Pane --> +	<panel +	 border="true" +	 follows="all" +	 height="510" +	 layout="topleft" +	 left="1" +	 width="410" +	 top_pad="1" +	 name="panel_ls_scrolllist"> +		<scroll_list +		 draw_heading="true" +		 follows="all" +		 height="485" +		 layout="topleft" +		 left="0" +		 name="search_results_events" +		 sort_ascending="true" +		 sort_column="3" +		 top="0" +		 width="410"> +			<columns +			 label="" +			 name="icon" +			 width="20" /> +			<columns +			 label="Event Name" +			 name="name" +			 relwidth="0.72" /> +			<columns +			 label="Date/Time" +			 name="date" +			 sort_column="time" +			 relwidth="0.28" /> +			<columns +			 label="Time" +			 name="time" +			 width="0"/> +		</scroll_list> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Yesterday" +		 name="events_yesterday" +		 top_pad="2" +		 left="3" +		 width="100" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Today" +		 name="events_today" +		 width="100" +		 left_pad="1" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Tomorrow" +		 name="events_tomorrow" +		 width="100" +		 left_pad="1" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 image_bottom_pad="2" +		 image_overlay="Arrow_Left_Off" +		 image_overlay_alignment="left" +		 label="Back" +		 name="events_back" +		 width="25" +		 left_pad="1" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 image_bottom_pad="2" +		 image_overlay="Arrow_Right_Off" +		 image_overlay_alignment="left" +		 label="Next" +		 name="events_next" +		 width="25" +		 left_pad="1" /> +	</panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_groups.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_groups.xml new file mode 100644 index 0000000000..90001952f7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_groups.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +	border="false" +	follows="all" +	height="566" +	layout="topleft" +	left="1" +	width="780" +	label="Groups" +	name="panel_ls_groups"> +	<panel +		border="false" +		follows="top|left|right" +		height="53" +		layout="topleft" +		left="0" +		width="780" +		name="panel_ls_input"> +		<text +			type="string" +			length="1" +			follows="left|top" +			top_pad="5" +			layout="topleft" +			left="6" +			name="search_text" +			top="12" +			height="16" +			width="156"> +			Enter search terms: +		</text> +		<search_combo_box +		layout="topleft" +		follows="left|top|right" +		height="23" +		left_delta="0" +		name="groups_edit" +		top="29" +		width="770"> +		</search_combo_box> +		<check_box +		control_name="ShowPGGroups" +		follows="right|top" +		height="16" +		label="" +		layout="topleft" +		left="660" +		name="pg_all" +		top="12" +		width="15" +		visible="false"/> +		<icon +		follows="right|top" +		height="16" +		image_name="Parcel_PG_Dark" +		layout="topleft" +		left_pad="2" +		name="rating_icon_general" +		top_delta="-1" +		width="18" +		visible="false"/> +		<check_box +		control_name="ShowMatureGroups" +		follows="right|top" +		height="16" +		label="" +		layout="topleft" +		left_pad="2" +		name="mature_all" +		top_delta="1" +		width="15" +		visible="false"/> +		<icon +		follows="right|top" +		height="16" +		image_name="Parcel_M_Dark" +		layout="topleft" +		left_pad="2" +		name="rating_icon_moderate" +		top_delta="-1" +		width="18" +		visible="false"/> +		<check_box +		control_name="ShowAdultGroups" +		follows="right|top" +		height="16" +		label="" +		layout="topleft" +		left_pad="2" +		name="adult_all" +		top_delta="1" +		width="15" +		visible="false"/> +		<icon +		follows="right|top" +		height="16" +		image_name="Parcel_R_Dark" +		layout="topleft" +		left_pad="2" +		name="rating_icon_adult" +		top_delta="-1" +		width="18" +		visible="false"/> +	</panel> +	<!-- Search Pane --> +	<panel +		border="true" +		follows="all" +		height="510" +		layout="topleft" +		left="1" +		width="410" +		top_pad="1" +		name="panel_ls_scrolllist"> +		<scroll_list +			draw_heading="true" +			follows="all" +			height="485" +			layout="topleft" +			left="0" +			name="search_results_groups" +			top="0" +			width="410"> +			<columns +			label="" +			name="icon" +			width="20" /> +			<columns +			label="Group Name" +			name="group_name" +			relwidth="0.72" /> +			<columns +			label="Members" +			name="members" +			relwidth="0.25" /> +			<columns +			label="Score" +			name="score" +			width="0" /> +		</scroll_list> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Back" +		name="groups_back" +		top_pad="2" +		left="3" +		width="100" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Next" +		name="groups_next" +		width="100" +		left_pad="1" /> +	</panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_land.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_land.xml new file mode 100644 index 0000000000..bb03a1e999 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_land.xml @@ -0,0 +1,281 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +	border="false" +	follows="all" +	height="566" +	layout="topleft" +	left="1" +	width="780" +	label="Land Sales" +	name="panel_ls_land"> +	<panel +		border="false" +		follows="top|left|right" +		height="53" +		layout="topleft" +		left="0" +		width="780" +		name="panel_ls_input"> +		<check_box +		 control_name="ShowPGLand" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left="660" +		 name="pg_all" +		 top="12" +		 width="15"> +            <check_box.commit_callback +             function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_PG_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_general" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowMatureLand" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="mature_all" +		 top_delta="1" +		 width="15"> +            <check_box.commit_callback +             function="CommitSearch" /> +        </check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_M_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_moderate" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowAdultLand" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="adult_all" +		 top_delta="1" +         width="15"> +            <check_box.commit_callback +             function="CommitSearch" /> +        </check_box> +		<icon +		follows="right|top" +		height="16" +		image_name="Parcel_R_Dark" +		layout="topleft" +		left_pad="2" +		name="rating_icon_adult" +		top_delta="-1" +		width="18"/> +		<text +			type="string" +			length="1" +			follows="left|top" +			layout="topleft" +			left="6" +			name="search_text" +			top="12" +			height="16" +			width="256"> +			Enter search terms: +		</text> +		<combo_box +			control_name="FindLandType" +			follows="left|top" +			layout="topleft" +			height="23" +			allow_text_entry="false" +			top_pad="2" +			left="6" +			name="land_category" +			width="122"> +                <combo_box.item label="All Categories" name="All" value="All"/> +                <combo_box.item label="Auction" name="Auction" value="Auction"/> +                <combo_box.item label="Mainland Sales" name="Mainland" value="Mainland"/> +                <combo_box.item label="Estate Sales" name="Estate" value="Estate"/> +                <combo_box.commit_callback +                 function="CommitSearch" /> +		</combo_box> +		<check_box +		 control_name="FindLandPrice" +		 follows="left|top" +		 height="16" +		 label="Price <" +		 layout="topleft" +		 left_pad="3" +		 name="price_check" +		 top_delta="3" +		 width="40" > +            <check_box.commit_callback +             function="CommitSearch" /> +        </check_box> +		<line_editor +		 enabled_control="FindLandPrice" +		 bevel_style="none" +		 border_style="line" +		 border.border_thickness="0" +		 commit_on_focus_lost="false" +		 follows="left|top" +		 height="18" +		 left_pad="20" +		 name="edit_price" +		 top_delta="-1" +		 width="40" > +            <line_editor.commit_callback +             function="CommitSearch" /> +        </line_editor> +		<check_box +		 control_name="FindLandArea" +		 follows="left|top" +		 height="16" +		 label="Area >" +		 layout="topleft" +		 left_pad="3" +		 name="area_check" +		 top_delta="1" +		 width="40" > +            <check_box.commit_callback +             function="CommitSearch" /> +        </check_box> +		<line_editor +		enabled_control="FindLandArea" +		bevel_style="none" +		border_style="line" +		border.border_thickness="0" +		commit_on_focus_lost="false" +		follows="left|top" +		height="18" +		left_pad="20" +		name="edit_area" +		top_delta="-1" +		width="40" > +            <line_editor.commit_callback +             function="CommitSearch" /> +        </line_editor> +		<text +         type="string" +         length="1" +         follows="left|top" +         layout="topleft" +         left="365" +         name="sort_text" +         top="12" +         height="16" +         width="98"> +         Sort results by: +		</text> +		<check_box +         follows="left|top" +         height="16" +         label="Ascending" +         layout="topleft" +         left_pad="3" +         name="ascending_check" +         width="100" > +            <check_box.commit_callback +             function="CommitSearch" /> +        </check_box> +		<combo_box +         follows="left|top" +         layout="topleft" +         height="23" +         allow_text_entry="false" +         left_delta="-102" +         top_pad="1" +         name="land_sort_combo" +         width="118"> +			<combo_box.item label="Name" name="Name_item" value="Name"/> +			<combo_box.item label="Price" name="Price_item" value="Price"/> +			<combo_box.item label="Price per meter" name="PPM_item" value="PPM"/> +			<combo_box.item label="Area" name="Area_item" value="Area"/> +            <combo_box.commit_callback +             function="CommitSearch" /> +		</combo_box> +		<button +		 follows="top|right" +		 height="23" +		 label="Search" +		 layout="topleft" +		 left="678" +		 top_delta="0" +		 name="land_find" +		 width="100" /> +	</panel> +	<!-- Search Pane --> +	<panel +     border="true" +     follows="all" +     height="510" +     layout="topleft" +     left="1" +     width="410" +     top_pad="1" +     name="panel_ls_scrolllist"> +		<scroll_list +         draw_heading="true" +         follows="all" +         height="485" +         layout="topleft" +         left="0" +         name="search_results_land" +         top="0" +         width="410"> +			<columns +			 label="" +			 name="icon" +			 width="20" /> +			 <columns +			 label="Name" +			 name="land_name" +			 relwidth="0.45" /> +			<columns +			 label="Price" +			 name="price" +			 relwidth="0.1" /> +            <columns +			 label="Area" +			 name="area" +			 relwidth="0.1" /> +            <columns +			 label="L$/m" +			 name="ppm" +			 relwidth="0.1" /> +			<columns +			 label="Type" +			 name="land_type" +			 relwidth="0.2" /> +		</scroll_list> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Back" +		 name="land_back" +		 top_pad="2" +		 left="3" +		 width="100" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Next" +		 name="land_next" +		 width="100" +		 left_pad="1" /> +	</panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_people.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_people.xml new file mode 100644 index 0000000000..28df02a7e3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_people.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +	border="false" +	follows="all" +	height="566" +	layout="topleft" +	left="1" +	width="780" +	label="People" +	name="panel_ls_people"> +	<panel +		border="false" +		follows="top|left|right" +		height="53" +		layout="topleft" +		left="0" +		width="780" +		name="panel_ls_input"> +		<text +			type="string" +			length="1" +			follows="left|top" +			top_pad="5" +			layout="topleft" +			left="6" +			name="search_text" +			top="12" +			height="16" +			width="156"> +			Enter search terms: +		</text> +		<search_combo_box +		layout="topleft" +		follows="left|top|right" +		height="23" +		left_delta="0" +		name="people_edit" +		top="29" +		width="770"> +		</search_combo_box> +	</panel> +	<!-- Search Pane --> +	<panel +		border="true" +		follows="all" +		height="510" +		layout="topleft" +		left="1" +		width="410" +		top_pad="1" +		name="panel_ls_scrolllist"> +		<scroll_list +			content_type="Agents" +			draw_heading="true" +			follows="all" +			height="485" +			layout="topleft" +			left="0" +			name="search_results_people" +			top="0" +			width="410"> +			<columns +			label="" +			name="icon" +			width="20" /> +			<columns +			label="Name" +			name="username" +			relwidth="1" /> +		</scroll_list> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Back" +		name="people_back" +		top_pad="2" +		left="3" +		width="100" /> +		<button +		layout="topleft" +		follows="left|bottom" +		height="23" +		label="Next" +		name="people_next" +		width="100" +		left_pad="1" /> +	</panel> +</panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_places.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_places.xml new file mode 100644 index 0000000000..09c142b8fc --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_places.xml @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + border="false" + follows="all" + height="566" + layout="topleft" + left="1" + width="780" + label="Places" + name="panel_ls_places"> +	<panel +	 border="false" +	 follows="top|left|right" +	 height="53" +	 layout="topleft" +	 left="0" +	 width="780" +	 name="panel_ls_input"> +		<text +		 type="string" +		 length="1" +		 follows="left|top" +		 top_pad="5" +		 layout="topleft" +		 left="6" +		 name="search_text" +		 top="12" +		 height="16" +		 width="156"> +		Enter search terms: +		</text> +		<search_combo_box +		 layout="topleft" +		 follows="left|top|right" +		 height="23" +		 left_delta="0" +		 name="places_edit" +		 top="29" +		 width="651" /> +		<combo_box +		 follows="right|top" +		 layout="topleft" +		 height="23" +		 allow_text_entry="false" +		 top_delta="0" +		 left_pad="2" +		 name="places_category" +		 width="122"> +			<combo_box.commit_callback +			 function="CommitSearch" /> +		</combo_box> +		<check_box + 		 control_name="ShowPGSims" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left="660" +		 name="pg_all" +		 top="12" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_PG_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_general" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowMatureSims" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="mature_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_M_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_moderate" +		 top_delta="-1" +		 width="18"/> +		<check_box +		 control_name="ShowAdultSims" +		 follows="right|top" +		 height="16" +		 label="" +		 layout="topleft" +		 left_pad="2" +		 name="adult_all" +		 top_delta="1" +		 width="15"> +			<check_box.commit_callback +			 function="CommitSearch" /> +		</check_box> +		<icon +		 follows="right|top" +		 height="16" +		 image_name="Parcel_R_Dark" +		 layout="topleft" +		 left_pad="2" +		 name="rating_icon_adult" +		 top_delta="-1" +		 width="18"/> +	</panel> +	<!-- Search Pane --> +	<panel +	 border="true" +	 follows="all" +	 height="510" +	 layout="topleft" +	 left="1" +	 width="410" +	 top_pad="1" +	 name="panel_ls_scrolllist"> +		<scroll_list +		 draw_heading="true" +		 follows="all" +		 height="485" +		 layout="topleft" +		 left="0" +		 name="search_results_places" +		 top="0" +		 width="410"> +			<columns +			 label="" +			 name="icon" +			 width="20" /> +			<columns +			 label="Name" +			 name="place_name" +			 relwidth="0.81" /> +			<columns +			 label="Traffic" +			 name="dwell" +			 relwidth="0.16" /> +		</scroll_list> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Back" +		 name="places_back" +		 top_pad="2" +		 left="3" +		 width="100" /> +		<button +		 layout="topleft" +		 follows="left|bottom" +		 height="23" +		 label="Next" +		 name="places_next" +		 width="100" +		 left_pad="1" /> +	</panel> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_fs_search_legacy_web.xml b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_web.xml new file mode 100644 index 0000000000..382a5e8945 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_fs_search_legacy_web.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +border="false" +follows="all" +height="566" +layout="topleft" +left="1" +width="780" +label="Websearch" +name="panel_ls_web"> +	<web_browser +	 top="5" +	 bottom="-1" +	 left="5" +	 right="-5" +	 layout="topleft" +	 follows="all" +	 name="search_browser" +	 trusted_content="true" +	 start_url="about:blank" /> +</panel>
\ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 1bc8ddc626..daa49eaa2c 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -71,7 +71,7 @@ Voice Server Version: [VOICE_VERSION]    <string name="LocalTime">[month, datetime, local] [day, datetime, local] [year, datetime, local] [hour, datetime, local]:[min, datetime, local]:[second,datetime, local]</string>  	<string name="ErrorFetchingServerReleaseNotesURL">Error fetching server release notes URL.</string>  	<string name="BuildConfiguration">Build Configuration</string> -	 +  	<!--  progress -->  	<string name="ProgressRestoring">Restoring...</string>  	<string name="ProgressChangingResolution">Changing resolution...</string> @@ -114,10 +114,10 @@ Voice Server Version: [VOICE_VERSION]  	<string name="LoginFailedHeader">Login failed.</string>  	<string name="Quit">Quit</string>  	<string name="create_account_url">http://join.secondlife.com/?sourceid=[sourceid]</string> -	 +  	<string name="AgniGridLabel">Second Life Main Grid (Agni)</string>  	<string name="AditiGridLabel">Second Life Beta Test Grid (Aditi)</string> -	 +  	<string name="ViewerDownloadURL">http://secondlife.com/download</string>  	<string name="LoginFailedViewerNotPermitted">  The viewer you are using can no longer access Second Life. Please visit the following page to download a new viewer: @@ -209,7 +209,7 @@ If you feel this is an error, please contact support@secondlife.com</string>  	<string name="YouHaveBeenDisconnected">You have been disconnected from the region you were in.</string>  	<string name="SentToInvalidRegion">You were sent to an invalid region.</string>  	<string name="TestingDisconnect">Testing viewer disconnect</string> -   +  	<!-- SLShare: User Friendly Filter Names Translation -->      <string name="BlackAndWhite">Black & White</string>      <string name="Colors1970">1970's Colors</string> @@ -222,7 +222,7 @@ If you feel this is an error, please contact support@secondlife.com</string>      <string name="LensFlare">Lens Flare</string>      <string name="Miniature">Miniature</string>      <string name="Toycamera">Toy Camera</string> -	 +      <!-- Tooltip -->  	<string name="TooltipPerson">Person</string><!-- Object under mouse pointer is an avatar -->  	<string name="TooltipNoName">(no name)</string> <!-- No name on an object --> @@ -259,10 +259,10 @@ If you feel this is an error, please contact support@secondlife.com</string>  	<string name="TooltipOutboxMixedStock">All items in a stock folder must have the same type and permission</string>  	<string name="TooltipOutfitNotInInventory">You can only put items or outfits from your personal inventory into "My outfits"</string>  	<string name="TooltipCantCreateOutfit">One or more items can't be used inside "My outfits"</string> -	 +  	<string name="TooltipDragOntoOwnChild">You can't move a folder into its child</string>  	<string name="TooltipDragOntoSelf">You can't move a folder into itself</string> -	 +  	<!-- tooltips for Urls -->  	<string name="TooltipHttpUrl">Click to view this web page</string>  	<string name="TooltipSLURL">Click to view this location's information</string> @@ -370,7 +370,7 @@ are allowed.  	<string name="AssetUploadServerDifficulties">The server is experiencing unexpected difficulties.</string>  	<string name="AssetUploadServerUnavaliable">Service not available or upload timeout was reached.</string>  	<string name="AssetUploadRequestInvalid"> -Error in upload request.  Please visit  +Error in upload request.  Please visit  http://secondlife.com/support for help fixing this problem.  </string> @@ -534,7 +534,7 @@ http://secondlife.com/support for help fixing this problem.  	<string name="ChangeYourDefaultAnimations">Change your default animations</string>  	<string name="ForceSitAvatar">Force your avatar to sit</string>  	<string name="ChangeEnvSettings">Change your environment settings</string> -	 +  	<string name="NotConnected">Not Connected</string>  	<string name="AgentNameSubst">(You)</string> <!-- Substitution for agent name -->  	<string name="JoinAnExperience"/><!-- intentionally blank --> @@ -2320,7 +2320,7 @@ For AI Character: Get the closest navigable point to the point provided.  	<!-- inventory -->  	<string name="InventoryNoMatchingItems">Didn't find what you're looking for? Try [secondlife:///app/search/all/[SEARCH_TERM] Search].</string> -	<string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string>	 +	<string name="InventoryNoMatchingRecentItems">Didn't find what you're looking for? Try [secondlife:///app/inventory/filters Show filters].</string>  	<string name="PlacesNoMatchingItems">To add a place to your landmarks, click the star to the right of the location name.</string>  	<string name="FavoritesNoMatchingItems">To add a place to your favorites, click the star to the right of the location name, then save the landmark to "Favorites bar".</string>  	<string name="MarketplaceNoListing">You have no listings yet.</string> @@ -2503,7 +2503,7 @@ If you continue to receive this message, please contact Second Life support for    <string name="InvFolder Materials">Materials</string>    <!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694--> -	<string name="InvFolder Friends">Friends</string>	 +	<string name="InvFolder Friends">Friends</string>  	<string name="InvFolder All">All</string>  	<string name="no_attachments">No attachments worn</string> @@ -2672,7 +2672,7 @@ If you continue to receive this message, please contact Second Life support for  	<string name="UploadFailed">File upload failed: </string>  	<string name="ObjectOutOfRange">Script (object out of range)</string>  	<string name="ScriptWasDeleted">Script (deleted from inventory)</string> -	 +  	<!-- god tools -->  	<string name="GodToolsObjectOwnedBy">Object [OBJECT] owned by [OWNER]</string> @@ -2942,12 +2942,14 @@ Expected .wav, .tga, .bmp, .jpg, .jpeg, or .anim  	<string name="Linden Location">Linden Location</string>  	<string name="Adult">Adult</string>  	<string name="Arts&Culture">Arts & Culture</string> +	<string name="Arts and Culture">Arts & Culture</string>  	<string name="Business">Business</string>  	<string name="Educational">Educational</string>  	<string name="Gaming">Gaming</string>  	<string name="Hangout">Hangout</string>  	<string name="Newcomer Friendly">Newcomer Friendly</string>  	<string name="Parks&Nature">Parks & Nature</string> +	<string name="Parks and Nature">Parks & Nature</string>  	<string name="Residential">Residential</string>  	<!--<string name="Shopping">Shopping</string>	-->  	<string name="Stage">Stage</string> @@ -3848,7 +3850,7 @@ Please reinstall viewer from  https://secondlife.com/support/downloads/ and cont    <string name="uploading_costs">Uploading costs L$ [AMOUNT]</string>    <string name="this_costs">This costs L$ [AMOUNT]</string> -   +    <string name="buying_selected_land">This land costs</string>    <string name="this_object_costs">This item costs</string>    <string name="giving">You want to give</string> @@ -3929,7 +3931,7 @@ Abuse Report</string>    <string name="New Daycycle">New Daycycle</string>    <string name="New Water">New Water</string>    <string name="New Sky">New Sky</string> -   +    <string name="/bow">/bow</string>    <string name="/clap">/clap</string> @@ -4011,7 +4013,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem    <string name="Accounting">Accounting</string>    <string name="Notices">Notices</string>    <string name="Chat">Chat</string> -   +    <!-- SL Membership -->    <string name="BaseMembership">Base</string>    <string name="PremiumMembership">Premium</string> @@ -4177,7 +4179,7 @@ Try enclosing path to the editor with double quotes.    <!-- commands --> -  <string  +  <string  name="Command_360_Capture_Label">360 snapshot</string>    <string name="Command_AboutLand_Label">About land</string>    <string name="Command_Appearance_Label">Outfits</string> @@ -4210,7 +4212,7 @@ name="Command_360_Capture_Label">360 snapshot</string>    <string name="Command_View_Label">Camera controls</string>    <string name="Command_Voice_Label">Voice settings</string> -  <string  +  <string  name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>    <string name="Command_AboutLand_Tooltip">Information about the land you're visiting</string>    <string name="Command_Appearance_Tooltip">Change your avatar</string> @@ -4275,7 +4277,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>    <!-- Spell check settings floater -->    <string name="UserDictionary">[User]</string> -   +    <!-- Experience Tools strings -->    <string name="experience_tools_experience">Experience</string>    <string name="ExperienceNameNull">(no experience)</string> @@ -4311,7 +4313,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>    <!-- PBR Materials -->    <string name="Material Texture Name Header">Textures present this material: </string> -   +    <!-- Conversation log messages -->    <string name="logging_calls_disabled_log_empty">      Conversations are not being logged. To begin keeping a log, choose "Save: Log only" or "Save: Log and transcripts" under Preferences > Chat. @@ -4334,7 +4336,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string>    <string name="Default">Default</string>    <string name="none_paren_cap">(None)</string>    <string name="no_limit">No limit</string> -   +    <string name="Mav_Details_MAV_FOUND_DEGENERATE_TRIANGLES">        The physics shape contains triangles which are too small. Try simplifying the physics model.    </string> @@ -4374,4 +4376,20 @@ and report the problem.  [https://community.secondlife.com/knowledgebase/english/error-messages-r520/#Section__3 Knowledge Base]    </string> +  <!-- megapahit strings --> +  <string name="not_found">'[TEXT]' not found</string> +  <string name="no_results">No results</string> +  <string name="searching">Searching...</string> +  <string name="all_categories">All Categories</string> +  <string name="search_banned">Some terms in your search query were excluded due to content restrictions as clarified in the Community Standards.</string> +  <string name="search_short">Your search terms were too short so no search was performed.</string> +  <string name="search_disabled">Legacy Search has been disabled in this region.</string> +  <string name="NotifyIncomingMessage">Incoming message from [NAME]...</string> +  <string name="NearbyChatTitleChannel">Nearby chat (on channel [CHANNEL])</string> +  <string name="AvatarTyping">Typing</string> +  <string name="UnknownAvatar">Unknown Avatar</string> +  <string name="NotAvailableOnPlatform">Not available on this platform</string> +  <string name="NowPlaying">Now Playing</string> +  <string name="GridInfoTitle">GRID INFO</string> +  </strings> | 
