# Conflicts:
#	indra/newview/llfloatersearch.cpp
#	indra/newview/llstatusbar.cpp
#	indra/newview/lltextureview.cpp
#	indra/newview/llviewerwindow.cpp
#	indra/newview/skins/default/xui/en/floater_search.xml
master
Ansariel 2025-08-25 11:26:30 +02:00
commit 950fa11bcb
31 changed files with 393 additions and 415 deletions

View File

@ -50,7 +50,7 @@ static const U32 DEFAULT_POOL_SIZE = 5;
// SL-14399: When we teleport to a brand-new simulator, the coprocedure queue // SL-14399: When we teleport to a brand-new simulator, the coprocedure queue
// gets absolutely slammed with fetch requests. Make this queue effectively // gets absolutely slammed with fetch requests. Make this queue effectively
// unlimited. // unlimited.
const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*1024; const U32 LLCoprocedureManager::DEFAULT_QUEUE_SIZE = 1024*512;
//========================================================================= //=========================================================================
class LLCoprocedurePool: private boost::noncopyable class LLCoprocedurePool: private boost::noncopyable
@ -58,7 +58,7 @@ class LLCoprocedurePool: private boost::noncopyable
public: public:
typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t; typedef LLCoprocedureManager::CoProcedure_t CoProcedure_t;
LLCoprocedurePool(const std::string &name, size_t size); LLCoprocedurePool(const std::string &name, size_t size, size_t queue_size);
~LLCoprocedurePool(); ~LLCoprocedurePool();
/// Places the coprocedure on the queue for processing. /// Places the coprocedure on the queue for processing.
@ -118,7 +118,7 @@ private:
typedef std::shared_ptr<CoprocQueue_t> CoprocQueuePtr; typedef std::shared_ptr<CoprocQueue_t> CoprocQueuePtr;
std::string mPoolName; std::string mPoolName;
size_t mPoolSize, mActiveCoprocsCount, mPending; size_t mPoolSize, mQueueSize, mActiveCoprocsCount, mPending;
CoprocQueuePtr mPendingCoprocs; CoprocQueuePtr mPendingCoprocs;
LLTempBoundListener mStatusListener; LLTempBoundListener mStatusListener;
@ -141,7 +141,7 @@ LLCoprocedureManager::~LLCoprocedureManager()
close(); close();
} }
void LLCoprocedureManager::initializePool(const std::string &poolName) void LLCoprocedureManager::initializePool(const std::string &poolName, size_t queue_size)
{ {
poolMap_t::iterator it = mPoolMap.find(poolName); poolMap_t::iterator it = mPoolMap.find(poolName);
@ -180,7 +180,7 @@ void LLCoprocedureManager::initializePool(const std::string &poolName)
LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL; LL_WARNS("CoProcMgr") << "LLCoprocedureManager: No setting for \"" << keyName << "\" setting pool size to default of " << size << LL_ENDL;
} }
poolPtr_t pool(new LLCoprocedurePool(poolName, size)); poolPtr_t pool(new LLCoprocedurePool(poolName, size, queue_size));
LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL; LL_ERRS_IF(!pool, "CoprocedureManager") << "Unable to create pool named \"" << poolName << "\" FATAL!" << LL_ENDL;
bool inserted = mPoolMap.emplace(poolName, pool).second; bool inserted = mPoolMap.emplace(poolName, pool).second;
@ -212,7 +212,8 @@ void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpd
mPropertyQueryFn = queryfn; mPropertyQueryFn = queryfn;
mPropertyDefineFn = updatefn; mPropertyDefineFn = updatefn;
initializePool("Upload"); constexpr size_t UPLOAD_QUEUE_SIZE = 2048;
initializePool("Upload", UPLOAD_QUEUE_SIZE);
initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS
// "ExpCache" pool gets initialized in LLExperienceCache // "ExpCache" pool gets initialized in LLExperienceCache
// asset storage pool gets initialized in LLViewerAssetStorage // asset storage pool gets initialized in LLViewerAssetStorage
@ -296,17 +297,19 @@ void LLCoprocedureManager::close(const std::string &pool)
} }
//========================================================================= //=========================================================================
LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size, size_t queue_size):
mPoolName(poolName), mPoolName(poolName),
mPoolSize(size), mPoolSize(size),
mQueueSize(queue_size),
mActiveCoprocsCount(0), mActiveCoprocsCount(0),
mPending(0), mPending(0),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping() mCoroMapping()
{ {
llassert_always(mQueueSize > mPoolSize); // queue should be able to fit pool
try try
{ {
mPendingCoprocs = std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE); mPendingCoprocs = std::make_shared<CoprocQueue_t>(mQueueSize);
// store in our LLTempBoundListener so that when the LLCoprocedurePool is // store in our LLTempBoundListener so that when the LLCoprocedurePool is
// destroyed, we implicitly disconnect from this LLEventPump // destroyed, we implicitly disconnect from this LLEventPump
// Monitores application status // Monitores application status
@ -357,7 +360,7 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter)); mCoroMapping.insert(CoroAdapterMap_t::value_type(pooledCoro, httpAdapter));
} }
LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << LLCoprocedureManager::DEFAULT_QUEUE_SIZE << LL_ENDL; LL_INFOS("CoProcMgr") << "Created coprocedure pool named \"" << mPoolName << "\" with " << size << " items, queue max " << mQueueSize << LL_ENDL;
} }
LLCoprocedurePool::~LLCoprocedurePool() LLCoprocedurePool::~LLCoprocedurePool()
@ -376,7 +379,7 @@ LLUUID LLCoprocedurePool::enqueueCoprocedure(const std::string &name, LLCoproced
<< "\" at " << "\" at "
<< mPending << LL_ENDL; << mPending << LL_ENDL;
if (mPending >= (LLCoprocedureManager::DEFAULT_QUEUE_SIZE - 1)) if (mPending >= (mQueueSize - 1))
{ {
// If it's all used up (not supposed to happen, // If it's all used up (not supposed to happen,
// fetched should cap it), we are going to crash // fetched should cap it), we are going to crash

View File

@ -79,7 +79,7 @@ public:
void close(); void close();
void close(const std::string &pool); void close(const std::string &pool);
void initializePool(const std::string &poolName); void initializePool(const std::string &poolName, size_t queue_size = DEFAULT_QUEUE_SIZE);
private: private:

View File

@ -116,7 +116,8 @@ void LLExperienceCache::initSingleton()
cache_stream >> (*this); cache_stream >> (*this);
} }
LLCoprocedureManager::instance().initializePool("ExpCache"); constexpr size_t CORO_QUEUE_SIZE = 2048;
LLCoprocedureManager::instance().initializePool("ExpCache", CORO_QUEUE_SIZE);
LLCoros::instance().launch("LLExperienceCache::idleCoro", LLCoros::instance().launch("LLExperienceCache::idleCoro",
boost::bind(&LLExperienceCache::idleCoro, this)); boost::bind(&LLExperienceCache::idleCoro, this));

View File

@ -521,6 +521,7 @@ set(viewer_SOURCE_FILES
llmaniprotate.cpp llmaniprotate.cpp
llmanipscale.cpp llmanipscale.cpp
llmaniptranslate.cpp llmaniptranslate.cpp
llfloatermarketplace.cpp
llmarketplacefunctions.cpp llmarketplacefunctions.cpp
llmarketplacenotifications.cpp llmarketplacenotifications.cpp
llmaterialeditor.cpp llmaterialeditor.cpp
@ -1223,6 +1224,7 @@ set(viewer_HEADER_FILES
llfloaterlinkreplace.h llfloaterlinkreplace.h
llfloaterloadprefpreset.h llfloaterloadprefpreset.h
llfloatermap.h llfloatermap.h
llfloatermarketplace.h
llfloatermarketplacelistings.h llfloatermarketplacelistings.h
llfloatermediasettings.h llfloatermediasettings.h
llfloatermemleak.h llfloatermemleak.h

View File

@ -2962,7 +2962,7 @@ FSPanelSearchWeb::FSPanelSearchWeb() : FSSearchPanelBase()
bool FSPanelSearchWeb::postBuild() bool FSPanelSearchWeb::postBuild()
{ {
mWebBrowser = getChild<LLMediaCtrl>("search_browser"); mWebBrowser = getChild<LLMediaCtrl>("search_contents");
return true; return true;
} }

View File

@ -5404,6 +5404,7 @@ void LLAppViewer::forceDisconnect(const std::string& mesg)
} }
else else
{ {
sendSimpleLogoutRequest();
args["MESSAGE"] = big_reason; args["MESSAGE"] = big_reason;
LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect ); LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect );
} }
@ -6223,6 +6224,27 @@ void LLAppViewer::sendLogoutRequest()
} }
} }
void LLAppViewer::sendSimpleLogoutRequest()
{
if (!mLogoutRequestSent && gMessageSystem)
{
gLogoutInProgress = true;
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_LogoutRequest);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
gAgent.sendReliableMessage();
LL_INFOS("Agent") << "Logging out as agent: " << gAgent.getID() << " Session: " << gAgent.getSessionID() << LL_ENDL;
gLogoutTimer.reset();
gLogoutMaxTime = LOGOUT_REQUEST_TIME;
mLogoutRequestSent = true;
}
}
void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp)
{ {
if (!regionp || !regionp->capabilitiesReceived()) if (!regionp || !regionp->capabilitiesReceived())

View File

@ -313,6 +313,10 @@ private:
void sendLogoutRequest(); void sendLogoutRequest();
void disconnectViewer(); void disconnectViewer();
// Does not create a marker file. For lost network case,
// to at least attempt to remove the ghost from the world.
void sendSimpleLogoutRequest();
// *FIX: the app viewer class should be some sort of singleton, no? // *FIX: the app viewer class should be some sort of singleton, no?
// Perhaps its child class is the singleton and this should be an abstract base. // Perhaps its child class is the singleton and this should be an abstract base.
static LLAppViewer* sInstance; static LLAppViewer* sInstance;

View File

@ -0,0 +1,47 @@
/**
* @file llfloatermarketplace.cpp
* @brief floater for the Marketplace web site
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llfloatermarketplace.h"
#include "lluictrlfactory.h"
LLFloaterMarketplace::LLFloaterMarketplace(const LLSD& key)
: LLFloater(key)
{
}
LLFloaterMarketplace::~LLFloaterMarketplace()
{
}
bool LLFloaterMarketplace::postBuild()
{
enableResizeCtrls(true, true, false);
return true;
}

View File

@ -0,0 +1,40 @@
/**
* @file llfloatermarketplace.h
* @brief floater for the Marketplace web site
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#pragma once
#include "llfloater.h"
class LLFloaterMarketplace:
public LLFloater
{
friend class LLFloaterReg;
private:
LLFloaterMarketplace(const LLSD& key);
~LLFloaterMarketplace();
bool postBuild() override;
};

View File

@ -1,11 +1,10 @@
/** /**
* @file llfloatersearch.cpp * @file llfloatersearch.cpp
* @author Martin Reddy * @brief Floater for Search (update 2025, preload)
* @brief Search floater - uses an embedded web browser control
* *
* $LicenseInfo:firstyear=2009&license=viewerlgpl$ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code * Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc. * Copyright (C) 2011, Linden Research, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -27,16 +26,13 @@
#include "llviewerprecompiledheaders.h" #include "llviewerprecompiledheaders.h"
#include "llfloatersearch.h"
#include "llagent.h"
#include "llcommandhandler.h" #include "llcommandhandler.h"
#include "llfloaterreg.h" #include "llfloaterreg.h"
#include "llfloatersearch.h"
#include "llhttpconstants.h"
#include "llmediactrl.h" #include "llmediactrl.h"
#include "llnotificationsutil.h" #include "lluictrlfactory.h"
#include "lllogininstance.h"
#include "lluri.h"
#include "llagent.h"
#include "llui.h"
#include "llviewercontrol.h" #include "llviewercontrol.h"
#include "llweb.h" #include "llweb.h"
@ -44,54 +40,23 @@
#include "lfsimfeaturehandler.h" // <FS:CR> Opensim search support #include "lfsimfeaturehandler.h" // <FS:CR> Opensim search support
// support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps // support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps
class LLSearchHandler : public LLCommandHandler class LLSearchHandler : public LLCommandHandler {
{ public:
public: // requires trusted browser to trigger
// requires trusted browser to trigger LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }
LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { } bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) {
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web) const size_t parts = tokens.size();
{
const size_t parts = tokens.size();
// get the (optional) category for the search // open the search floater and perform the requested search
std::string collection; LLFloaterReg::showInstance("search", tokens);
if (parts > 0) return true;
{
collection = tokens[0].asString();
} }
// get the (optional) search string
std::string search_text;
if (parts > 1)
{
search_text = tokens[1].asString();
}
// create the LLSD arguments for the search floater
LLFloaterSearch::Params p;
p.search.collection = collection;
p.search.query = LLURI::unescape(search_text);
// open the search floater and perform the requested search
LLFloaterReg::showInstance("search", p);
return true;
}
}; };
LLSearchHandler gSearchHandler; LLSearchHandler gSearchHandler;
LLFloaterSearch::SearchQuery::SearchQuery() LLFloaterSearch::LLFloaterSearch(const LLSD& key)
: category("category", ""), : LLFloater(key)
collection("collection", ""),
query("query")
{}
LLFloaterSearch::LLFloaterSearch(const Params& key) :
LLFloaterWebContent(key),
mSearchGodLevel(0)
{ {
// declare a map that transforms a category name into
// the URL suffix that is used to search that category
mSearchType.insert("standard"); mSearchType.insert("standard");
mSearchType.insert("land"); mSearchType.insert("land");
mSearchType.insert("classified"); mSearchType.insert("classified");
@ -103,122 +68,17 @@ LLFloaterSearch::LLFloaterSearch(const Params& key) :
mCollectionType.insert("people"); mCollectionType.insert("people");
} }
bool LLFloaterSearch::postBuild() LLFloaterSearch::~LLFloaterSearch()
{ {
LLFloaterWebContent::postBuild();
mWebBrowser->addObserver(this);
// <FS:Ansariel> Seperate help topic aside from other web content
setHelpTopic("floater_search");
return true;
} }
void LLFloaterSearch::onOpen(const LLSD& key) void LLFloaterSearch::onOpen(const LLSD& tokens)
{ {
Params p(key); initiateSearch(tokens);
p.trusted_content = true;
// <FS:AW opensim search support>
// p.allow_address_entry = false;
#ifdef OPENSIM // <FS:AW optional opensim support>
bool debug = gSavedSettings.getBOOL("DebugSearch");
p.allow_address_entry = debug;
// <FS:AW optional opensim support>
#else // OPENSIM
p.allow_address_entry = false;
#endif // OPENSIM
// </FS:AW optional opensim support>
// </FS:AW opensim search support>
LLFloaterWebContent::onOpen(p);
mWebBrowser->setFocus(true);
search(p.search);
} }
void LLFloaterSearch::onClose(bool app_quitting) void LLFloaterSearch::initiateSearch(const LLSD& tokens)
{ {
LLFloaterWebContent::onClose(app_quitting);
// tear down the web view so we don't show the previous search
// result when the floater is opened next time
destroy();
}
void LLFloaterSearch::godLevelChanged(U8 godlevel)
{
// search results can change based upon god level - if the user
// changes god level, then give them a warning (we don't refresh
// the search as this might undo any page navigation or
// AJAX-driven changes since the last search).
//FIXME: set status bar text
//getChildView("refresh_search")->setVisible( (godlevel != mSearchGodLevel));
}
void LLFloaterSearch::search(const SearchQuery &p)
{
if (! mWebBrowser || !p.validateBlock())
{
return;
}
// reset the god level warning as we're sending the latest state
getChildView("refresh_search")->setVisible(false);
mSearchGodLevel = gAgent.getGodLevel();
// work out the subdir to use based on the requested category
LLSD subs;
if (mSearchType.find(p.category) != mSearchType.end())
{
subs["TYPE"] = p.category;
}
else
{
subs["TYPE"] = "standard";
}
// add the search query string
subs["QUERY"] = LLURI::escape(p.query);
subs["COLLECTION"] = "";
if (subs["TYPE"] == "standard")
{
if (mCollectionType.find(p.collection) != mCollectionType.end())
{
subs["COLLECTION"] = "&collection_chosen=" + std::string(p.collection);
}
else
{
std::string collection_args("");
for (std::set<std::string>::iterator it = mCollectionType.begin(); it != mCollectionType.end(); ++it)
{
collection_args += "&collection_chosen=" + std::string(*it);
}
subs["COLLECTION"] = collection_args;
}
}
// add the user's preferred maturity (can be changed via prefs)
std::string maturity;
if (gAgent.prefersAdult())
{
maturity = "gma"; // PG,Mature,Adult
}
else if (gAgent.prefersMature())
{
maturity = "gm"; // PG,Mature
}
else
{
maturity = "g"; // 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.)
// <FS:AW opensim search support> // <FS:AW opensim search support>
// std::string url = gSavedSettings.getString("SearchURL"); // std::string url = gSavedSettings.getString("SearchURL");
std::string url; std::string url;
@ -236,8 +96,98 @@ void LLFloaterSearch::search(const SearchQuery &p)
} }
// </FS:AW opensim search support> // </FS:AW opensim search support>
LLSD subs;
// Setting this substitution here results in a full set of collections being
// substituted into the final URL using the logic from the original search.
subs["TYPE"] = "standard";
const size_t parts = tokens.size();
// get the (optional) category for the search
std::string collection;
if (parts > 0)
{
collection = tokens[0].asString();
}
// get the (optional) search string
std::string search_text;
if (parts > 1)
{
search_text = tokens[1].asString();
}
// TODO: where does category get set? I cannot find a reference to
// it in internal docs - might be conflated with values in mSearchType
std::string category;
if (mSearchType.find(category) != mSearchType.end())
{
subs["TYPE"] = category;
}
else
{
subs["TYPE"] = "standard";
}
subs["QUERY"] = LLURI::escape(search_text);
subs["COLLECTION"] = "";
if (subs["TYPE"] == "standard")
{
if (mCollectionType.find(collection) != mCollectionType.end())
{
subs["COLLECTION"] = "&collection_chosen=" + std::string(collection);
}
else
{
std::string collection_args("");
for (std::set<std::string>::iterator it = mCollectionType.begin(); it != mCollectionType.end(); ++it)
{
collection_args += "&collection_chosen=" + std::string(*it);
}
subs["COLLECTION"] = collection_args;
}
}
// Default to PG
std::string maturity = "g";
if (gAgent.prefersAdult())
{
// PG,Mature,Adult
maturity = "gma";
}
else if (gAgent.prefersMature())
{
// PG,Mature
maturity = "gm";
}
subs["MATURITY"] = maturity;
// God status
subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0";
// This call expands a set of generic substitutions like language, viewer version
// etc. and then also does the same with the list of subs passed in.
url = LLWeb::expandURLSubstitutions(url, subs); url = LLWeb::expandURLSubstitutions(url, subs);
// and load the URL in the web view // Naviation to the calculated URL - we know it's HTML so we can
mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML); // tell the media system not to bother with the MIME type check.
LLMediaCtrl* search_browser = findChild<LLMediaCtrl>("search_contents");
search_browser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
}
bool LLFloaterSearch::postBuild()
{
enableResizeCtrls(true, true, false);
// This call is actioned by the preload code in llViewerWindow
// that creates the search floater during the login process
// using a generic search with no query
initiateSearch(LLSD());
// <FS:Ansariel> Seperate help topic aside from other web content
setHelpTopic("floater_search");
return true;
} }

View File

@ -1,11 +1,10 @@
/** /**
* @file llfloatersearch.h * @file llfloatersearch.h
* @author Martin Reddy * @brief Floater for Search (update 2025, preload)
* @brief Search floater - uses an embedded web browser control
* *
* $LicenseInfo:firstyear=2009&license=viewerlgpl$ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code * Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc. * Copyright (C) 2011, Linden Research, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -25,70 +24,23 @@
* $/LicenseInfo$ * $/LicenseInfo$
*/ */
#ifndef LL_LLFLOATERSEARCH_H #pragma once
#define LL_LLFLOATERSEARCH_H
#include "llfloaterwebcontent.h" #include "llfloater.h"
#include "llviewermediaobserver.h"
#include <string> class LLFloaterSearch:
public LLFloater {
friend class LLFloaterReg;
class LLMediaCtrl; public:
void onOpen(const LLSD& key) override;
/// private:
/// The search floater allows users to perform all search operations. LLFloaterSearch(const LLSD& key);
/// All search functionality is now implemented via web services and ~LLFloaterSearch();
/// so this floater simply embeds a web view and displays the search void initiateSearch(const LLSD& tokens);
/// web page. The browser control is explicitly marked as "trusted" bool postBuild() override;
/// so that the user can click on teleport links in search results.
///
class LLFloaterSearch :
public LLFloaterWebContent
{
public:
struct SearchQuery : public LLInitParam::Block<SearchQuery>
{
Optional<std::string> category;
Optional<std::string> collection;
Optional<std::string> query;
SearchQuery(); std::set<std::string> mSearchType;
}; std::set<std::string> mCollectionType;
struct _Params : public LLInitParam::Block<_Params, LLFloaterWebContent::Params>
{
Optional<SearchQuery> search;
};
typedef LLSDParamAdapter<_Params> Params;
LLFloaterSearch(const Params& key);
/// show the search floater with a new search
/// see search() for details on the key parameter.
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ void onClose(bool app_quitting);
/// perform a search with the specific search term.
/// The key should be a map that can contain the following keys:
/// - "id": specifies the text phrase to search for
/// - "category": one of "all" (default), "people", "places",
/// "events", "groups", "wiki", "destinations", "classifieds"
void search(const SearchQuery &query);
/// changing godmode can affect the search results that are
/// returned by the search website - use this method to tell the
/// search floater that the user has changed god level.
void godLevelChanged(U8 godlevel);
private:
/*virtual*/ bool postBuild();
std::set<std::string> mSearchType;
std::set<std::string> mCollectionType;
U8 mSearchGodLevel;
}; };
#endif // LL_LLFLOATERSEARCH_H

View File

@ -296,7 +296,8 @@ bool LLStatusBar::postBuild()
boost::bind(&LLStatusBar::onClickBuyCurrency, this)); boost::bind(&LLStatusBar::onClickBuyCurrency, this));
// <FS:Ansariel> Not used in Firestorm // <FS:Ansariel> Not used in Firestorm
//getChild<LLUICtrl>("goShop")->setCommitCallback(boost::bind(&LLWeb::loadURL, gSavedSettings.getString("MarketplaceURL"), LLStringUtil::null, LLStringUtil::null)); //getChild<LLUICtrl>("goShop")->setCommitCallback(
// boost::bind(&LLStatusBar::onClickShop, this));
mBoxBalance = getChild<LLTextBox>("balance"); mBoxBalance = getChild<LLTextBox>("balance");
mBoxBalance->setClickedCallback(&LLStatusBar::onClickRefreshBalance, this); mBoxBalance->setClickedCallback(&LLStatusBar::onClickRefreshBalance, this);
@ -968,6 +969,11 @@ void LLStatusBar::onClickBuyCurrency()
LLFirstUse::receiveLindens(false); LLFirstUse::receiveLindens(false);
} }
void LLStatusBar::onClickShop()
{
LLFloaterReg::toggleInstanceOrBringToFront("marketplace");
}
void LLStatusBar::onMouseEnterPresetsCamera() void LLStatusBar::onMouseEnterPresetsCamera()
{ {
LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder"); LLView* popup_holder = gViewerWindow->getRootView()->getChildView("popup_holder");

View File

@ -164,6 +164,7 @@ public:
private: private:
void onClickBuyCurrency(); void onClickBuyCurrency();
void onClickShop();
void onVolumeChanged(const LLSD& newvalue); void onVolumeChanged(const LLSD& newvalue);
//void onVoiceChanged(const LLSD& newvalue); // <FS:Ansariel> Fix LL voice disabled on 2nd instance nonsense //void onVoiceChanged(const LLSD& newvalue); // <FS:Ansariel> Fix LL voice disabled on 2nd instance nonsense
void onObscureBalanceChanged(const LLSD& newvalue); void onObscureBalanceChanged(const LLSD& newvalue);

View File

@ -49,6 +49,7 @@
#include "llviewerregion.h" #include "llviewerregion.h"
#include "llviewerstats.h" #include "llviewerstats.h"
#include "llviewerstatsrecorder.h" #include "llviewerstatsrecorder.h"
#include "llviewerthrottle.h"
#include "llviewerassetstats.h" #include "llviewerassetstats.h"
#include "llworld.h" #include "llworld.h"
#include "llsdparam.h" #include "llsdparam.h"
@ -2705,7 +2706,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded, bool qa_mod
mOriginFetchSource(LLTextureFetch::FROM_ALL), mOriginFetchSource(LLTextureFetch::FROM_ALL),
mTextureInfoMainThread(false) mTextureInfoMainThread(false)
{ {
mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); mMaxBandwidth = LLViewerThrottle::getMaxBandwidthKbps();
mTextureInfo.setLogging(true); mTextureInfo.setLogging(true);
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
@ -3265,11 +3266,10 @@ void LLTextureFetch::commonUpdate()
size_t LLTextureFetch::update(F32 max_time_ms) size_t LLTextureFetch::update(F32 max_time_ms)
{ {
LL_PROFILE_ZONE_SCOPED; LL_PROFILE_ZONE_SCOPED;
static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS", 3000.0);
{ {
mNetworkQueueMutex.lock(); // +Mfnq mNetworkQueueMutex.lock(); // +Mfnq
mMaxBandwidth = band_width(); mMaxBandwidth = LLViewerThrottle::getMaxBandwidthKbps();
add(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED, mHTTPTextureBits); add(LLStatViewer::TEXTURE_NETWORK_DATA_RECEIVED, mHTTPTextureBits);
mHTTPTextureBits = (U32Bits)0; mHTTPTextureBits = (U32Bits)0;

View File

@ -49,6 +49,7 @@
#include "llviewerobjectlist.h" #include "llviewerobjectlist.h"
#include "llviewertexture.h" #include "llviewertexture.h"
#include "llviewertexturelist.h" #include "llviewertexturelist.h"
#include "llviewerthrottle.h"
#include "llviewerwindow.h" #include "llviewerwindow.h"
#include "llwindow.h" #include "llwindow.h"
#include "llvovolume.h" #include "llvovolume.h"
@ -735,13 +736,9 @@ void LLGLTexMemBar::draw()
// <FS:Ansariel> Move BW figures further to the right to prevent overlapping // <FS:Ansariel> Move BW figures further to the right to prevent overlapping
left = 575; left = 575;
F32Kilobits bandwidth( LLAppViewer::getTextureFetch()->getTextureBandwidth() ); F32Kilobits bandwidth(LLAppViewer::getTextureFetch()->getTextureBandwidth());
// <FS:Ansariel> Speed-up F32Kilobits max_bandwidth(LLViewerThrottle::getMaxBandwidthKbps());
//F32Kilobits max_bandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS"); color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color;
static LLCachedControl<F32> throttleBandwidthKBPS(gSavedSettings, "ThrottleBandwidthKBPS");
F32Kilobits max_bandwidth( (F32)throttleBandwidthKBPS );
// </FS:Ansariel> Speed-upx
color = bandwidth.value() > max_bandwidth.value() ? LLColor4::red : bandwidth.value() > max_bandwidth.value() * .75f ? LLColor4::yellow : text_color;
color[VALPHA] = text_color[VALPHA]; color[VALPHA] = text_color[VALPHA];
text = llformat("BW:%.0f/%.0f",bandwidth.value(), max_bandwidth.value()); text = llformat("BW:%.0f/%.0f",bandwidth.value(), max_bandwidth.value());
LLFontGL::getFontMonospace()->renderUTF8(text, 0, (S32)x_right, v_offset + line_height*3, LLFontGL::getFontMonospace()->renderUTF8(text, 0, (S32)x_right, v_offset + line_height*3,

View File

@ -21,6 +21,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$ * $/LicenseInfo$
*/ */
@ -98,6 +99,7 @@
#include "llfloaterlinkreplace.h" #include "llfloaterlinkreplace.h"
#include "llfloaterloadprefpreset.h" #include "llfloaterloadprefpreset.h"
#include "llfloatermap.h" #include "llfloatermap.h"
#include "llfloatermarketplace.h"
#include "llfloatermarketplacelistings.h" #include "llfloatermarketplacelistings.h"
#include "llfloatermediasettings.h" #include "llfloatermediasettings.h"
#include "llfloatermemleak.h" #include "llfloatermemleak.h"
@ -501,6 +503,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>); LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMemLeak>);
LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>); LLFloaterReg::add("media_settings", "floater_media_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMediaSettings>);
LLFloaterReg::add("marketplace", "floater_marketplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplace>);
LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>); LLFloaterReg::add("marketplace_listings", "floater_marketplace_listings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceListings>);
LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>); LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>);
LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>); LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);

View File

@ -1267,35 +1267,46 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url)
{ {
LLAppViewer::instance()->postToMainCoro([=]() LLAppViewer::instance()->postToMainCoro([=]()
{ {
LLMediaCtrl* media_instance = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents"); std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart);
if (media_instance) std::string cookie_name = "";
std::string cookie_value = "";
std::string cookie_path = "";
bool httponly = true;
bool secure = true;
LLViewerMedia* inst = getInstance();
if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure))
{ {
LLViewerMedia* inst = getInstance(); // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the
std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked.
std::string cookie_name = ""; // For now, we use the URL for the OpenID POST request since it will have the same authority
std::string cookie_value = ""; // as the domain field.
std::string cookie_path = ""; // (Feels like there must be a less dirty way to construct a URL from component LLURL parts)
bool httponly = true; // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further
bool secure = true; // down.
if (inst->parseRawCookie(inst->mOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority));
media_instance->getMediaPlugin())
// list of floater names and webbrowser therein to set the cookie that arrived via login into
struct MediaCookieInstance {
std::string floater_name;
std::string browser_name;
};
struct MediaCookieInstance media_cookie_instances[] = {
{"search", "search_contents" },
{"marketplace", "marketplace_contents" },
{"destinations", "destination_guide_contents" },
};
for (MediaCookieInstance mci : media_cookie_instances)
{ {
// MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the LLMediaCtrl* media_instance = LLFloaterReg::getInstance(mci.floater_name)->getChild<LLMediaCtrl>(mci.browser_name);
// url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. if (media_instance && media_instance->getMediaPlugin())
// For now, we use the URL for the OpenID POST request since it will have the same authority {
// as the domain field. media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host,
// (Feels like there must be a less dirty way to construct a URL from component LLURL parts) cookie_path, httponly, secure);
// MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further
// down.
std::string cefUrl(std::string(inst->mOpenIDURL.mURI) + "://" + std::string(inst->mOpenIDURL.mAuthority));
media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value,
cookie_path, httponly, secure); cookie_host, cookie_path, httponly, secure);
}
// Now that we have parsed the raw cookie, we must store it so that each new media instance
// can also get a copy and faciliate logging into internal SL sites.
media_instance->getMediaPlugin()->storeOpenIDCookie(cefUrl, cookie_name, cookie_value,
cookie_host, cookie_path, httponly, secure);
} }
} }
}); });

View File

@ -5504,13 +5504,6 @@ void set_god_level(U8 god_level)
// changing god-level can affect which menus we see // changing god-level can affect which menus we see
show_debug_menus(); show_debug_menus();
// changing god-level can invalidate search results
LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search"));
if (search)
{
search->godLevelChanged(god_level);
}
} }
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER #ifdef TOGGLE_HACKED_GODLIKE_VIEWER

View File

@ -225,7 +225,7 @@ void LLViewerThrottle::setMaxBandwidth(F32 kbits_per_second, bool from_event)
void LLViewerThrottle::load() void LLViewerThrottle::load()
{ {
mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS")*1024; mMaxBandwidth = getMaxBandwidthKbps() * 1024;
resetDynamicThrottle(); resetDynamicThrottle();
mCurrent.dump(); mCurrent.dump();
} }
@ -242,6 +242,15 @@ void LLViewerThrottle::sendToSim() const
mCurrent.sendToSim(); mCurrent.sendToSim();
} }
F32 LLViewerThrottle::getMaxBandwidthKbps()
{
constexpr F32 MIN_BANDWIDTH = 100.0f; // 100 Kbps
constexpr F32 MAX_BANDWIDTH = 10000.0f; // 10 Mbps
static LLCachedControl<F32> bandwidth(gSavedSettings, "ThrottleBandwidthKBPS", 3000.0);
return llclamp(bandwidth(), MIN_BANDWIDTH, MAX_BANDWIDTH);
}
LLViewerThrottleGroup LLViewerThrottle::getThrottleGroup(const F32 bandwidth_kbps) LLViewerThrottleGroup LLViewerThrottle::getThrottleGroup(const F32 bandwidth_kbps)
{ {

View File

@ -64,6 +64,7 @@ public:
void save() const; void save() const;
void sendToSim() const; void sendToSim() const;
static F32 getMaxBandwidthKbps();
F32 getMaxBandwidth()const { return mMaxBandwidth; } F32 getMaxBandwidth()const { return mMaxBandwidth; }
F32 getCurrentBandwidth() const { return mCurrentBandwidth; } F32 getCurrentBandwidth() const { return mCurrentBandwidth; }

View File

@ -2525,6 +2525,18 @@ void LLViewerWindow::initWorldUI()
{ {
destination_guide_url = gSavedSettings.getString("DestinationGuideURL"); destination_guide_url = gSavedSettings.getString("DestinationGuideURL");
} }
LLMediaCtrl* search = LLFloaterReg::getInstance("search")->findChild<LLMediaCtrl>("search_contents");
if (search)
{
search->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
}
LLMediaCtrl* marketplace = LLFloaterReg::getInstance("marketplace")->getChild<LLMediaCtrl>("marketplace_contents");
if (marketplace)
{
marketplace->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL"));
std::string url = gSavedSettings.getString("MarketplaceURL");
marketplace->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
}
if(!destination_guide_url.empty()) if(!destination_guide_url.empty())
{ {

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="FIND">
<floater.string name="loading_text">
Henter...
</floater.string>
<floater.string name="done_text">
Færdig
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Gentag søgning med &quot;God level&quot;
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -1,16 +1,2 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title=""> <floater name="floater_search" title="Suche"/>
<floater.string name="loading_text">
Wird geladen...
</floater.string>
<floater.string name="done_text">
Fertig
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Suche wiederholen, um aktuellen Gott-Level zu berücksichtigen
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater
positioning="cascading"
legacy_header_height="225"
can_minimize="true"
can_close="true"
can_resize="true"
min_height="800"
min_width="800"
height="800"
layout="topleft"
name="Marketplace"
single_instance="true"
help_topic="marketplace"
save_rect="true"
save_visibility="true"
title="Marketplace"
width="800">
<web_browser
top="25"
height="775"
width="800"
follows="all"
name="marketplace_contents"
trusted_content="true"/>
</floater>

View File

@ -1,18 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater <floater
positioning="centered" positioning="cascading"
legacy_header_height="18" legacy_header_height="225"
can_resize="true" can_minimize="true"
height="775" can_close="true"
layout="topleft" can_resize="true"
min_height="400" min_height="800"
min_width="500" min_width="800"
name="floater_search" height="800"
help_topic="fs_search" layout="topleft"
save_rect="true" name="Search"
save_visibility="true" single_instance="true"
title="" help_topic="search"
initial_mime_type="text/html" save_rect="true"
width="780" save_visibility="true"
tab_stop="true" title="Search"
filename="floater_web_content.xml"/> width="800">
<web_browser
top="25"
height="775"
width="800"
follows="all"
name="search_contents"
trusted_content="true"/>
</floater>

View File

@ -15,7 +15,7 @@ name="panel_ls_web">
right="-5" right="-5"
layout="topleft" layout="topleft"
follows="all" follows="all"
name="search_browser" name="search_contents"
trusted_content="true" trusted_content="true"
start_url="about:blank" /> start_url="about:blank" />
</panel> </panel>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="">
<floater.string name="loading_text">
Cargando...
</floater.string>
<floater.string name="done_text">
Hecho
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Redo search to reflect current God level
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="">
<floater.string name="loading_text">
Caricamento in corso...
</floater.string>
<floater.string name="done_text">
Fine
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Ripeti ricerca in modo che rifletta il livello di diritti Admin attuale
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="">
<floater.string name="loading_text">
Carregando...
</floater.string>
<floater.string name="done_text">
Pronto
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Buscar novamente com status God
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="">
<floater.string name="loading_text">
Yükleniyor...
</floater.string>
<floater.string name="done_text">
Tamamlandı
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
Mevcut Yönetici seviyesini dikkate alarak aramayı yenile
</text>
</layout_panel>
</layout_stack>
</floater>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater name="floater_search" title="">
<floater.string name="loading_text">
載入中...
</floater.string>
<floater.string name="done_text">
完成
</floater.string>
<layout_stack name="stack1">
<layout_panel name="browser_layout">
<text name="refresh_search">
以目前具備的神階級再搜尋一次
</text>
</layout_panel>
</layout_stack>
</floater>