summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/lltexteditor.cpp3
-rw-r--r--indra/llui/lltexteditor.h10
-rw-r--r--indra/newview/llcommandhandler.cpp80
-rw-r--r--indra/newview/llcommandhandler.h62
-rw-r--r--indra/newview/llfloatermap.cpp44
-rw-r--r--indra/newview/llfloatermap.h2
-rw-r--r--indra/newview/llpanellogin.cpp1
-rw-r--r--indra/newview/llstartup.cpp69
-rw-r--r--indra/newview/llstartup.h8
-rw-r--r--indra/newview/llurldispatcher.cpp303
-rw-r--r--indra/newview/llurldispatcher.h32
-rw-r--r--indra/newview/llviewermenu.cpp8
-rw-r--r--indra/newview/llviewerwindow.cpp17
13 files changed, 548 insertions, 91 deletions
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 1ec62f6927..daf3438d3c 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -58,7 +58,8 @@ const S32 SPACES_PER_TAB = 4;
LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
void (* LLTextEditor::mURLcallback)(const char*) = NULL;
-BOOL (* LLTextEditor::mSecondlifeURLcallback)(LLString) = NULL;
+bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL;
+bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL;
///////////////////////////////////////////////////////////////////
//virtuals
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index e19e799033..ea2e6b3efe 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -194,9 +194,10 @@ public:
// Callbacks
static void setLinkColor(LLColor4 color) { mLinkColor = color; }
- static void setURLCallbacks( void (*callback1) (const char* url),
- BOOL (*callback2) (LLString url) )
- { mURLcallback = callback1; mSecondlifeURLcallback = callback2;}
+ static void setURLCallbacks(void (*callback1) (const char* url),
+ bool (*callback2) (const std::string& url),
+ bool (*callback3) (const std::string& url) )
+ { mURLcallback = callback1; mSecondlifeURLcallback = callback2; mSecondlifeURLcallbackRightClick = callback3;}
void setOnScrollEndCallback(void (*callback)(void*), void* userdata);
@@ -318,7 +319,8 @@ public:
LLKeywords mKeywords;
static LLColor4 mLinkColor;
static void (*mURLcallback) (const char* url);
- static BOOL (*mSecondlifeURLcallback) (LLString url);
+ static bool (*mSecondlifeURLcallback) (const std::string& url);
+ static bool (*mSecondlifeURLcallbackRightClick) (const std::string& url);
protected:
LLWString mWText;
mutable LLString mUTF8Text;
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
new file mode 100644
index 0000000000..47192c99f8
--- /dev/null
+++ b/indra/newview/llcommandhandler.cpp
@@ -0,0 +1,80 @@
+/**
+ * @file llcommandhandler.cpp
+ * @brief Central registry for text-driven "commands", most of
+ * which manipulate user interface. For example, the command
+ * "agent (uuid) about" will open the UI for an avatar's profile.
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+#include "llviewerprecompiledheaders.h"
+
+#include "llcommandhandler.h"
+
+// system includes
+#include <boost/tokenizer.hpp>
+
+//---------------------------------------------------------------------------
+// Underlying registry for command handlers, not directly accessible.
+//---------------------------------------------------------------------------
+
+class LLCommandHandlerRegistry
+{
+public:
+ static LLCommandHandlerRegistry& instance();
+ void add(const char* cmd, LLCommandHandler* handler);
+ bool dispatch(const std::string& cmd, const std::vector<std::string>& params);
+
+private:
+ std::map<std::string, LLCommandHandler*> mMap;
+};
+
+// static
+LLCommandHandlerRegistry& LLCommandHandlerRegistry::instance()
+{
+ // Force this to be initialized on first call, because we're going
+ // to be adding items to the std::map before main() and we can't
+ // rely on a global being initialized in the right order.
+ static LLCommandHandlerRegistry instance;
+ return instance;
+}
+
+void LLCommandHandlerRegistry::add(const char* cmd, LLCommandHandler* handler)
+{
+ mMap[cmd] = handler;
+}
+
+bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,
+ const std::vector<std::string>& params)
+{
+ std::map<std::string, LLCommandHandler*>::iterator it = mMap.find(cmd);
+ if (it == mMap.end()) return false;
+ LLCommandHandler* handler = it->second;
+ if (!handler) return false;
+ return handler->handle(params);
+}
+
+//---------------------------------------------------------------------------
+// Automatic registration of commands, runs before main()
+//---------------------------------------------------------------------------
+
+LLCommandHandler::LLCommandHandler(const char* cmd)
+{
+ LLCommandHandlerRegistry::instance().add(cmd, this);
+}
+
+LLCommandHandler::~LLCommandHandler()
+{
+ // Don't care about unregistering these, all the handlers
+ // should be static objects.
+}
+
+//---------------------------------------------------------------------------
+// Public interface
+//---------------------------------------------------------------------------
+
+// static
+bool LLCommandDispatcher::dispatch(const std::string& cmd, const std::vector<std::string>& params)
+{
+ return LLCommandHandlerRegistry::instance().dispatch(cmd, params);
+}
diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h
new file mode 100644
index 0000000000..65ce6c633b
--- /dev/null
+++ b/indra/newview/llcommandhandler.h
@@ -0,0 +1,62 @@
+/**
+ * @file llcommandhandler.h
+ * @brief Central registry for text-driven "commands", most of
+ * which manipulate user interface. For example, the command
+ * "agent (uuid) about" will open the UI for an avatar's profile.
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+#ifndef LLCOMMANDHANDLER_H
+#define LLCOMMANDHANDLER_H
+
+/* To implement a command "foo" that takes one parameter,
+ a UUID, do this:
+
+class LLFooHandler : public LLCommandHandler
+{
+public:
+ // Inform the system you handle commands starting
+ // with "foo"
+ LLFooHandler() : LLCommandHandler("foo") { }
+
+ // Your code here
+ bool handle(const std::vector<std::string>& tokens)
+ {
+ if (tokens.size() < 1) return false;
+ LLUUID id( tokens[0] );
+ return doFoo(id);
+ }
+};
+
+// Creating the object registers with the dispatcher.
+LLFooHandler gFooHandler;
+*/
+
+class LLCommandHandler
+{
+public:
+ LLCommandHandler(const char* command);
+ // Automatically registers object to get called when
+ // command is executed.
+
+ virtual ~LLCommandHandler();
+
+ virtual bool handle(const std::vector<std::string>& params) = 0;
+ // Execute the command with a provided (possibly empty)
+ // list of parameters.
+ // Return true if you did something, false if the parameters
+ // are invalid or on error.
+};
+
+
+class LLCommandDispatcher
+{
+public:
+ static bool dispatch(const std::string& cmd, const std::vector<std::string>& params);
+ // Execute a command registered via the above mechanism,
+ // passing string parameters.
+ // Returns true if command was found and executed correctly.
+};
+
+#endif
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 242f5b7991..d53929272c 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -197,47 +197,3 @@ void LLFloaterMap::toggle(void*)
}
}
}
-
-
-BOOL process_secondlife_url(LLString url)
-{
- S32 strpos, strpos2;
-
- LLString slurlID = "slurl.com/secondlife/";
- strpos = url.find(slurlID);
-
- if (strpos < 0)
- {
- slurlID="secondlife://";
- strpos = url.find(slurlID);
- }
-
- if (strpos >= 0)
- {
- LLString simname;
-
- strpos+=slurlID.length();
- strpos2=url.find("/",strpos);
- if (strpos2 < strpos) strpos2=url.length();
- simname="secondlife://" + url.substr(strpos,url.length() - strpos);
-
- LLURLSimString::setString( simname );
- LLURLSimString::parse();
-
- // if there is a world map
- if ( gFloaterWorldMap )
- {
- // mark where the destination is
- gFloaterWorldMap->trackURL( LLURLSimString::sInstance.mSimName.c_str(),
- LLURLSimString::sInstance.mX,
- LLURLSimString::sInstance.mY,
- LLURLSimString::sInstance.mZ );
-
- // display map
- LLFloaterWorldMap::show( NULL, TRUE );
- };
-
- return TRUE;
- }
- return FALSE;
-}
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index 5b581c0fe5..8f7629be3f 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -46,6 +46,4 @@ protected:
extern LLFloaterMap *gFloaterMap;
-BOOL process_secondlife_url(LLString url);
-
#endif // LL_LLFLOATERMAP_H
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 7a05f2bdbf..b730d15aab 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -31,6 +31,7 @@
#include "lltextbox.h"
#include "llui.h"
#include "lluiconstants.h"
+#include "llurlsimstring.h"
#include "llviewerbuild.h"
#include "llviewerimagelist.h"
#include "llviewermenu.h" // for handle_preferences()
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index fe17664c7d..615f872de8 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -107,6 +107,8 @@
#include "lltexturefetch.h"
#include "lltoolmgr.h"
#include "llui.h"
+#include "llurldispatcher.h"
+#include "llurlsimstring.h"
#include "llurlwhitelist.h"
#include "lluserauth.h"
#include "llviewerassetstorage.h"
@@ -779,7 +781,7 @@ BOOL idle_startup()
//For HTML parsing in text boxes.
LLTextEditor::setLinkColor( gSavedSettings.getColor4("HTMLLinkColor") );
- LLTextEditor::setURLCallbacks ( &LLWeb::loadURL, &process_secondlife_url );
+ LLTextEditor::setURLCallbacks ( &LLWeb::loadURL, &LLURLDispatcher::dispatch, &LLURLDispatcher::dispatch );
//-------------------------------------------------
// Handle startup progress screen
@@ -2254,25 +2256,8 @@ BOOL idle_startup()
gAgentPilot.startPlayback();
}
- // ok, if we've gotten this far and have a startup URL
- if (LLURLSimString::sInstance.parse())
- {
- // kick off request for landmark to startup URL
- if(gFloaterWorldMap)
- {
- LLVector3 pos = gAgent.getPositionAgent();
- if( LLURLSimString::sInstance.mSimName != gAgent.getRegion()->getName()
- || LLURLSimString::sInstance.mX != llfloor(pos[VX])
- || LLURLSimString::sInstance.mY != llfloor(pos[VY]) )
- {
- LLFloaterWorldMap::show(NULL, TRUE);
- gFloaterWorldMap->trackURL(LLURLSimString::sInstance.mSimName,
- LLURLSimString::sInstance.mX,
- LLURLSimString::sInstance.mY,
- LLURLSimString::sInstance.mZ);
- }
- }
- }
+ // If we've got a startup URL, dispatch it
+ LLStartUp::dispatchURL();
// Clean up the userauth stuff.
if (gUserAuthp)
@@ -3665,13 +3650,6 @@ void release_start_screen()
}
// static
-bool LLStartUp::canGoFullscreen()
-{
- return LLStartUp::getStartupState() >= STATE_WORLD_INIT;
-}
-
-
-// static
void LLStartUp::setStartupState( S32 state )
{
llinfos << "Startup state changing from " << gStartupState << " to " << state << llendl;
@@ -3692,3 +3670,40 @@ void reset_login()
if ( gFloaterMap )
gFloaterMap->setVisible( FALSE );
}
+
+//---------------------------------------------------------------------------
+
+std::string LLStartUp::sSLURLCommand;
+
+bool LLStartUp::canGoFullscreen()
+{
+ return gStartupState >= STATE_WORLD_INIT;
+}
+
+bool LLStartUp::dispatchURL()
+{
+ // ok, if we've gotten this far and have a startup URL
+ if (!sSLURLCommand.empty())
+ {
+ LLURLDispatcher::dispatch(sSLURLCommand);
+ }
+ else if (LLURLSimString::parse())
+ {
+ // If we started with a location, but we're already
+ // at that location, don't pop dialogs open.
+ LLVector3 pos = gAgent.getPositionAgent();
+ F32 dx = pos.mV[VX] - (F32)LLURLSimString::sInstance.mX;
+ F32 dy = pos.mV[VY] - (F32)LLURLSimString::sInstance.mY;
+ const F32 SLOP = 2.f; // meters
+
+ if( LLURLSimString::sInstance.mSimName != gAgent.getRegion()->getName()
+ || (dx*dx > SLOP*SLOP)
+ || (dy*dy > SLOP*SLOP) )
+ {
+ std::string url = LLURLSimString::getURL();
+ LLURLDispatcher::dispatch(url);
+ }
+ return true;
+ }
+ return false;
+}
diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h
index 9e1ff3c151..88ed0bdd24 100644
--- a/indra/newview/llstartup.h
+++ b/indra/newview/llstartup.h
@@ -64,6 +64,14 @@ public:
static void setStartupState( S32 state );
static S32 getStartupState() { return gStartupState; };
+ static bool dispatchURL();
+ // if we have a SLURL or sim string ("Ahern/123/45") that started
+ // the viewer, dispatch it
+
+ static std::string sSLURLCommand;
+ // *HACK: On startup, if we were passed a secondlife://app/do/foo
+ // command URL, store it for later processing.
+
protected:
static S32 gStartupState; // Do not set directly, use LLStartup::setStartupState
};
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
new file mode 100644
index 0000000000..4145ec305c
--- /dev/null
+++ b/indra/newview/llurldispatcher.cpp
@@ -0,0 +1,303 @@
+/**
+ * @file llurldispatcher.cpp
+ * @brief Central registry for all URL handlers
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+#include "llviewerprecompiledheaders.h"
+
+#include "llurldispatcher.h"
+
+// viewer includes
+#include "llagent.h" // teleportViaLocation()
+#include "llcommandhandler.h"
+// *FIX: code in merge sl-search-8
+//#include "llfloaterurldisplay.h"
+#include "llfloaterdirectory.h"
+#include "llfloaterhtmlhelp.h"
+#include "llfloaterworldmap.h"
+#include "llpanellogin.h"
+#include "llstartup.h" // gStartupState
+#include "llurlsimstring.h"
+#include "llviewerwindow.h" // alertXml()
+#include "llworldmap.h"
+
+// library includes
+#include "llsd.h"
+
+// system includes
+#include <boost/tokenizer.hpp>
+
+const std::string SLURL_SL_HELP_PREFIX = "secondlife://app.";
+const std::string SLURL_SL_PREFIX = "sl://";
+const std::string SLURL_SECONDLIFE_PREFIX = "secondlife://";
+const std::string SLURL_SLURL_PREFIX = "http://slurl.com/secondlife/";
+
+const std::string SLURL_APP_TOKEN = "app/";
+
+class LLURLDispatcherImpl
+{
+public:
+ static bool isSLURL(const std::string& url);
+
+ static bool isSLURLCommand(const std::string& url);
+
+ static bool dispatch(const std::string& url);
+ // returns true if handled
+
+ static bool dispatchRightClick(const std::string& url);
+
+private:
+ static bool dispatchCore(const std::string& url, bool right_mouse);
+ // handles both left and right click
+
+ static bool dispatchHelp(const std::string& url, BOOL right_mouse);
+ // Handles sl://app.floater.html.help by showing Help floater.
+ // Returns true if handled.
+
+ static bool dispatchApp(const std::string& url, BOOL right_mouse);
+ // Handles secondlife://app/agent/<agent_id>/about and similar
+ // by showing panel in Search floater.
+ // Returns true if handled.
+
+ static bool dispatchRegion(const std::string& url, BOOL right_mouse);
+ // handles secondlife://Ahern/123/45/67/
+ // Returns true if handled.
+
+// *FIX: code in merge sl-search-8
+// static void regionHandleCallback(U64 handle, const std::string& url,
+// const LLUUID& snapshot_id, bool teleport);
+// // Called by LLWorldMap when a region name has been resolved to a
+// // location in-world, used by places-panel display.
+
+ static bool matchPrefix(const std::string& url, const std::string& prefix);
+
+ static std::string stripProtocol(const std::string& url);
+
+ friend class LLTeleportHandler;
+};
+
+// static
+bool LLURLDispatcherImpl::isSLURL(const std::string& url)
+{
+ if (matchPrefix(url, SLURL_SL_HELP_PREFIX)) return true;
+ if (matchPrefix(url, SLURL_SL_PREFIX)) return true;
+ if (matchPrefix(url, SLURL_SECONDLIFE_PREFIX)) return true;
+ if (matchPrefix(url, SLURL_SLURL_PREFIX)) return true;
+ return false;
+}
+
+// static
+bool LLURLDispatcherImpl::isSLURLCommand(const std::string& url)
+{
+ if (matchPrefix(url, SLURL_SL_PREFIX + SLURL_APP_TOKEN)
+ || matchPrefix(url, SLURL_SECONDLIFE_PREFIX + SLURL_APP_TOKEN)
+ || matchPrefix(url, SLURL_SLURL_PREFIX + SLURL_APP_TOKEN) )
+ {
+ return true;
+ }
+ return false;
+}
+
+// static
+bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool right_mouse)
+{
+ if (url.empty()) return false;
+ if (dispatchHelp(url, right_mouse)) return true;
+ if (dispatchApp(url, right_mouse)) return true;
+ if (dispatchRegion(url, right_mouse)) return true;
+ return false;
+}
+
+// static
+bool LLURLDispatcherImpl::dispatch(const std::string& url)
+{
+ llinfos << "url: " << url << llendl;
+ return dispatchCore(url, false); // not right click
+}
+
+// static
+bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url)
+{
+ llinfos << "url: " << url << llendl;
+ return dispatchCore(url, true); // yes right click
+}
+// static
+bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, BOOL right_mouse)
+{
+ if (matchPrefix(url, SLURL_SL_HELP_PREFIX))
+ {
+ gViewerHtmlHelp.show();
+ return true;
+ }
+ return false;
+}
+
+// static
+bool LLURLDispatcherImpl::dispatchApp(const std::string& url, BOOL right_mouse)
+{
+ if (!isSLURL(url))
+ {
+ return false;
+ }
+ std::string s = stripProtocol(url);
+
+ // At this point, "secondlife://app/foo/bar/baz/" should be left
+ // as: "app/foo/bar/baz/"
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("/", "", boost::drop_empty_tokens);
+ tokenizer tokens(s, sep);
+ tokenizer::iterator it = tokens.begin();
+ tokenizer::iterator end = tokens.end();
+
+ // Build parameter list suitable for LLDispatcher dispatch
+ if (it == end) return false;
+ if (*it != "app") return false;
+ ++it;
+
+ if (it == end) return false;
+ std::string cmd = *it;
+ ++it;
+
+ std::vector<std::string> params;
+ for ( ; it != end; ++it)
+ {
+ params.push_back(*it);
+ }
+
+ bool handled = LLCommandDispatcher::dispatch(cmd, params);
+ if (handled) return true;
+
+ // Inform the user we can't handle this
+ std::map<std::string, std::string> args;
+ args["[SLURL]"] = url;
+ gViewerWindow->alertXml("BadURL", args);
+ return false;
+}
+
+// static
+bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, BOOL right_mouse)
+{
+ if (!isSLURL(url))
+ {
+ return false;
+ }
+
+ // Before we're logged in, need to update the startup screen
+ // to tell the user where they are going.
+ if (LLStartUp::getStartupState() < STATE_CLEANUP)
+ {
+ // Parse it and stash in globals, it will be dispatched in
+ // STATE_CLEANUP.
+ LLURLSimString::setString(url);
+ // We're at the login screen, so make sure user can see
+ // the login location box to know where they are going.
+ LLPanelLogin::refreshLocation( true );
+ return true;
+ }
+
+ std::string sim_string = stripProtocol(url);
+ std::string region_name;
+ S32 x = 128;
+ S32 y = 128;
+ S32 z = 0;
+ LLURLSimString::parse(sim_string, &region_name, &x, &y, &z);
+ if (gFloaterWorldMap)
+ {
+ llinfos << "Opening map to " << region_name << llendl;
+ gFloaterWorldMap->trackURL( region_name.c_str(), x, y, z );
+ LLFloaterWorldMap::show(NULL, TRUE);
+ }
+ return true;
+}
+
+// static
+bool LLURLDispatcherImpl::matchPrefix(const std::string& url, const std::string& prefix)
+{
+ std::string test_prefix = url.substr(0, prefix.length());
+ LLString::toLower(test_prefix);
+ return test_prefix == prefix;
+}
+
+// static
+std::string LLURLDispatcherImpl::stripProtocol(const std::string& url)
+{
+ std::string stripped = url;
+ if (matchPrefix(stripped, SLURL_SL_HELP_PREFIX))
+ {
+ stripped.erase(0, SLURL_SL_HELP_PREFIX.length());
+ }
+ else if (matchPrefix(stripped, SLURL_SL_PREFIX))
+ {
+ stripped.erase(0, SLURL_SL_PREFIX.length());
+ }
+ else if (matchPrefix(stripped, SLURL_SECONDLIFE_PREFIX))
+ {
+ stripped.erase(0, SLURL_SECONDLIFE_PREFIX.length());
+ }
+ else if (matchPrefix(stripped, SLURL_SLURL_PREFIX))
+ {
+ stripped.erase(0, SLURL_SLURL_PREFIX.length());
+ }
+ return stripped;
+}
+
+// *FIX: code in merge sl-search-8
+//
+////---------------------------------------------------------------------------
+//// Teleportation links are handled here because they are tightly coupled
+//// to URL parsing and sim-fragment parsing
+//class LLTeleportHandler : public LLCommandHandler
+//{
+//public:
+// LLTeleportHandler() : LLCommandHandler("teleport") { }
+// bool handle(const std::vector<std::string>& tokens)
+// {
+// // construct a "normal" SLURL, resolve the region to
+// // a global position, and teleport to it
+// if (tokens.size() < 1) return false;
+//
+// // Region names may be %20 escaped.
+// std::string region_name = LLURLSimString::unescapeRegionName(tokens[0]);
+//
+// // build secondlife://De%20Haro/123/45/67 for use in callback
+// std::string url = SLURL_SECONDLIFE_PREFIX;
+// for (size_t i = 0; i < tokens.size(); ++i)
+// {
+// url += tokens[i] + "/";
+// }
+// gWorldMap->sendNamedRegionRequest(region_name,
+// LLURLDispatcherImpl::regionHandleCallback,
+// url,
+// true); // teleport
+// return true;
+// }
+//};
+//LLTeleportHandler gTeleportHandler;
+
+//---------------------------------------------------------------------------
+
+// static
+bool LLURLDispatcher::isSLURL(const std::string& url)
+{
+ return LLURLDispatcherImpl::isSLURL(url);
+}
+
+// static
+bool LLURLDispatcher::isSLURLCommand(const std::string& url)
+{
+ return LLURLDispatcherImpl::isSLURLCommand(url);
+}
+
+// static
+bool LLURLDispatcher::dispatch(const std::string& url)
+{
+ return LLURLDispatcherImpl::dispatch(url);
+}
+// static
+bool LLURLDispatcher::dispatchRightClick(const std::string& url)
+{
+ return LLURLDispatcherImpl::dispatchRightClick(url);
+}
+
diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h
new file mode 100644
index 0000000000..e701a01be4
--- /dev/null
+++ b/indra/newview/llurldispatcher.h
@@ -0,0 +1,32 @@
+/**
+ * @file llurldispatcher.h
+ * @brief Central registry for all SL URL handlers
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+#ifndef LLURLDISPATCHER_H
+#define LLURLDISPATCHER_H
+
+class LLURLDispatcher
+{
+public:
+ static bool isSLURL(const std::string& url);
+ // Is this any sort of secondlife:// or sl:// URL?
+
+ static bool isSLURLCommand(const std::string& url);
+ // Is this a special secondlife://app/ URL?
+
+ static bool dispatch(const std::string& url);
+ // At startup time and on clicks in internal web browsers,
+ // teleport, open map, or run requested command.
+ // Handles:
+ // secondlife://RegionName/123/45/67/
+ // secondlife://app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show
+ // sl://app/foo/bar
+ // Returns true if someone handled the URL.
+ static bool dispatchRightClick(const std::string& url);
+
+};
+
+#endif
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c242d855f1..adea8968e5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -83,7 +83,6 @@
#include "llfloatergroups.h"
#include "llfloaterhtml.h"
#include "llfloaterhtmlhelp.h"
-#include "llfloaterhtmlfind.h"
#include "llfloaterinspect.h"
#include "llfloaterlagmeter.h"
#include "llfloaterland.h"
@@ -340,6 +339,7 @@ void toggle_show_xui_names(void *);
BOOL check_show_xui_names(void *);
// Debug UI
+void handle_slurl_test(void*);
void handle_save_to_xml(void*);
void handle_load_from_xml(void*);
@@ -976,6 +976,7 @@ extern BOOL gVectorizePerfTest;
void init_debug_ui_menu(LLMenuGL* menu)
{
+ menu->append(new LLMenuItemCallGL("SLURL Test", &handle_slurl_test));
menu->append(new LLMenuItemCallGL("Editable UI", &edit_ui));
menu->append(new LLMenuItemToggleGL("Async Keystrokes", &gHandleKeysAsync));
menu->append(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr));
@@ -7282,6 +7283,11 @@ void handle_load_from_xml(void*)
}
}
+void handle_slurl_test(void*)
+{
+ LLFloaterHtml::getInstance()->show("http://user.lindenlab.com/~james/slurl.html", "SLURL Test");
+}
+
void handle_rebake_textures(void*)
{
LLVOAvatar* avatar = gAgent.getAvatarObject();
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 897831afc0..d4b87ceba0 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -136,6 +136,7 @@
#include "lltoolview.h"
#include "llvieweruictrlfactory.h"
#include "lluploaddialog.h"
+#include "llurldispatcher.h" // SLURL from other app instance
#include "llviewercamera.h"
#include "llviewergesture.h"
#include "llviewerimagelist.h"
@@ -1394,22 +1395,14 @@ void LLViewerWindow::handleWindowUnblock(LLWindow *window)
void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
{
+ const S32 SLURL_MESSAGE_TYPE = 0;
switch (data_type)
{
- case 0:
+ case SLURL_MESSAGE_TYPE:
// received URL
- if (LLURLSimString::unpack_data(data))
+ std::string url = (const char*)data;
+ if (LLURLDispatcher::dispatch(url))
{
- if(gFloaterWorldMap)
- {
- gFloaterWorldMap->trackURL(LLURLSimString::sInstance.mSimName,
- LLURLSimString::sInstance.mX,
- LLURLSimString::sInstance.mY,
- LLURLSimString::sInstance.mZ);
-
- LLFloaterWorldMap::show(NULL, TRUE);
- }
-
// bring window to foreground, as it has just been "launched" from a URL
mWindow->bringToFront();
}