Merge - final pull of viewer-development.
commit
9c97a200be
|
|
@ -373,6 +373,8 @@ Khyota Wulluf
|
|||
Kitty Barnett
|
||||
VWR-19699
|
||||
STORM-288
|
||||
STORM-799
|
||||
STORM-800
|
||||
Kunnis Basiat
|
||||
VWR-82
|
||||
VWR-102
|
||||
|
|
|
|||
|
|
@ -805,6 +805,69 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const
|
|||
return ::getStringAfterToken(url, "://");
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryRegion Describes secondlife:///app/region/REGION_NAME/X/Y/Z URLs, e.g.
|
||||
// secondlife:///app/region/Ahern/128/128/0
|
||||
//
|
||||
LLUrlEntryRegion::LLUrlEntryRegion()
|
||||
{
|
||||
mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?",
|
||||
boost::regex::perl|boost::regex::icase);
|
||||
mMenuName = "menu_url_slurl.xml";
|
||||
mTooltip = LLTrans::getString("TooltipSLURL");
|
||||
}
|
||||
|
||||
std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
|
||||
{
|
||||
//
|
||||
// we handle SLURLs in the following formats:
|
||||
// - secondlife:///app/region/Place/X/Y/Z
|
||||
// - secondlife:///app/region/Place/X/Y
|
||||
// - secondlife:///app/region/Place/X
|
||||
// - secondlife:///app/region/Place
|
||||
//
|
||||
|
||||
LLSD path_array = LLURI(url).pathArray();
|
||||
S32 path_parts = path_array.size();
|
||||
|
||||
if (path_parts < 3) // no region name
|
||||
{
|
||||
llwarns << "Failed to parse url [" << url << "]" << llendl;
|
||||
return url;
|
||||
}
|
||||
|
||||
std::string label = unescapeUrl(path_array[2]); // region name
|
||||
|
||||
if (path_parts > 3) // secondlife:///app/region/Place/X
|
||||
{
|
||||
std::string x = path_array[3];
|
||||
label += " (" + x;
|
||||
|
||||
if (path_parts > 4) // secondlife:///app/region/Place/X/Y
|
||||
{
|
||||
std::string y = path_array[4];
|
||||
label += "," + y;
|
||||
|
||||
if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z
|
||||
{
|
||||
std::string z = path_array[5];
|
||||
label = label + "," + z;
|
||||
}
|
||||
}
|
||||
|
||||
label += ")";
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
std::string LLUrlEntryRegion::getLocation(const std::string &url) const
|
||||
{
|
||||
LLSD path_array = LLURI(url).pathArray();
|
||||
std::string region_name = unescapeUrl(path_array[2]);
|
||||
return region_name;
|
||||
}
|
||||
|
||||
//
|
||||
// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
|
||||
// secondlife:///app/teleport/Ahern/50/50/50/
|
||||
|
|
|
|||
|
|
@ -301,6 +301,18 @@ public:
|
|||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryRegion Describes a Second Life location Url, e.g.,
|
||||
/// secondlife:///app/region/Ahern/128/128/0
|
||||
///
|
||||
class LLUrlEntryRegion : public LLUrlEntryBase
|
||||
{
|
||||
public:
|
||||
LLUrlEntryRegion();
|
||||
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
|
||||
/*virtual*/ std::string getLocation(const std::string &url) const;
|
||||
};
|
||||
|
||||
///
|
||||
/// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g.,
|
||||
/// secondlife:///app/teleport/Ahern/50/50/50/
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ LLUrlRegistry::LLUrlRegistry()
|
|||
registerUrl(new LLUrlEntryGroup());
|
||||
registerUrl(new LLUrlEntryParcel());
|
||||
registerUrl(new LLUrlEntryTeleport());
|
||||
registerUrl(new LLUrlEntryRegion());
|
||||
registerUrl(new LLUrlEntryWorldMap());
|
||||
registerUrl(new LLUrlEntryObjectIM());
|
||||
registerUrl(new LLUrlEntryPlace());
|
||||
|
|
|
|||
|
|
@ -103,6 +103,45 @@ namespace tut
|
|||
ensure_equals(testname, url, expected);
|
||||
}
|
||||
|
||||
void dummyCallback(const std::string &url, const std::string &label, const std::string& icon)
|
||||
{
|
||||
}
|
||||
|
||||
void testLabel(const std::string &testname, LLUrlEntryBase &entry,
|
||||
const char *text, const std::string &expected)
|
||||
{
|
||||
boost::regex regex = entry.getPattern();
|
||||
std::string label = "";
|
||||
boost::cmatch result;
|
||||
bool found = boost::regex_search(text, result, regex);
|
||||
if (found)
|
||||
{
|
||||
S32 start = static_cast<U32>(result[0].first - text);
|
||||
S32 end = static_cast<U32>(result[0].second - text);
|
||||
std::string url = std::string(text+start, end-start);
|
||||
label = entry.getLabel(url, boost::bind(dummyCallback, _1, _2, _3));
|
||||
}
|
||||
ensure_equals(testname, label, expected);
|
||||
}
|
||||
|
||||
void testLocation(const std::string &testname, LLUrlEntryBase &entry,
|
||||
const char *text, const std::string &expected)
|
||||
{
|
||||
boost::regex regex = entry.getPattern();
|
||||
std::string location = "";
|
||||
boost::cmatch result;
|
||||
bool found = boost::regex_search(text, result, regex);
|
||||
if (found)
|
||||
{
|
||||
S32 start = static_cast<U32>(result[0].first - text);
|
||||
S32 end = static_cast<U32>(result[0].second - text);
|
||||
std::string url = std::string(text+start, end-start);
|
||||
location = entry.getLocation(url);
|
||||
}
|
||||
ensure_equals(testname, location, expected);
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
|
|
@ -697,4 +736,114 @@ namespace tut
|
|||
"<nolink>My Object</nolink>",
|
||||
"My Object");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<13>()
|
||||
{
|
||||
//
|
||||
// test LLUrlEntryRegion - secondlife:///app/region/<location> URLs
|
||||
//
|
||||
LLUrlEntryRegion url;
|
||||
|
||||
// Regex tests.
|
||||
testRegex("no valid region", url,
|
||||
"secondlife:///app/region/",
|
||||
"");
|
||||
|
||||
testRegex("invalid coords", url,
|
||||
"secondlife:///app/region/Korea2/a/b/c",
|
||||
"secondlife:///app/region/Korea2/"); // don't count invalid coords
|
||||
|
||||
testRegex("Ahern (50,50,50) [1]", url,
|
||||
"secondlife:///app/region/Ahern/50/50/50/",
|
||||
"secondlife:///app/region/Ahern/50/50/50/");
|
||||
|
||||
testRegex("Ahern (50,50,50) [2]", url,
|
||||
"XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
|
||||
"secondlife:///app/region/Ahern/50/50/50/");
|
||||
|
||||
testRegex("Ahern (50,50,50) [3]", url,
|
||||
"XXX secondlife:///app/region/Ahern/50/50/50 XXX",
|
||||
"secondlife:///app/region/Ahern/50/50/50");
|
||||
|
||||
testRegex("Ahern (50,50,50) multicase", url,
|
||||
"XXX secondlife:///app/region/Ahern/50/50/50/ XXX",
|
||||
"secondlife:///app/region/Ahern/50/50/50/");
|
||||
|
||||
testRegex("Ahern (50,50) [1]", url,
|
||||
"XXX secondlife:///app/region/Ahern/50/50/ XXX",
|
||||
"secondlife:///app/region/Ahern/50/50/");
|
||||
|
||||
testRegex("Ahern (50,50) [2]", url,
|
||||
"XXX secondlife:///app/region/Ahern/50/50 XXX",
|
||||
"secondlife:///app/region/Ahern/50/50");
|
||||
|
||||
// DEV-21577: In-world SLURLs containing "(" or ")" are not treated as a hyperlink in chat
|
||||
testRegex("Region with brackets", url,
|
||||
"XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX",
|
||||
"secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30");
|
||||
|
||||
// DEV-35459: SLURLs and teleport Links not parsed properly
|
||||
testRegex("Region with quote", url,
|
||||
"XXX secondlife:///app/region/A'ksha%20Oasis/41/166/701 XXX",
|
||||
"secondlife:///app/region/A%27ksha%20Oasis/41/166/701");
|
||||
|
||||
// Rendering tests.
|
||||
testLabel("Render /app/region/Ahern/50/50/50/", url,
|
||||
"secondlife:///app/region/Ahern/50/50/50/",
|
||||
"Ahern (50,50,50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/50/50/50", url,
|
||||
"secondlife:///app/region/Ahern/50/50/50",
|
||||
"Ahern (50,50,50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/50/50/", url,
|
||||
"secondlife:///app/region/Ahern/50/50/",
|
||||
"Ahern (50,50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/50/50", url,
|
||||
"secondlife:///app/region/Ahern/50/50",
|
||||
"Ahern (50,50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/50/", url,
|
||||
"secondlife:///app/region/Ahern/50/",
|
||||
"Ahern (50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/50", url,
|
||||
"secondlife:///app/region/Ahern/50",
|
||||
"Ahern (50)");
|
||||
|
||||
testLabel("Render /app/region/Ahern/", url,
|
||||
"secondlife:///app/region/Ahern/",
|
||||
"Ahern");
|
||||
|
||||
testLabel("Render /app/region/Ahern/ within context", url,
|
||||
"XXX secondlife:///app/region/Ahern/ XXX",
|
||||
"Ahern");
|
||||
|
||||
testLabel("Render /app/region/Ahern", url,
|
||||
"secondlife:///app/region/Ahern",
|
||||
"Ahern");
|
||||
|
||||
testLabel("Render /app/region/Ahern within context", url,
|
||||
"XXX secondlife:///app/region/Ahern XXX",
|
||||
"Ahern");
|
||||
|
||||
testLabel("Render /app/region/Product%20Engine/", url,
|
||||
"secondlife:///app/region/Product%20Engine/",
|
||||
"Product Engine");
|
||||
|
||||
testLabel("Render /app/region/Product%20Engine", url,
|
||||
"secondlife:///app/region/Product%20Engine",
|
||||
"Product Engine");
|
||||
|
||||
// Location parsing texts.
|
||||
testLocation("Location /app/region/Ahern/50/50/50/", url,
|
||||
"secondlife:///app/region/Ahern/50/50/50/",
|
||||
"Ahern");
|
||||
|
||||
testLocation("Location /app/region/Product%20Engine", url,
|
||||
"secondlife:///app/region/Product%20Engine",
|
||||
"Product Engine");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
virtual ~LLInspectToast();
|
||||
|
||||
/*virtual*/ void onOpen(const LLSD& notification_id);
|
||||
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
|
||||
private:
|
||||
void onToastDestroy(LLToast * toast);
|
||||
|
||||
|
|
@ -73,6 +74,7 @@ LLInspectToast::~LLInspectToast()
|
|||
LLTransientFloaterMgr::getInstance()->removeControlView(this);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLInspectToast::onOpen(const LLSD& notification_id)
|
||||
{
|
||||
LLInspect::onOpen(notification_id);
|
||||
|
|
@ -103,6 +105,15 @@ void LLInspectToast::onOpen(const LLSD& notification_id)
|
|||
LLUI::positionViewNearMouse(this);
|
||||
}
|
||||
|
||||
// virtual
|
||||
BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
// We don't like the way LLInspect handles tooltips
|
||||
// (black tooltips look weird),
|
||||
// so force using the default implementation (STORM-511).
|
||||
return LLFloater::handleToolTip(x, y, mask);
|
||||
}
|
||||
|
||||
void LLInspectToast::onToastDestroy(LLToast * toast)
|
||||
{
|
||||
closeFloater(false);
|
||||
|
|
|
|||
|
|
@ -341,10 +341,11 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()
|
|||
if(getAvatarId().notNull())
|
||||
{
|
||||
LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
|
||||
}
|
||||
}
|
||||
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -758,10 +759,11 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile()
|
|||
if(getAvatarId().notNull())
|
||||
{
|
||||
LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
|
||||
}
|
||||
}
|
||||
|
||||
if(LLVoiceClient::instanceExists())
|
||||
{
|
||||
LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,22 +140,25 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
|
|||
typedef std::vector<observer_multimap_t::iterator> deadlist_t;
|
||||
deadlist_t dead_iters;
|
||||
|
||||
observer_multimap_t::iterator oi;
|
||||
observer_multimap_t::iterator start = observers.lower_bound(parcel_data.parcel_id);
|
||||
observer_multimap_t::iterator oi = observers.lower_bound(parcel_data.parcel_id);
|
||||
observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id);
|
||||
|
||||
for (oi = start; oi != end; ++oi)
|
||||
while (oi != end)
|
||||
{
|
||||
LLRemoteParcelInfoObserver * observer = oi->second.get();
|
||||
// increment the loop iterator now since it may become invalid below
|
||||
observer_multimap_t::iterator cur_oi = oi++;
|
||||
|
||||
LLRemoteParcelInfoObserver * observer = cur_oi->second.get();
|
||||
if(observer)
|
||||
{
|
||||
// may invalidate cur_oi if the observer removes itself
|
||||
observer->processParcelInfo(parcel_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the handle points to an expired observer, so don't keep it
|
||||
// around anymore
|
||||
dead_iters.push_back(oi);
|
||||
dead_iters.push_back(cur_oi);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
|
|||
from << from_name << "/" << groupData.mName;
|
||||
LLTextBox* pTitleText = getChild<LLTextBox>("title");
|
||||
pTitleText->setValue(from.str());
|
||||
pTitleText->setToolTip(from.str());
|
||||
|
||||
//message subject
|
||||
const std::string& subject = payload["subject"].asString();
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@
|
|||
</expandable_text>
|
||||
</panel>
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
height="15"
|
||||
font.style="BOLD"
|
||||
font="SansSerifMedium"
|
||||
|
|
@ -200,7 +200,7 @@
|
|||
use_ellipses="true"
|
||||
/>
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
font.style="BOLD"
|
||||
height="10"
|
||||
layout="topleft"
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
<text_editor
|
||||
allow_scroll="false"
|
||||
bg_visible="false"
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
h_pad="0"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
width="300"
|
||||
word_wrap="true" />
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
font.style="BOLD"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
|
|
@ -250,7 +250,7 @@
|
|||
<text_editor
|
||||
allow_scroll="false"
|
||||
bg_visible="false"
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
h_pad="0"
|
||||
height="28"
|
||||
layout="topleft"
|
||||
|
|
@ -266,7 +266,7 @@
|
|||
Linden.
|
||||
</text_editor>
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
font.style="BOLD"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
|
|
@ -277,7 +277,7 @@
|
|||
value="Partner:"
|
||||
width="300" />
|
||||
<panel
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
height="15"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
|
|
@ -285,7 +285,7 @@
|
|||
top_pad="0"
|
||||
width="300">
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
height="10"
|
||||
initial_value="(retrieving)"
|
||||
layout="topleft"
|
||||
|
|
@ -297,7 +297,7 @@
|
|||
width="300" />
|
||||
</panel>
|
||||
<text
|
||||
follows="left|top"
|
||||
follows="left|top|right"
|
||||
font.style="BOLD"
|
||||
height="13"
|
||||
layout="topleft"
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
control_name="AllowMultipleViewers"
|
||||
follows="top|left"
|
||||
height="15"
|
||||
label="Allow Multiple Viewer"
|
||||
label="Allow Multiple Viewers"
|
||||
layout="topleft"
|
||||
left="30"
|
||||
name="allow_multiple_viewer_check"
|
||||
|
|
|
|||
Loading…
Reference in New Issue