Compare commits

...

80 Commits

Author SHA1 Message Date
Liru Færs
9548270306 Buncha tinies
Link name in inventory offer received chat message
Fix shupdate compile missing ; and include from two commits ago
Update links used in menu_viewer.xml, I have things to do today...
And move inventory button on toolbar to between favs and received
2020-02-07 09:00:03 -05:00
Liru Færs
44aec1384a Fix crash in object weights when null selection 2020-02-07 08:03:57 -05:00
Liru Færs
42139835d5 Redo update checker responder to be more like unstable branch 2020-02-07 08:02:44 -05:00
Liru Færs
49f0f8e28f [XP Tools] Further UI beautification
Refix all the panels that weren't good enough.
Fix settingss and default rects
Remove unused
Fix toolbar prefs floater
Use text editors for "URLs" we can't control, they resolve nicer anyway
Fix Texture Ctrl on profile not popping out on click
Fix Maturity string on profile not displaying
Also update about floater credits according to modern data.
2020-02-07 07:48:58 -05:00
Inusaito Sayori
36b75b2398 A Massive Experience Tools (and Unstable Branch) Merge
[XP Tools] Initial merge Cherry Pick

Also modernize llfloaterauction internally, but leave the ui the same for now.
Breaks out script_question_mute() in llviewermessage.cpp to better sync with upstream
Adds support for UnknownScriptQuestion notification (translators need to translate this one~)
RLVa note: Rewrote RLVa permissions handling block just a bit.
Added 13 new capabilities from the XP Tools, I doubt all of them really exist.
Minor update to LLComboBox, decided against implementing LLIconsComboBox for now.
Modified LLExperienceLog::notify to lookup names and display them along with the slurls since our editors don't do that automatically.
Experience tweak: Changed a few notify's to notifytips so that we can click the links to experience profiles from chat instead of via hacked in buttons
Migrated LLFloaterCompileQueue to a proper Instance Tracker so we can call getKey
Modernized LLSD, gives us reverse iterators and the new debugging impl. We needed the reverse iterators.
Experience tweak: Added virtual destructors to responders.
Updated llhandle.h to allow calling getDerivedHandle in public.
Updated LLScrollContainer and LLScrollBar to be more modern.
Added LLFlatListView/flat_list_view from upstream - these don't seem work though?
Added some newer login/logout strings to strings.xml
Thanks for the default timeout policies, Aleric~
To avoid needing to scroll through tabs, about land tabs now are as big as they need to be to display their labels, same on groups
Group Members and Roles has been renamed to just Members because this allows the new Experiences tab enough room to display.
Thanks to Henri Beauchamp (Cool VL Viewer) for the setupList augmentation. (without it, I'd still be stuck)
Thanks to Shyotl for the helpsies~
Added the LSL constants, events, and functions that LL neglected to put in.
Added click callbacks and name lookups for profile linky texts~

Merge is up to 22b4cdc
Old TODO: Get the uis looking nice (profiles? Experiences... floater) - done
Old TODO: Make sure flatlistviews look okay... - Not using
Old TODO: Fix LLFloaterExperiencePicker, right now the panel does not show. - unsure
Old TODO: Remove the llfloaterabout.cpp change. - done

Merges llexperiencecache with upstream and unstable
Introduces LLCoroResponder, TODO: Make everything use this.
Updates Reporter floater to the latest, supports the new cap thingy

Also adds these commits/changes:
[XPTools] Double clicking experiences in namelists should open the profile
Add List.CopyNames support for Experiences
[XP Tools] Some UI work, I'll do more later
[XPTools] More UI Stuff, Later is now!
Allow getSLURL for experiences
WIP Experience list menu
Also make EXPERIENCE > OBJECT, because mainline started OBJECT already
[XPTools] Add Experience support to Name UI
[XPTools] Fix experience profile UI 9c3067e843265587e91c659200a8d783acf2d9b2
[XPTools] Fix experience location showing "last" and getting set to "last"
[XPTools] Move Experiences floater from view menu to world menu
[XPTools] Fix up more UI
[XPTools] Fix experiences panels
[XPTools] Hide pieces of the Experiences menu when they're not usable
[XPTools] More UI work, mostly to get the menus working
[XPTools] The events list is for events, not experiences, remove menu

# Conflicts:
#	indra/llcommon/llsd.cpp - merge with unstable branch
#	indra/llmessage/message_prehash.cpp
#	indra/llmessage/message_prehash.h
#	indra/llui/llscrollbar.cpp
#	indra/llui/llscrollcontainer.cpp
#	indra/llui/llurlentry.cpp
#	indra/llui/llurlregistry.cpp
#	indra/newview/app_settings/keywords.ini
#	indra/newview/app_settings/settings.xml
#	indra/newview/llappviewer.cpp
#	indra/newview/llappviewer.h
#	indra/newview/llassetuploadresponders.cpp
#	indra/newview/llcompilequeue.* - merge stable
#	indra/newview/llfloaterabout.cpp
#	indra/newview/llfloaterland.* - merge unstable
#	indra/newview/llfloaterproperties.cpp
#	indra/newview/llfloaterregioninfo.* - merge unstable
#	indra/newview/llmenucommands.cpp - merge unstable
#	indra/newview/llpreviewscript.cpp - merge unstable
#	indra/newview/llviewermessage.cpp - merge unstable
#	indra/newview/llviewerregion.cpp - merge unstable
#	indra/newview/skins/default/textures/textures.xml - merge unstable
#	indra/newview/skins/default/xui/en-us/strings.xml - merge unstable
2020-02-04 21:18:47 -05:00
Liru Færs
9a53824d6d Move click_for_profile into LLNameUI base for use in nameboxes
This allows having a linked name text on profiles without it stealing mouse
2020-01-31 14:32:45 -05:00
Router Gray
a9e2672820 [Lib] Update Linux Fmod to 2.00.07 2020-01-22 01:40:52 -06:00
Router Gray
138cf5d4f8 [AIS] Apparently friending a class isn't friendly enough. 2020-01-22 01:38:40 -06:00
Liru Færs
4b2e358783 Sync LLInventoryModel and LLViewerInventory with upstream 2020-01-21 03:18:44 -05:00
Liru Færs
851b3659ee Improve AISv3 code to retry less aggressively
Syncs LLAISAPI with upstream alchemy
Thanks to Kitty Barnett for Appearance-SyncAttach patch
Fixes typos, uses more modern C++ features,
Accounts for VERSION_UNKNOWN so the viewer won't get stuck
Adds in support for 410 GONE response
No longer retries on empty map, malformed response.
2020-01-21 03:18:43 -05:00
Liru Færs
27d4e05f2b Prevent crash 37 2020-01-21 03:18:43 -05:00
Liru Færs
deade4438d Fix login favorites and copy Landmark SLURL missing z-axis (height) 2020-01-21 03:18:43 -05:00
Liru Færs
deafc6814d Fix crashes from badly formed json responses (LL's fault)
Adds LlsdFromJsonString, an exception-free wrapper for parsing json strings
LLSD objects that failed to parse through this will be the type Undefined.

Fixes crashes 36, 1G, 33, 21, and 3A.
2020-01-21 03:18:43 -05:00
Liru Færs
1fd6e91c68 Clean up update checker dependencies 2020-01-21 03:18:42 -05:00
Liru Færs
67126ab494 Wooops, our update checker is broken since the beta started! 2020-01-21 03:18:42 -05:00
Router Gray
e3318fb0d2 Add missing Nvidia GTX cards to gpu table. Used Cool VL Viewer's source, thanks Henri Beauchamp 2020-01-20 16:55:40 -06:00
Liru Færs
e9d28ee5c1 Inventory offers should link offerer avatar/group name 2020-01-17 23:44:41 -05:00
Liru Færs
2ffc99aecf Clean up useless code 2020-01-17 23:35:55 -05:00
Liru Færs
450afff50b [VMM] Drop zone is no longer WIP, and neither are the tabs
Searching tabs is still kinda wonky though... This needs investigation
2020-01-17 17:20:31 -05:00
Liru Færs
570b0d3c5b [VMM] Make the marketplace panel a dropzone, drag and drop anywhere~
Fixes Deltek's issue with not being able to drop in the zone
nor in the empty space where there are not folders in the listings
2020-01-17 17:19:01 -05:00
Liru Færs
09daa2a865 [VMM] Background transparency is important, even in marketplace drop zone 2020-01-17 17:14:25 -05:00
Liru Færs
e97837e103 Friendship Offered should link receiver's name 2020-01-17 14:33:38 -05:00
Liru Færs
84add2d864 This comment forgot to be saved 2020-01-17 10:54:07 -05:00
Liru Færs
4c224def62 Update FMOD Studio 2020-01-17 02:29:52 -05:00
Liru Færs
2242a1d101 Fix a bunch of disconnectNeighbor crashes in LLSurface 2020-01-17 02:27:56 -05:00
Liru Færs
b957c0930d Fix dumb in LLSurface, don't do dumb math 2020-01-17 02:27:48 -05:00
Liru Færs
f7434711ad [Follow] Reset No Progress count when target's position changes 2020-01-17 02:26:40 -05:00
Liru Færs
5f0b23edd7 [Follow] Try to sit on far away objects by moving closer
Groundsit if that still fails
2020-01-17 02:25:45 -05:00
Liru Færs
2eff62ad0d [Follow] Fix orbiting leader after follow sitting and standing up 2020-01-17 01:32:05 -05:00
Liru Færs
686795618a If object sitting while following, bypass follow logic block 2020-01-17 01:30:39 -05:00
Liru Færs
5c8c5a2c45 Condense autopilot no progress code into getAutoPilotNoProgress() 2020-01-17 00:04:31 -05:00
Liru Færs
d98b99f7b3 [Follow] Fall into walking code if RLV Sit restricted
Mostly space changes
2020-01-16 17:47:17 -05:00
Liru Færs
8d472a9c7b Rearrange some Follow code 2020-01-16 17:43:14 -05:00
Liru Færs
3747d79143 [Follow] Fly if we aren't rendering the avatar 2020-01-16 17:40:50 -05:00
Liru Færs
910a5557ab Sync some code in hopes to squish Marketplace wire chewed popups
A query url will no longer be built in making the request
The status of marketplace will no longer get reset to uninitialized upon
region change.
Merchant status will no longer be requested on regions without the DD cap
2020-01-16 17:10:08 -05:00
Liru Færs
8163448a6c [RLVa] Always show your own hover tip 2020-01-15 23:55:42 -05:00
Liru Færs
ac0e93dcad People don't seem to know what an ARC is... it's Complexity 2020-01-15 23:55:13 -05:00
Liru Færs
ed420c3645 Add Edit and Add to Selection to Object UI menus 2020-01-15 19:46:49 -05:00
Liru Færs
b872860443 Fix crash in land floater init when null region (disconnected?)
Fixes crash 2E
Cleans up code
2020-01-15 14:00:00 -05:00
Liru Færs
992f4c7b5d Modernize/sync LLSpeakers code 2020-01-15 12:57:58 -05:00
Liru Færs
8f15478ba4 Condense code~ 2020-01-15 12:56:56 -05:00
Liru Færs
1c371e7be6 Allow touching multiple objects in succession 2020-01-14 19:37:53 -05:00
Liru Færs
937c80f694 Fix an oopsie in Debug Settings, Thanks for the heads up, Yuriko 2020-01-14 15:53:42 -05:00
Liru Færs
15bd41bd71 Add Touch to object ui menus 2020-01-14 15:52:58 -05:00
Liru Færs
b9156b7955 Combine send_ObjectDeGrab and send_ObjectGrab repetitive code 2020-01-14 10:49:46 -05:00
Liru Færs
623a484ae3 Woops, gotta do a char array for that, also set errno to 0 2020-01-13 18:35:08 -05:00
Liru Færs
2ace698101 [Follow] Automatically accept Teleport Requests/Offers from the leader 2020-01-13 02:20:33 -05:00
Liru Færs
34e0c722e7 Don't cancel autopilot when escaping out of customize appearance 2020-01-13 01:34:06 -05:00
Liru Færs
82ee06a6bd Add Find on Map to avatar UI menus 2020-01-13 01:33:26 -05:00
Liru Færs
584ee8fffe const byref autopilot accessors 2020-01-13 00:29:51 -05:00
Liru Færs
d80d232ee5 Don't cancel follow if the target disappears, wait for them 2020-01-12 23:57:20 -05:00
Liru Færs
de47736038 Ignore object kills if our region is null
Fixes crash 1R
2020-01-12 20:06:01 -05:00
Liru Færs
0da16e6034 Some days, I scream in the faces of cats 2020-01-12 16:27:19 -05:00
Liru Færs
6c9a156610 Maybe fix pusssycat's issue with clicking for group profile being broken 2020-01-12 14:47:52 -05:00
Liru Færs
1726c27078 Fix for Linux file rename failures, thanks Taya and Router! 2020-01-12 13:23:02 -05:00
Liru Færs
64b43a47b5 Clean up ScriptCounter code more 2020-01-12 12:33:10 -05:00
Liru Færs
8005a58ed5 Script Counting on an avatar now shows their SLURL, instead of just a name 2020-01-11 21:53:29 -05:00
Liru Færs
d1d42701f5 Fix taya's linux crash, thanks to taya and router!
Crash was due to invalidated iterator
2020-01-11 21:00:16 -05:00
Liru Færs
c57fceff17 Modernizing scriptcounter code 2020-01-11 20:23:31 -05:00
Liru Færs
265336463d Add FMOD Logo to login screen to comply with licensing
Adds code to hide the new UI when compiled without FMOD Studio
2020-01-11 04:32:42 -05:00
Liru Færs
3ba1c88672 Remove reference to dead control 2020-01-11 03:01:28 -05:00
Liru Færs
90e6afe159 Merge branch 'master' of git://github.com/Shyotl/SingularityViewer 2020-01-10 17:14:39 -05:00
Liru Færs
3209507b6c [Follow] Sit if target is sitting, stand when they stand
Does object and ground sitting.
May fly to sitting target if they're in air
Ground sits as close as it can get if cannot reach ground sitting target

Optimizes following when within desired range of target

Moves sitting/standing autopilot cancels to more proper places
2020-01-10 17:13:28 -05:00
Liru Færs
fa97d8497a [Follow] If the user decides to sit/stand, that should cancel following 2020-01-10 16:47:52 -05:00
Liru Færs
a687273d57 Default column sorting to list sort_ascending attribute value 2020-01-10 16:07:37 -05:00
Liru Færs
28f13b806c Some harmless reorganization 2020-01-10 16:06:44 -05:00
Liru Færs
f1342d7bb8 Fix Name List xml processing (and typing into them to +find names!)
LLNameListCtrl::fromXML was ancient,
and LLScrollListCtrl::fromXML had been getting updated
but that processing should be done in a common virtual function so we have
a valid hierarchy! This fixes that!
Now all of the modern amenities added to scroll lists are in name lists.
2020-01-10 15:49:12 -05:00
Liru Færs
c3428c6d57 When chat scrolls, IDBearer URL menus shouldn't lead to the wrong place
Optimizes away multiple iterations over scroll lists and
multiple parsings of urls to determine the target(s)
At the cost of the last selection being stored statically in a vector

Removes virtual LFIDBearer::getNumSelected
2020-01-10 14:46:54 -05:00
Liru Færs
0efddbd9ff Add Pay to Object UI Menus 2020-01-10 13:12:13 -05:00
Liru Færs
be0aba4bfa Woops, fix this 2020-01-10 03:34:57 -05:00
Liru Færs
c3f03b6bbf [Follow] Specify that Follow has been cancelled, with Cancelled notice 2020-01-10 03:11:19 -05:00
Liru Færs
e15839a2cb Move autoPilot Agent Avatar Valid check to beginning 2020-01-10 02:42:48 -05:00
Shyotl
e0efbd7d26 Fix two race conditions in meshrepo. 2020-01-10 00:09:35 -06:00
Liru Færs
8e57288819 Stand Up by user should cancel autopilot 2020-01-10 01:01:38 -05:00
Liru Færs
107f512545 Teleport notifications now use avatar slurls 2020-01-09 22:53:16 -05:00
Liru Færs
14dc348179 Add Sit On to Object UI Menus
Breaks handle_object_sit out of handle_object_sit_or_stand,
parameterizes offset so that one doesn't need to select a side
still respects RLV, yay~
2020-01-09 22:14:06 -05:00
Liru Færs
eccbd98d79 Change some enables to visibles 2020-01-09 21:18:31 -05:00
Liru Færs
a5115aa69e Fix Crash T, someone broke their install, but we should gracefully exit 2020-01-09 12:41:43 -05:00
Liru Færs
327574db7c Cancel autopilot when user initiates a goto 2020-01-08 22:32:17 -05:00
Liru Færs
8b4a29cbd3 Break simulator autopilot out into its own function 2020-01-08 22:31:18 -05:00
188 changed files with 14642 additions and 3866 deletions

View File

@@ -874,11 +874,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>54dbd41322a08a1fc333ca6d96af5502</string>
<string>ccd495598894c8e2e541a348015ee3f0</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>/opt/devel/secondlife/pkg/fmodstudio-2.00.02.191991250-linux64-191991250.tar.bz2</string>
<string>/opt/devel/fmodstudio-2.00.07.200182252-linux64-200182252.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -888,11 +888,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>e0e87e0423fa42e4d2997b47b92eac6e</string>
<string>22daed7c860daaef217eb8d90dfc1119</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.00.03.192211030-windows-192211030.tar.bz2</string>
<string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.00.06.3-windows-3.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@@ -902,18 +902,18 @@
<key>archive</key>
<map>
<key>hash</key>
<string>c2e55e1bfef7e066a0e40867a64b4cce</string>
<string>ccf7b1935743df55244139c4323c0465</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows64/fmodstudio-2.00.03.192211029-windows64-192211029.tar.bz2</string>
<string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows64/fmodstudio-2.00.06.3-windows64-3.tar.bz2</string>
</map>
<key>name</key>
<string>windows64</string>
</map>
</map>
<key>version</key>
<string>2.00.03.192211300</string>
<string>2.00.06.3</string>
</map>
<key>fonts</key>
<map>

View File

@@ -281,6 +281,11 @@ int LLFile::rename_nowarn(const std::string& filename, const std::string& newnam
int rc = _wrename(utf16filename.c_str(),utf16newname.c_str());
#else
int rc = ::rename(filename.c_str(),newname.c_str());
if (rc == -1 && errno == EXDEV)
{
rc = std::system(("mv '" + filename + "' '" + newname + '\'').data());
errno = 0;
}
#endif
return rc;
}

View File

@@ -126,9 +126,9 @@ public:
virtual Date asDate() const { return LLDate(); }
virtual URI asURI() const { return LLURI(); }
virtual const Binary& asBinary() const { static const std::vector<U8> empty; return empty; }
virtual const String& asStringRef() const { static const std::string empty; return empty; }
virtual const String& asStringRef() const { static const std::string empty; return empty; }
virtual bool has(const String&) const { return false; }
virtual LLSD get(const String&) const { return LLSD(); }
virtual LLSD getKeys() const { return LLSD::emptyArray(); }
@@ -183,10 +183,11 @@ namespace
public:
ImplBase(DataRef value) : mValue(value) { }
virtual LLSD::Type type() const { return T; }
LLSD::Type type() const override { return T; }
using LLSD::Impl::assign; // Unhiding base class virtuals...
virtual void assign(LLSD::Impl*& var, DataRef value) {
void assign(LLSD::Impl*& var, DataRef value) override
{
if (shared())
{
Impl::assign(var, value);
@@ -205,10 +206,10 @@ namespace
public:
ImplBoolean(LLSD::Boolean v) : Base(v) { }
virtual LLSD::Boolean asBoolean() const { return mValue; }
virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; }
virtual LLSD::Real asReal() const { return mValue ? 1 : 0; }
virtual LLSD::String asString() const;
LLSD::Boolean asBoolean() const override { return mValue; }
LLSD::Integer asInteger() const override { return mValue ? 1 : 0; }
LLSD::Real asReal() const override { return mValue ? 1 : 0; }
LLSD::String asString() const override;
};
LLSD::String ImplBoolean::asString() const
@@ -226,10 +227,10 @@ namespace
public:
ImplInteger(LLSD::Integer v) : Base(v) { }
virtual LLSD::Boolean asBoolean() const { return mValue != 0; }
virtual LLSD::Integer asInteger() const { return mValue; }
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
LLSD::Boolean asBoolean() const override { return mValue != 0; }
LLSD::Integer asInteger() const override { return mValue; }
LLSD::Real asReal() const override { return mValue; }
LLSD::String asString() const override;
};
LLSD::String ImplInteger::asString() const
@@ -242,10 +243,10 @@ namespace
public:
ImplReal(LLSD::Real v) : Base(v) { }
virtual LLSD::Boolean asBoolean() const;
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const { return mValue; }
virtual LLSD::String asString() const;
LLSD::Boolean asBoolean() const override;
LLSD::Integer asInteger() const override;
LLSD::Real asReal() const override { return mValue; }
LLSD::String asString() const override;
};
LLSD::Boolean ImplReal::asBoolean() const
@@ -264,15 +265,15 @@ namespace
public:
ImplString(const LLSD::String& v) : Base(v) { }
virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); }
virtual LLSD::Integer asInteger() const;
virtual LLSD::Real asReal() const;
virtual LLSD::String asString() const { return mValue; }
virtual LLSD::UUID asUUID() const { return LLUUID(mValue); }
virtual LLSD::Date asDate() const { return LLDate(mValue); }
virtual LLSD::URI asURI() const { return LLURI(mValue); }
virtual int size() const { return mValue.size(); }
virtual const LLSD::String& asStringRef() const { return mValue; }
LLSD::Boolean asBoolean() const override { return !mValue.empty(); }
LLSD::Integer asInteger() const override;
LLSD::Real asReal() const override;
LLSD::String asString() const override { return mValue; }
LLSD::UUID asUUID() const override { return LLUUID(mValue); }
LLSD::Date asDate() const override { return LLDate(mValue); }
LLSD::URI asURI() const override { return LLURI(mValue); }
int size() const override { return mValue.size(); }
const LLSD::String& asStringRef() const override { return mValue; }
};
LLSD::Integer ImplString::asInteger() const
@@ -308,8 +309,8 @@ namespace
public:
ImplUUID(const LLSD::UUID& v) : Base(v) { }
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::UUID asUUID() const { return mValue; }
LLSD::String asString() const override { return mValue.asString(); }
LLSD::UUID asUUID() const override { return mValue; }
};
@@ -321,16 +322,17 @@ namespace
: ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v)
{ }
virtual LLSD::Integer asInteger() const
LLSD::Integer asInteger() const override
{
return (LLSD::Integer)(mValue.secondsSinceEpoch());
}
virtual LLSD::Real asReal() const
LLSD::Real asReal() const override
{
return mValue.secondsSinceEpoch();
}
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::Date asDate() const { return mValue; }
LLSD::String asString() const override { return mValue.asString(); }
LLSD::Date asDate() const override { return mValue; }
};
@@ -340,8 +342,8 @@ namespace
public:
ImplURI(const LLSD::URI& v) : Base(v) { }
virtual LLSD::String asString() const{ return mValue.asString(); }
virtual LLSD::URI asURI() const { return mValue; }
LLSD::String asString() const override { return mValue.asString(); }
LLSD::URI asURI() const override { return mValue; }
};
@@ -351,7 +353,7 @@ namespace
public:
ImplBinary(const LLSD::Binary& v) : Base(v) { }
virtual const LLSD::Binary& asBinary() const{ return mValue; }
const LLSD::Binary& asBinary() const override { return mValue; }
};
@@ -368,33 +370,33 @@ namespace
public:
ImplMap() { }
virtual ImplMap& makeMap(LLSD::Impl*&);
ImplMap& makeMap(LLSD::Impl*&) override;
virtual LLSD::Type type() const { return LLSD::TypeMap; }
LLSD::Type type() const override { return LLSD::TypeMap; }
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
LLSD::Boolean asBoolean() const override { return !mData.empty(); }
virtual bool has(const LLSD::String&) const;
bool has(const LLSD::String&) const override;
using LLSD::Impl::get; // Unhiding get(LLSD::Integer)
using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer)
using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer)
virtual LLSD get(const LLSD::String&) const;
virtual LLSD getKeys() const;
LLSD get(const LLSD::String&) const override;
LLSD getKeys() const override;
void insert(const LLSD::String& k, const LLSD& v);
virtual void erase(const LLSD::String&);
void erase(const LLSD::String&) override;
LLSD& ref(const LLSD::String&);
virtual const LLSD& ref(const LLSD::String&) const;
const LLSD& ref(const LLSD::String&) const override;
virtual int size() const { return mData.size(); }
int size() const override { return mData.size(); }
LLSD::map_iterator beginMap() { return mData.begin(); }
LLSD::map_iterator endMap() { return mData.end(); }
virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); }
virtual LLSD::map_const_iterator endMap() const { return mData.end(); }
LLSD::map_const_iterator beginMap() const override { return mData.begin(); }
LLSD::map_const_iterator endMap() const override { return mData.end(); }
virtual void dumpStats() const;
virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
void dumpStats() const override;
void calcStats(S32 type_counts[], S32 share_counts[]) const override;
};
ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
@@ -481,7 +483,7 @@ namespace
{
//std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl;
Impl::calcStats((*iter).second, type_counts, share_counts);
iter++;
++iter;
}
// Add in the values for this map
@@ -502,32 +504,32 @@ namespace
public:
ImplArray() { }
virtual ImplArray& makeArray(Impl*&);
ImplArray& makeArray(Impl*&) override;
virtual LLSD::Type type() const { return LLSD::TypeArray; }
LLSD::Type type() const override { return LLSD::TypeArray; }
virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
LLSD::Boolean asBoolean() const override { return !mData.empty(); }
using LLSD::Impl::get; // Unhiding get(LLSD::String)
using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
virtual int size() const;
virtual LLSD get(LLSD::Integer) const;
int size() const override;
LLSD get(LLSD::Integer) const override;
void set(LLSD::Integer, const LLSD&);
void insert(LLSD::Integer, const LLSD&);
LLSD& append(const LLSD&);
virtual void erase(LLSD::Integer);
void erase(LLSD::Integer) override;
LLSD& ref(LLSD::Integer);
virtual const LLSD& ref(LLSD::Integer) const;
const LLSD& ref(LLSD::Integer) const override;
LLSD::array_iterator beginArray() { return mData.begin(); }
LLSD::array_iterator endArray() { return mData.end(); }
LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); }
LLSD::reverse_array_iterator rendArray() { return mData.rend(); }
virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); }
virtual LLSD::array_const_iterator endArray() const { return mData.end(); }
LLSD::array_const_iterator beginArray() const override { return mData.begin(); }
LLSD::array_const_iterator endArray() const override { return mData.end(); }
virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
void calcStats(S32 type_counts[], S32 share_counts[]) const override;
};
ImplArray& ImplArray::makeArray(Impl*& var)
@@ -631,7 +633,7 @@ namespace
while (iter != endArray())
{ // Add values for all items held in the array
Impl::calcStats((*iter), type_counts, share_counts);
iter++;
++iter;
}
// Add in the values for this array
@@ -703,7 +705,7 @@ void LLSD::Impl::assign(Impl*& var, const Impl* other)
void LLSD::Impl::assignUndefined(Impl*& var)
{
reset(var, 0);
reset(var, nullptr);
}
void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v)
@@ -779,7 +781,7 @@ void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const
S32 tp = S32(type());
if (0 <= tp && tp < LLSD::TypeLLSDNumTypes)
{
type_counts[tp]++;
type_counts[tp]++;
if (shared())
{
share_counts[tp]++;
@@ -813,10 +815,10 @@ namespace
}
LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; }
LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
LLSD::LLSD() : impl(nullptr) { ALLOC_LLSD_OBJECT; }
LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, nullptr); }
LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
LLSD::LLSD(const LLSD& other) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
@@ -825,17 +827,17 @@ void LLSD::clear() { Impl::assignUndefined(impl); }
LLSD::Type LLSD::type() const { return safe(impl).type(); }
// Scalar Constructors
LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(Boolean v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(Integer v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(Real v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const UUID& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const String& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Date& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const URI& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const Binary& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
// Convenience Constructors
LLSD::LLSD(F32 v) : impl(0) { ALLOC_LLSD_OBJECT; assign((Real)v); }
LLSD::LLSD(F32 v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign((Real)v); }
// Scalar Assignment
void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); }
@@ -860,7 +862,7 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); }
const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }
// const char * helpers
LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); }
LLSD::LLSD(const char* v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); }
void LLSD::assign(const char* v)
{
if(v) assign(std::string(v));
@@ -927,7 +929,7 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
// sStorage will point to the result of the last call. This will actually
// be one leak, but since this is used only when running under the
// debugger, it should not be an issue.
static char *sStorage = NULL;
static char *sStorage = nullptr;
delete[] sStorage;
std::string out_string;
{

View File

@@ -79,6 +79,17 @@ LLSD LlsdFromJson(const nlohmann::json &val)
return result;
}
LLSD LlsdFromJsonString(const std::string& str)
{
auto json = nlohmann::json::parse(str, nullptr, false);
if (json.is_discarded())
{
LL_WARNS() << "Cannot parse invalid json string:\n" << str << LL_ENDL;
return LLSD();
}
return LlsdFromJson(json);
}
//=========================================================================
nlohmann::json LlsdToJson(const LLSD &val)
{

View File

@@ -54,6 +54,7 @@
/// For maps and arrays child entries will be converted and added to the structure.
/// Order is preserved for an array but not for objects.
LLSD LlsdFromJson(const nlohmann::json &val);
LLSD LlsdFromJsonString(const std::string& body);
/// Convert an LLSD object into Parsed JSON object maintaining member names and
/// array indexs.

View File

@@ -40,6 +40,8 @@
#include "llsdutil_math.h"
#include "message.h"
#include "u64.h"
#include "llregionflags.h"
#include <boost/range/adaptor/map.hpp>
static const F32 SOME_BIG_NUMBER = 1000.0f;
static const F32 SOME_BIG_NEG_NUMBER = -1000.0f;
@@ -742,8 +744,8 @@ void LLParcel::unpackMessage(LLMessageSystem* msg)
void LLParcel::packAccessEntries(LLMessageSystem* msg,
const std::map<LLUUID,LLAccessEntry>& list)
{
access_map_const_iterator cit = list.begin();
access_map_const_iterator end = list.end();
LLAccessEntry::map::const_iterator cit = list.begin();
LLAccessEntry::map::const_iterator end = list.end();
if (cit == end)
{
@@ -794,9 +796,28 @@ void LLParcel::unpackAccessEntries(LLMessageSystem* msg,
}
void LLParcel::unpackExperienceEntries(LLMessageSystem* msg, U32 type)
{
LLUUID id;
S32 i;
S32 count = msg->getNumberOfBlocksFast(_PREHASH_List);
for (i = 0; i < count; i++)
{
msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i);
if (id.notNull())
{
mExperienceKeys[id] = type;
}
}
}
void LLParcel::expirePasses(S32 now)
{
access_map_iterator itor = mAccessList.begin();
LLAccessEntry::map::iterator itor = mAccessList.begin();
while (itor != mAccessList.end())
{
const LLAccessEntry& entry = (*itor).second;
@@ -886,7 +907,7 @@ BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time)
// Can't add owner to these lists
return FALSE;
}
access_map_iterator itor = mAccessList.begin();
LLAccessEntry::map::iterator itor = mAccessList.begin();
while (itor != mAccessList.end())
{
const LLAccessEntry& entry = (*itor).second;
@@ -931,7 +952,7 @@ BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time)
return FALSE;
}
access_map_iterator itor = mBanList.begin();
LLAccessEntry::map::iterator itor = mBanList.begin();
while (itor != mBanList.end())
{
const LLAccessEntry& entry = (*itor).second;
@@ -970,7 +991,7 @@ BOOL remove_from_access_array(std::map<LLUUID,LLAccessEntry>* list,
const LLUUID& agent_id)
{
BOOL removed = FALSE;
access_map_iterator itor = list->begin();
LLAccessEntry::map::iterator itor = list->begin();
while (itor != list->end())
{
const LLAccessEntry& entry = (*itor).second;
@@ -1091,7 +1112,7 @@ void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group)
mSaleTimerExpires.start();
mSaleTimerExpires.setTimerExpirySec(U64Microseconds(DEFAULT_USEC_SALE_TIMEOUT));
mStatus = OS_LEASE_PENDING;
mClaimDate = time(NULL);
mClaimDate = time(nullptr);
setAuctionID(0);
// clear the autoreturn whenever land changes hands
setCleanOtherTime(0);
@@ -1313,3 +1334,58 @@ LLParcel::ECategory category_ui_string_to_category(const std::string& s)
// is a distinct option from "None" and "Other"
return LLParcel::C_ANY;
}
LLAccessEntry::map LLParcel::getExperienceKeysByType(U32 type) const
{
LLAccessEntry::map access;
LLAccessEntry entry;
xp_type_map_t::const_iterator it = mExperienceKeys.begin();
for(/**/; it != mExperienceKeys.end(); ++it)
{
if(it->second == type)
{
entry.mID = it->first;
access[entry.mID] = entry;
}
}
return access;
}
void LLParcel::clearExperienceKeysByType(U32 type)
{
xp_type_map_t::iterator it = mExperienceKeys.begin();
while(it != mExperienceKeys.end())
{
if(it->second == type)
{
mExperienceKeys.erase(it++);
}
else
{
++it;
}
}
}
void LLParcel::setExperienceKeyType(const LLUUID& experience_key, U32 type)
{
if (type == EXPERIENCE_KEY_TYPE_NONE)
{
mExperienceKeys.erase(experience_key);
}
else
{
if (countExperienceKeyType(type) < PARCEL_MAX_EXPERIENCE_LIST)
{
mExperienceKeys[experience_key] = type;
}
}
}
U32 LLParcel::countExperienceKeyType(U32 type)
{
return std::count_if(
boost::begin(mExperienceKeys | boost::adaptors::map_values),
boost::end(mExperienceKeys | boost::adaptors::map_values),
std::bind2nd(std::equal_to<U32>(), type));
}

View File

@@ -60,6 +60,9 @@ const S32 PARCEL_MAX_ACCESS_LIST = 300;
//for access/ban lists.
const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f;
// Maximum number of experiences
const S32 PARCEL_MAX_EXPERIENCE_LIST = 24;
// Weekly charge for listing a parcel in the directory
const S32 PARCEL_DIRECTORY_FEE = 30;
@@ -141,9 +144,11 @@ class LLSD;
class LLAccessEntry
{
public:
typedef std::map<LLUUID,LLAccessEntry> map;
LLAccessEntry()
: mID(),
mTime(0),
: mTime(0),
mFlags(0)
{}
@@ -152,8 +157,6 @@ public:
U32 mFlags; // Not used - currently should always be zero
};
typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
typedef std::map<LLUUID,LLAccessEntry>::const_iterator access_map_const_iterator;
class LLParcel
{
@@ -331,6 +334,9 @@ public:
void unpackAccessEntries(LLMessageSystem* msg,
std::map<LLUUID,LLAccessEntry>* list);
void unpackExperienceEntries(LLMessageSystem* msg, U32 type);
void setAABBMin(const LLVector3& min) { mAABBMin = min; }
void setAABBMax(const LLVector3& max) { mAABBMax = max; }
@@ -707,6 +713,17 @@ public:
std::map<LLUUID,LLAccessEntry> mTempBanList;
std::map<LLUUID,LLAccessEntry> mTempAccessList;
typedef std::map<LLUUID, U32> xp_type_map_t;
void setExperienceKeyType(const LLUUID& experience_key, U32 type);
U32 countExperienceKeyType(U32 type);
U32 getExperienceKeyType(const LLUUID& experience_key)const;
LLAccessEntry::map getExperienceKeysByType(U32 type)const;
void clearExperienceKeysByType(U32 type);
private:
xp_type_map_t mExperienceKeys;
};

View File

@@ -1,31 +1,25 @@
/**
* @file llparcelflags.h
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -97,8 +91,10 @@ const U32 PF_DEFAULT = PF_ALLOW_FLY
| PF_USE_ESTATE_VOICE_CHAN;
// Access list flags
const U32 AL_ACCESS = (1 << 0);
const U32 AL_BAN = (1 << 1);
const U32 AL_ACCESS = (1 << 0);
const U32 AL_BAN = (1 << 1);
const U32 AL_ALLOW_EXPERIENCE = (1 << 3);
const U32 AL_BLOCK_EXPERIENCE = (1 << 4);
//const U32 AL_RENTER = (1 << 2);
// Block access return values. BA_ALLOWED is the only success case

View File

@@ -45,6 +45,7 @@ set(llmessage_SOURCE_FILES
llclassifiedflags.cpp
lldatapacker.cpp
lldispatcher.cpp
llexperiencecache.cpp
llfiltersd2xmlrpc.cpp
llhost.cpp
llhttpclient.cpp
@@ -133,10 +134,12 @@ set(llmessage_HEADER_FILES
llcipher.h
llcircuit.h
llclassifiedflags.h
llcororesponder.h
llcurl.h
lldatapacker.h
lldbstrings.h
lldispatcher.h
llexperiencecache.h
lleventflags.h
llfiltersd2xmlrpc.h
llfollowcamparams.h

View File

@@ -0,0 +1,43 @@
/**
* @file llcororesponder.h
* @brief A responder purposed to call coro functions, to ease transition to LLCoro
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
*
* Copyright (C) 2020, Liru Færs
*
* 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 <functional>
#include "llhttpclient.h"
struct LLCoroResponder final : public LLHTTPClient::ResponderWithCompleted
{
typedef std::function<void(const LLCoroResponder&)> cb_t;
LLCoroResponder(const cb_t& cb) : mCB(cb) {}
void httpCompleted() override { mCB(*this); }
const AIHTTPReceivedHeaders& getHeaders() const { return mReceivedHeaders; }
const LLSD& getContent() const { return mContent; }
char const* getName() const override { return "LLCoroResponder"; }
private:
const cb_t mCB;
};

View File

@@ -0,0 +1,928 @@
/**
* @file llexperiencecache.cpp
* @brief llexperiencecache and related class definitions
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "llexperiencecache.h"
#include "llavatarname.h"
#include "llcororesponder.h"
#include "llsdserialize.h"
#include "lleventfilter.h"
#include "lldir.h"
#include <set>
#include <map>
#include <boost/tokenizer.hpp>
#include <boost/concept_check.hpp>
#include <boost/smart_ptr/make_shared.hpp>
//=========================================================================
namespace LLExperienceCacheImpl
{
void mapKeys(const LLSD& legacyKeys);
F64 getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers);
bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age);
static const std::string PRIVATE_KEY = "private_id";
static const std::string EXPERIENCE_ID = "public_id";
static const std::string MAX_AGE("max-age");
static const boost::char_separator<char> EQUALS_SEPARATOR("=");
static const boost::char_separator<char> COMMA_SEPARATOR(",");
// *TODO$: this seems to be tied to mapKeys which is used by bootstrap.... but I don't think that bootstrap is used.
typedef std::map<LLUUID, LLUUID> KeyMap;
KeyMap privateToPublicKeyMap;
}
//=========================================================================
const std::string LLExperienceCache::PRIVATE_KEY = "private_id";
const std::string LLExperienceCache::MISSING = "DoesNotExist";
const std::string LLExperienceCache::AGENT_ID = "agent_id";
const std::string LLExperienceCache::GROUP_ID = "group_id";
const std::string LLExperienceCache::EXPERIENCE_ID = "public_id";
const std::string LLExperienceCache::NAME = "name";
const std::string LLExperienceCache::PROPERTIES = "properties";
const std::string LLExperienceCache::EXPIRES = "expiration";
const std::string LLExperienceCache::DESCRIPTION = "description";
const std::string LLExperienceCache::QUOTA = "quota";
const std::string LLExperienceCache::MATURITY = "maturity";
const std::string LLExperienceCache::METADATA = "extended_metadata";
const std::string LLExperienceCache::SLURL = "slurl";
// should be in sync with experience-api/experiences/models.py
const int LLExperienceCache::PROPERTY_INVALID = 1 << 0;
const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3;
const int LLExperienceCache::PROPERTY_GRID = 1 << 4;
const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5;
const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6;
const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7;
// default values
const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0;
const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes
const int LLExperienceCache::SEARCH_PAGE_SIZE = 30;
//=========================================================================
LLExperienceCache::LLExperienceCache():
mShutdown(false)
{
}
LLExperienceCache::~LLExperienceCache()
{
}
void LLExperienceCache::initSingleton()
{
mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml");
LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL;
llifstream cache_stream(mCacheFileName.c_str());
if (cache_stream.is_open())
{
cache_stream >> (*this);
}
}
void LLExperienceCache::cleanup()
{
LL_INFOS("ExperienceCache") << "Saving " << mCacheFileName << LL_ENDL;
llofstream cache_stream(mCacheFileName.c_str());
if (cache_stream.is_open())
{
cache_stream << (*this);
}
mShutdown = true;
}
//-------------------------------------------------------------------------
void LLExperienceCache::importFile(std::istream& istr)
{
LLSD data;
S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr);
if (parse_count < 1) return;
LLSD experiences = data["experiences"];
LLUUID public_key;
LLSD::map_const_iterator it = experiences.beginMap();
for (; it != experiences.endMap(); ++it)
{
public_key.set(it->first);
mCache[public_key] = it->second;
}
LL_DEBUGS("ExperienceCache") << "importFile() loaded " << mCache.size() << LL_ENDL;
}
void LLExperienceCache::exportFile(std::ostream& ostr) const
{
LLSD experiences;
cache_t::const_iterator it = mCache.begin();
for (; it != mCache.end(); ++it)
{
if (!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() ||
it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID))
continue;
experiences[it->first.asString()] = it->second;
}
LLSD data;
data["experiences"] = experiences;
LLSDSerialize::toPrettyXML(data, ostr);
}
// *TODO$: Rider: This method does not seem to be used... it may be useful in testing.
void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration)
{
LLExperienceCacheImpl::mapKeys(legacyKeys);
LLSD::array_const_iterator it = legacyKeys.beginArray();
for (/**/; it != legacyKeys.endArray(); ++it)
{
LLSD experience = *it;
if (experience.has(EXPERIENCE_ID))
{
if (!experience.has(EXPIRES))
{
experience[EXPIRES] = initialExpiration;
}
processExperience(experience[EXPERIENCE_ID].asUUID(), experience);
}
else
{
LL_WARNS("ExperienceCache")
<< "Skipping bootstrap entry which is missing " << EXPERIENCE_ID
<< LL_ENDL;
}
}
}
LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found)
{
if (private_key.isNull())
return LLUUID::null;
LLExperienceCacheImpl::KeyMap::const_iterator it = LLExperienceCacheImpl::privateToPublicKeyMap.find(private_key);
if (it == LLExperienceCacheImpl::privateToPublicKeyMap.end())
{
if (null_if_not_found)
{
return LLUUID::null;
}
return private_key;
}
LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL;
return it->second;
}
//=========================================================================
void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& experience)
{
LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL;
mCache[public_key]=experience;
LLSD & row = mCache[public_key];
if(row.has(EXPIRES))
{
row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds();
}
if(row.has(EXPERIENCE_ID))
{
mPendingQueue.erase(row[EXPERIENCE_ID].asUUID());
}
//signal
signal_map_t::iterator sig_it = mSignalMap.find(public_key);
if (sig_it != mSignalMap.end())
{
signal_ptr signal = sig_it->second;
(*signal)(experience);
mSignalMap.erase(public_key);
}
}
const LLExperienceCache::cache_t& LLExperienceCache::getCached()
{
return mCache;
}
void LLExperienceCache::requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t requests)
{
//LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL;
LLSD result = responder.getContent();
auto status = responder.getStatus();
if (!responder.isGoodStatus(status))
{
F64 now = LLFrameTimer::getTotalSeconds();
auto headers = responder.getHeaders();
// build dummy entries for the failed requests
for (auto request : requests)
{
LLSD exp = get(request);
//leave the properties alone if we already have a cache entry for this xp
if (exp.isUndefined())
{
exp[PROPERTIES] = PROPERTY_INVALID;
}
exp[EXPIRES] = now + LLExperienceCacheImpl::getErrorRetryDeltaTime(status, headers);
exp[EXPERIENCE_ID] = request;
exp["key_type"] = EXPERIENCE_ID;
exp["uuid"] = request;
exp["error"] = status;
exp[QUOTA] = DEFAULT_QUOTA;
processExperience(request, exp);
}
return;
}
LLSD experiences = result["experience_keys"];
for (LLSD::array_const_iterator it = experiences.beginArray();
it != experiences.endArray(); ++it)
{
const LLSD& row = *it;
LLUUID public_key = row[EXPERIENCE_ID].asUUID();
LL_DEBUGS("ExperienceCache") << "Received result for " << public_key
<< " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL;
processExperience(public_key, row);
}
LLSD error_ids = result["error_ids"];
for (LLSD::array_const_iterator errIt = error_ids.beginArray();
errIt != error_ids.endArray(); ++errIt)
{
LLUUID id = errIt->asUUID();
LLSD exp;
exp[EXPIRES] = DEFAULT_EXPIRATION;
exp[EXPERIENCE_ID] = id;
exp[PROPERTIES] = PROPERTY_INVALID;
exp[MISSING] = true;
exp[QUOTA] = DEFAULT_QUOTA;
processExperience(id, exp);
LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL;
}
}
void LLExperienceCache::requestExperiences()
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string urlBase = mCapability("GetExperienceInfo");
if (urlBase.empty())
{
LL_DEBUGS("ExperienceCache") << "No Experience capability." << LL_ENDL;
return;
}
if (*urlBase.rbegin() != '/')
{
urlBase += "/";
}
urlBase += "id/";
F64 now = LLFrameTimer::getTotalSeconds();
const U32 EXP_URL_SEND_THRESHOLD = 3000;
constexpr U32 EXP_PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH;
std::ostringstream ostr;
ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE;
RequestQueue_t requests;
while (!mRequestQueue.empty())
{
RequestQueue_t::iterator it = mRequestQueue.begin();
LLUUID key = (*it);
mRequestQueue.erase(it);
requests.insert(key);
ostr << "&" << EXPERIENCE_ID << "=" << key.asString();
mPendingQueue[key] = now;
if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD))
{ // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself.
LLHTTPClient::get(ostr.str(), new LLCoroResponder(
boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, requests) ));
ostr.str(std::string());
ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE;
requests.clear();
}
}
}
bool LLExperienceCache::isRequestPending(const LLUUID& public_key)
{
bool isPending = false;
const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0;
PendingQueue_t::const_iterator it = mPendingQueue.find(public_key);
if(it != mPendingQueue.end())
{
F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS;
isPending = (it->second > expire_time);
}
return isPending;
}
void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn)
{
mCapability = queryfn;
}
void LLExperienceCache::idleCoro()
{
const F32 SECS_BETWEEN_REQUESTS = 0.5f;
const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds
{
static LLFrameTimer sRequestTimer;
if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) return;
if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))
{
eraseExpired();
}
if (!mRequestQueue.empty())
{
requestExperiences();
}
}
// The coroutine system will likely be shut down by the time we get to this point
// (or at least no further cycling will occur on it since the user has decided to quit.)
}
void LLExperienceCache::erase(const LLUUID& key)
{
cache_t::iterator it = mCache.find(key);
if(it != mCache.end())
{
mCache.erase(it);
}
}
void LLExperienceCache::eraseExpired()
{
F64 now = LLFrameTimer::getTotalSeconds();
cache_t::iterator it = mCache.begin();
while (it != mCache.end())
{
cache_t::iterator cur = it;
LLSD& exp = cur->second;
++it;
//LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL;
if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now)
{
if(!exp.has(EXPERIENCE_ID))
{
LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ;
mCache.erase(cur);
}
else
{
LLUUID id = exp[EXPERIENCE_ID].asUUID();
LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null;
if(private_key.notNull() || !exp.has("DoesNotExist"))
{
fetch(id, true);
}
else
{
LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ;
mCache.erase(cur);
}
}
}
}
}
bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/)
{
if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end()))
{
LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL;
mRequestQueue.insert(key);
return true;
}
return false;
}
void LLExperienceCache::insert(const LLSD& experience_data)
{
if(experience_data.has(EXPERIENCE_ID))
{
processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data);
}
else
{
LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL;
}
}
const LLSD& LLExperienceCache::get(const LLUUID& key)
{
static const LLSD empty;
if(key.isNull())
return empty;
cache_t::const_iterator it = mCache.find(key);
if (it != mCache.end())
{
return it->second;
}
fetch(key);
return empty;
}
void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot)
{
if(key.isNull())
return;
cache_t::const_iterator it = mCache.find(key);
if (it != mCache.end())
{
// ...name already exists in cache, fire callback now
callback_signal_t signal;
signal.connect(slot);
signal(it->second);
return;
}
fetch(key);
signal_ptr signal = boost::make_shared<callback_signal_t>();
std::pair<signal_map_t::iterator, bool> result = mSignalMap.insert(signal_map_t::value_type(key, signal));
if (!result.second)
signal = (*result.first).second;
signal->connect(slot);
}
//=========================================================================
void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
if (url.empty())
{
url = mCapability("GetMetadata");
if (url.empty())
{
LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL;
return;
}
}
LLSD fields;
fields.append("experience");
LLSD data;
data["object-id"] = objectId;
data["item-id"] = itemId;
data["fields"] = fields;
LLHTTPClient::post(url, data, new LLCoroResponder(
boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, fn)));
}
void LLExperienceCache::fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn)
{
LLSD result = responder.getContent();
auto status = responder.getStatus();
if (!responder.isGoodStatus(status) || !result.has("experience"))
{
LLSD failure;
if (!status)
{
failure["error"] = status;
failure["message"] = responder.getReason();
}
else
{
failure["error"] = -1;
failure["message"] = "no experience";
}
if (fn != nullptr)
fn(failure);
return;
}
LLUUID expId = result["experience"].asUUID();
get(expId, fn);
}
//-------------------------------------------------------------------------
void LLExperienceCache::findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::ostringstream url;
url << mCapability("FindExperienceByName") << "?page=" << page << "&page_size=" << SEARCH_PAGE_SIZE << "&query=" << LLURI::escape(text);
LLHTTPClient::get(url.str(), new LLCoroResponder(
boost::bind(&LLExperienceCache::findExperienceByNameCoro, this, _1, fn)));
}
void LLExperienceCache::findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn)
{
LLSD result = responder.getContent();
if (!responder.isGoodStatus(responder.getStatus()))
{
fn(LLSD());
return;
}
const LLSD& experiences = result["experience_keys"];
for (LLSD::array_const_iterator it = experiences.beginArray(); it != experiences.endArray(); ++it)
{
insert(*it);
}
fn(result);
}
//-------------------------------------------------------------------------
void LLExperienceCache::getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
// search for experiences owned by the current group
std::string url = mCapability("GroupExperiences");
if (url.empty())
{
LL_WARNS("ExperienceCache") << "No Group Experiences capability" << LL_ENDL;
return;
}
url += "?" + groupId.asString();
LLHTTPClient::get(url, new LLCoroResponder(
boost::bind(&LLExperienceCache::getGroupExperiencesCoro, this, _1, fn)));
}
void LLExperienceCache::getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn)
{
LLSD result = responder.getContent();
if (!responder.isGoodStatus(responder.getStatus()))
{
fn(LLSD());
return;
}
const LLSD& experienceIds = result["experience_ids"];
fn(experienceIds);
}
//-------------------------------------------------------------------------
void LLExperienceCache::getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn)
{
regionExperiences(regioncaps, LLSD(), false, fn);
}
void LLExperienceCache::setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn)
{
regionExperiences(regioncaps, experiences, true, fn);
}
void LLExperienceCache::regionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, bool update, ExperienceGetFn_t fn)
{
// search for experiences owned by the current group
std::string url = regioncaps("RegionExperiences");
if (url.empty())
{
LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
return;
}
auto httpRequest = new LLCoroResponder(
boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, fn));
LLSD result;
if (update)
LLHTTPClient::post(url, experiences, httpRequest);
else
LLHTTPClient::get(url, httpRequest);
}
void LLExperienceCache::regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn)
{
LLSD result = responder.getContent();
if (!responder.isGoodStatus(responder.getStatus()))
{
// fn(LLSD());
return;
}
fn(result);
}
//-------------------------------------------------------------------------
void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
LLHTTPClient::get(url, new LLCoroResponder(
boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn)));
}
void LLExperienceCache::setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string url = mCapability("ExperiencePreferences");
if (url.empty())
return;
LLSD permData;
LLSD data;
permData["permission"] = permission;
data[experienceId.asString()] = permData;
LLHTTPClient::put(url, data, new LLCoroResponder(
boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn)));
}
void LLExperienceCache::forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString();
LLHTTPClient::del(url, new LLCoroResponder(
boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn)));
}
void LLExperienceCache::experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn)
{
// search for experiences owned by the current group
LLSD result = responder.getContent();
if (responder.isGoodStatus(responder.getStatus()))
{
fn(result);
}
}
//-------------------------------------------------------------------------
void LLExperienceCache::getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string url = mCapability("IsExperienceAdmin");
if (url.empty())
{
LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
return;
}
url += "?experience_id=" + experienceId.asString();
LLHTTPClient::get(url, new LLCoroResponder(
boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1))));
}
//-------------------------------------------------------------------------
void LLExperienceCache::updateExperience(LLSD updateData, ExperienceGetFn_t fn)
{
if (mCapability == nullptr)
{
LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL;
return;
}
std::string url = mCapability("UpdateExperience");
if (url.empty())
{
LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL;
return;
}
updateData.erase(LLExperienceCache::QUOTA);
updateData.erase(LLExperienceCache::EXPIRES);
updateData.erase(LLExperienceCache::AGENT_ID);
LLHTTPClient::post(url, updateData, new LLCoroResponder(
boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1))));
}
//=========================================================================
void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys)
{
LLSD::array_const_iterator exp = legacyKeys.beginArray();
for (/**/; exp != legacyKeys.endArray(); ++exp)
{
if (exp->has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp->has(LLExperienceCacheImpl::PRIVATE_KEY))
{
LLExperienceCacheImpl::privateToPublicKeyMap[(*exp)[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] =
(*exp)[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID();
}
}
}
// Return time to retry a request that generated an error, based on
// error type and headers. Return value is seconds-since-epoch.
F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers)
{
// Retry-After takes priority
std::string retry_afters;
if (headers.getFirstValue("retry-after", retry_afters))
{
LLSD retry_after(retry_afters);
// We only support the delta-seconds type
S32 delta_seconds = retry_after.asInteger();
if (delta_seconds > 0)
{
// ...valid delta-seconds
return F64(delta_seconds);
}
}
// If no Retry-After, look for Cache-Control max-age
// Allow the header to override the default
std::string cache_control;
if (headers.getFirstValue("cache-control", cache_control))
{
S32 max_age = 0;
if (LLExperienceCacheImpl::maxAgeFromCacheControl(cache_control, &max_age))
{
LL_WARNS("ExperienceCache")
<< "got EXPIRES from headers, max_age " << max_age
<< LL_ENDL;
return (F64)max_age;
}
}
// No information in header, make a guess
if (status == 503)
{
// ...service unavailable, retry soon
const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min
return SERVICE_UNAVAILABLE_DELAY;
}
else if (status == 499)
{
// ...we were probably too busy, retry quickly
const F64 BUSY_DELAY = 10.0; // 10 seconds
return BUSY_DELAY;
}
else
{
// ...other unexpected error
const F64 DEFAULT_DELAY = 3600.0; // 1 hour
return DEFAULT_DELAY;
}
}
bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age)
{
// Split the string on "," to get a list of directives
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer directives(cache_control, COMMA_SEPARATOR);
tokenizer::iterator token_it = directives.begin();
for ( ; token_it != directives.end(); ++token_it)
{
// Tokens may have leading or trailing whitespace
std::string token = *token_it;
LLStringUtil::trim(token);
if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0)
{
// ...this token starts with max-age, so let's chop it up by "="
tokenizer subtokens(token, EQUALS_SEPARATOR);
tokenizer::iterator subtoken_it = subtokens.begin();
// Must have a token
if (subtoken_it == subtokens.end()) return false;
std::string subtoken = *subtoken_it;
// Must exactly equal "max-age"
LLStringUtil::trim(subtoken);
if (subtoken != MAX_AGE) return false;
// Must have another token
++subtoken_it;
if (subtoken_it == subtokens.end()) return false;
subtoken = *subtoken_it;
// Must be a valid integer
// *NOTE: atoi() returns 0 for invalid values, so we have to
// check the string first.
// *TODO: Do servers ever send "0000" for zero? We don't handle it
LLStringUtil::trim(subtoken);
if (subtoken == "0")
{
*max_age = 0;
return true;
}
S32 val = atoi( subtoken.c_str() );
if (val > 0 && val < S32_MAX)
{
*max_age = val;
return true;
}
return false;
}
}
return false;
}

View File

@@ -0,0 +1,181 @@
/**
* @file llexperiencecache.h
* @brief Caches information relating to experience keys
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
#ifndef LL_LLEXPERIENCECACHE_H
#define LL_LLEXPERIENCECACHE_H
#include "linden_common.h"
#include "llsingleton.h"
#include "llframetimer.h"
#include "llsd.h"
#include <boost/signals2.hpp>
struct LLCoroResponder;
class LLSD;
class LLUUID;
class LLExperienceCache final : public LLSingleton < LLExperienceCache >
{
friend class LLSingleton<LLExperienceCache>;
LLExperienceCache();
public:
typedef std::function<std::string(const std::string &)> CapabilityQuery_t;
typedef std::function<void(const LLSD &)> ExperienceGetFn_t;
void idleCoro();
void setCapabilityQuery(CapabilityQuery_t queryfn);
void cleanup();
//-------------------------------------------
// Cache methods
void erase(const LLUUID& key);
bool fetch(const LLUUID& key, bool refresh = false);
void insert(const LLSD& experience_data);
const LLSD& get(const LLUUID& key);
void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately.
bool isRequestPending(const LLUUID& public_key);
//-------------------------------------------
void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn) { fetchAssociatedExperience(objectId, itemId, LLStringUtil::null, fn); }
void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn);
void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn);
void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn);
// the Get/Set Region Experiences take a CapabilityQuery to get the capability since
// the region being queried may not be the region that the agent is standing on.
void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn);
void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn);
void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn);
void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn);
void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn);
void updateExperience(LLSD updateData, ExperienceGetFn_t fn);
//-------------------------------------------
static const std::string NAME; // "name"
static const std::string EXPERIENCE_ID; // "public_id"
static const std::string AGENT_ID; // "agent_id"
static const std::string GROUP_ID; // "group_id"
static const std::string PROPERTIES; // "properties"
static const std::string EXPIRES; // "expiration"
static const std::string DESCRIPTION; // "description"
static const std::string QUOTA; // "quota"
static const std::string MATURITY; // "maturity"
static const std::string METADATA; // "extended_metadata"
static const std::string SLURL; // "slurl"
static const std::string MISSING; // "DoesNotExist"
// should be in sync with experience-api/experiences/models.py
static const int PROPERTY_INVALID; // 1 << 0
static const int PROPERTY_PRIVILEGED; // 1 << 3
static const int PROPERTY_GRID; // 1 << 4
static const int PROPERTY_PRIVATE; // 1 << 5
static const int PROPERTY_DISABLED; // 1 << 6
static const int PROPERTY_SUSPENDED; // 1 << 7
private:
virtual ~LLExperienceCache();
void initSingleton() override;
// Callback types for get()
typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t;
typedef boost::shared_ptr<callback_signal_t> signal_ptr;
// May have multiple callbacks for a single ID, which are
// represented as multiple slots bound to the signal.
// Avoid copying signals via pointers.
typedef std::map<LLUUID, signal_ptr> signal_map_t;
typedef std::map<LLUUID, LLSD> cache_t;
typedef uuid_set_t RequestQueue_t;
typedef std::map<LLUUID, F64> PendingQueue_t;
//--------------------------------------------
static const std::string PRIVATE_KEY; // "private_id"
// default values
static const F64 DEFAULT_EXPIRATION; // 600.0
static const S32 DEFAULT_QUOTA; // 128 this is megabytes
static const int SEARCH_PAGE_SIZE;
//--------------------------------------------
void processExperience(const LLUUID& public_key, const LLSD& experience);
//--------------------------------------------
cache_t mCache;
signal_map_t mSignalMap;
RequestQueue_t mRequestQueue;
PendingQueue_t mPendingQueue;
LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache
CapabilityQuery_t mCapability;
std::string mCacheFileName;
bool mShutdown;
void eraseExpired();
void requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t);
void requestExperiences();
void fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t);
void findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t);
void getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t);
void regionExperiences(CapabilityQuery_t regioncaps, const LLSD& experiences, bool update, ExperienceGetFn_t fn);
void regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn);
void experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn);
void bootstrap(const LLSD& legacyKeys, int initialExpiration);
void exportFile(std::ostream& ostr) const;
void importFile(std::istream& istr);
//
const cache_t& getCached();
// maps an experience private key to the experience id
LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false);
//=====================================================================
inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache)
{
cache.exportFile(os);
return os;
}
inline friend std::istream &operator >> (std::istream &is, LLExperienceCache &cache)
{
cache.importFile(is);
return is;
}
};
#endif // LL_LLEXPERIENCECACHE_H

View File

@@ -168,19 +168,20 @@ const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS
| ESTATE_ACCESS_BANNED_AGENTS
| ESTATE_ACCESS_MANAGERS;
// for EstateOwnerRequest, estateaccessdelta message
const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1 << 0;
const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1 << 1;
// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages
const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0;
const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1 << 2;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1 << 3;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1 << 4;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1 << 5;
const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1 << 6;
const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1 << 7;
const U32 ESTATE_ACCESS_MANAGER_ADD = 1 << 8;
const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9;
const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2;
const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4;
const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5;
const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6;
const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7;
const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8;
const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9;
const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10;
const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11;
const S32 ESTATE_MAX_MANAGERS = 15;
const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned
@@ -191,6 +192,26 @@ const U32 SWD_OTHERS_LAND_ONLY = (1 << 0);
const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1);
const U32 SWD_SCRIPTED_ONLY = (1 << 2);
// Controls experience key validity in the estate
const U32 EXPERIENCE_KEY_TYPE_NONE = 0;
const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1;
const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2;
const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3;
const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED;
const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED;
//
const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2;
const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3;
const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4;
const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5;
const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6;
const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7;
const S32 ESTATE_MAX_EXPERIENCE_IDS = 8;
#endif

View File

@@ -1393,6 +1393,8 @@ char const* const _PREHASH_AppearanceVersion = LLMessageStringTable::getInstance
char const* const _PREHASH_CofVersion = LLMessageStringTable::getInstance()->getString("CofVersion");
char const* const _PREHASH_AppearanceHover = LLMessageStringTable::getInstance()->getString("AppearanceHover");
char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->getString("HoverHeight");
char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience");
char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID");
// <FS:CR> Aurora Sim
char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX");

View File

@@ -1393,6 +1393,8 @@ extern char const* const _PREHASH_AppearanceVersion;
extern char const* const _PREHASH_CofVersion;
extern char const* const _PREHASH_AppearanceHover;
extern char const* const _PREHASH_HoverHeight;
extern char const* const _PREHASH_Experience;
extern char const* const _PREHASH_ExperienceID;
// <FS:CR> Aurora Sim
extern char const* const _PREHASH_RegionSizeX;

View File

@@ -37,6 +37,7 @@ set(llui_SOURCE_FILES
lldraghandle.cpp
lleditmenuhandler.cpp
llfiltereditor.cpp
llflatlistview.cpp
llfloater.cpp
llflyoutbutton.cpp
llfocusmgr.cpp
@@ -116,6 +117,7 @@ set(llui_HEADER_FILES
lldraghandle.h
lleditmenuhandler.h
llfiltereditor.h
llflatlistview.h
llfloater.h
llflyoutbutton.h
llfocusmgr.h

View File

@@ -26,12 +26,14 @@ const std::array<const std::string, LFIDBearer::COUNT> LFIDBearer::sMenuStrings
{
"menu_avs_list.xml" // 0
, "menu_groups_list.xml" // 1
, "menu_objects_list.xml" // 2 // Singu TODO
, "menu_objects_list.xml" // 2
, "menu_experiences.xml" // 3
};
std::array<LLMenuGL*, LFIDBearer::COUNT> LFIDBearer::sMenus {};
const LFIDBearer* LFIDBearer::sActive = nullptr;
LFIDBearer::Type LFIDBearer::sActiveType = LFIDBearer::AVATAR;
uuid_vec_t LFIDBearer::sActiveIDs {};
void LFIDBearer::buildMenus()
{

View File

@@ -34,25 +34,26 @@ struct LFIDBearer
AVATAR = 0,
GROUP,
OBJECT,
EXPERIENCE,
COUNT
};
virtual ~LFIDBearer() { if (sActive == this) sActive = nullptr; }
virtual LLUUID getStringUUIDSelectedItem() const = 0;
virtual uuid_vec_t getSelectedIDs() const { return { getStringUUIDSelectedItem() }; }
virtual S32 getNumSelected() const { return getStringUUIDSelectedItem().notNull(); }
virtual Type getSelectedType() const { return AVATAR; }
template<typename T> static const T* getActive() { return static_cast<const T*>(sActive); }
static LLUUID getActiveSelectedID() { return sActive->getStringUUIDSelectedItem(); }
static uuid_vec_t getActiveSelectedIDs() { return sActive->getSelectedIDs(); }
static S32 getActiveNumSelected() { return sActive->getNumSelected(); }
static const LLUUID& getActiveSelectedID() { return sActiveIDs.empty() ? LLUUID::null : sActiveIDs[0]; }
static const uuid_vec_t& getActiveSelectedIDs() { return sActiveIDs; }
static size_t getActiveNumSelected() { return sActiveIDs.size(); }
static const Type& getActiveType() { return sActiveType; }
void setActive() const
{
sActive = this;
sActiveType = getSelectedType();
sActiveIDs = getSelectedIDs();
//sActiveIDs or even some kinda hybrid map, if Type is MULTIPLE fill the vals? and remove a buncha virtual functions?
}
@@ -68,4 +69,5 @@ protected:
private:
static const LFIDBearer* sActive;
static Type sActiveType;
static uuid_vec_t sActiveIDs;
};

View File

@@ -446,8 +446,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
if (!mAllowTextEntry)
{
mButton->setLabelUnselected(name);
mButton->setLabelSelected(name);
mButton->setLabel(name);
}
}
@@ -465,9 +464,7 @@ void LLComboBox::updateLabel()
// the combo button label.
if (!mAllowTextEntry)
{
std::string label = getSelectedItemLabel();
mButton->setLabelUnselected(label);
mButton->setLabelSelected(label);
mButton->setLabel(getSelectedItemLabel());
}
}
@@ -513,13 +510,16 @@ void LLComboBox::onFocusLost()
void LLComboBox::setButtonVisible(BOOL visible)
{
static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
mButton->setVisible(visible);
if (mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
if (visible)
{
text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -558,18 +558,21 @@ S32 LLComboBox::getCurrentIndex() const
void LLComboBox::updateLayout()
{
static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
LLRect rect = getLocalRect();
if (mAllowTextEntry)
{
S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size,
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
S32 shadow_size = drop_shadow_button;
mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
mButton->setTabStop(FALSE);
mButton->setHAlign(LLFontGL::HCENTER);
if (!mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * shadow_size;
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
// clear label on button
std::string cur_label = mButton->getLabelSelected();
mTextEntry = new LLLineEditor(std::string("combo_text_entry"),
@@ -718,6 +721,7 @@ void LLComboBox::showList()
mList->setVisible(TRUE);
setUseBoundingRect(TRUE);
// updateBoundingRect();
}
void LLComboBox::hideList()
@@ -744,6 +748,7 @@ void LLComboBox::hideList()
{
gFocusMgr.setTopCtrl(NULL);
}
// updateBoundingRect();
}
}
@@ -1029,9 +1034,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor)
void LLComboBox::updateSelection()
{
if(mSuppressAutoComplete) {
return;
}
if(mSuppressAutoComplete) return;
LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
// user-entered portion of string, based on assumption that any selected
@@ -1242,3 +1245,25 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last )
return mList->selectItemRange(first, last);
}
/* Singu Note: This isn't very necessary for now, let's not bother.
static LLRegisterWidget<LLIconsComboBox> register_icons_combo_box("icons_combo_box");
LLIconsComboBox::Params::Params()
: icon_column("icon_column", ICON_COLUMN),
label_column("label_column", LABEL_COLUMN)
{}
LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p)
: LLComboBox(p),
mIconColumnIndex(p.icon_column),
mLabelColumnIndex(p.label_column)
{}
const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const
{
mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign());
return LLComboBox::getSelectedItemLabel(mLabelColumnIndex);
}
*/

File diff suppressed because it is too large Load Diff

540
indra/llui/llflatlistview.h Normal file
View File

@@ -0,0 +1,540 @@
/**
* @file llflatlistview.h
* @brief LLFlatListView base class and extension to support messages for several cases of an empty list.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLFLATLISTVIEW_H
#define LL_LLFLATLISTVIEW_H
#include "llpanel.h"
#include "llscrollcontainer.h"
#include "lltextbox.h"
/**
* LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's.
* LLSD can be associated with each added item, it can keep data from an item in digested form.
* Associated LLSD's can be of any type (singular, a map etc.).
* Items (LLPanel's subclasses) can be of different height.
* The list is LLPanel created in itself and grows in height while new items are added.
*
* The control can manage selection of its items when the flag "allow_select" is set. Also ability to select
* multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag
* is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items)
* since any item of the list was selected.
*
* Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to
* manage the list of pick items.
*
* ASSUMPTIONS AND STUFF
* - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise
* - Order of returned selected items are not guaranteed
* - The control assumes that all items being added are unique.
*/
class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler
{
LOG_CLASS(LLFlatListView);
public:
/**
* Abstract comparator for comparing flat list items in a form of LLPanel
*/
class ItemComparator
{
public:
ItemComparator() {};
virtual ~ItemComparator() {};
/** Returns true if item1 < item2, false otherwise */
virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0;
};
/**
* Represents reverse comparator which acts as a decorator for a comparator that need to be reversed
*/
class ItemReverseComparator : public ItemComparator
{
public:
ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {};
virtual ~ItemReverseComparator() {};
bool compare(const LLPanel* item1, const LLPanel* item2) const override
{
return mComparator.compare(item2, item1);
}
private:
const ItemComparator& mComparator;
};
struct Params : public LLInitParam::Block<Params, LLScrollContainer::Params>
{
/** turning on/off selection support */
Optional<bool> allow_select;
/** turning on/off multiple selection (works while clicking and holding CTRL)*/
Optional<bool> multi_select;
/** don't allow to deselect all selected items (for mouse events on items only) */
Optional<bool> keep_one_selected;
/** try to keep selection visible after reshape */
Optional<bool> keep_selection_visible_on_reshape;
/** padding between items */
Optional<U32> item_pad;
/** textbox with info message when list is empty*/
Optional<LLTextBox::Params> no_items_text;
Params();
};
// disable traversal when finding widget to hand focus off to
/*virtual*/ BOOL canFocusChildren() const override { return FALSE; }
/**
* Connects callback to signal called when Return key is pressed.
*/
boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); }
/** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */
void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
/** Returns full rect of child panel */
const LLRect& getItemsRect() const;
LLRect getRequiredRect() override { return getItemsRect(); }
/** Returns distance between items */
const S32 getItemsPad() const { return mItemPad; }
/**
* Adds and item and LLSD value associated with it to the list at specified position
* @return true if the item was added, false otherwise
*/
virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true);
/**
* Insert item_to_add along with associated value to the list right after the after_item.
* @return true if the item was successfully added, false otherwise
*/
virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null);
/**
* Remove specified item
* @return true if the item was removed, false otherwise
*/
virtual bool removeItem(LLPanel* item, bool rearrange = true);
/**
* Remove an item specified by value
* @return true if the item was removed, false otherwise
*/
virtual bool removeItemByValue(const LLSD& value, bool rearrange = true);
/**
* Remove an item specified by uuid
* @return true if the item was removed, false otherwise
*/
virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true);
/**
* Get an item by value
* @return the item as LLPanel if associated with value, NULL otherwise
*/
virtual LLPanel* getItemByValue(const LLSD& value) const;
/**
* Check for item by value in list
* @return bool whether item exists by value or not
*/
virtual bool valueExists(const LLSD& value) const;
template<class T>
T* getTypedItemByValue(const LLSD& value) const
{
return dynamic_cast<T*>(getItemByValue(value));
}
/**
* Select or deselect specified item based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItem(LLPanel* item, bool select = true);
/**
* Select or deselect an item by associated value based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItemByValue(const LLSD& value, bool select = true);
/**
* Select or deselect an item by associated uuid based on select
* @return true if succeed, false otherwise
*/
virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true);
/**
* Get all panels stored in the list.
*/
virtual void getItems(std::vector<LLPanel*>& items) const;
/**
* Get all items values.
*/
virtual void getValues(std::vector<LLSD>& values) const;
/**
* Get LLSD associated with the first selected item
*/
virtual LLSD getSelectedValue() const;
/**
* Get LLSD's associated with selected items.
* @param selected_values std::vector being populated with LLSD associated with selected items
*/
virtual void getSelectedValues(std::vector<LLSD>& selected_values) const;
/**
* Get LLUUID associated with selected item
* @return LLUUID if such was associated with selected item
*/
virtual LLUUID getSelectedUUID() const;
/**
* Get LLUUIDs associated with selected items
* @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items
*/
virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const;
/** Get the top selected item */
virtual LLPanel* getSelectedItem() const;
/**
* Get selected items
* @param selected_items An std::vector being populated with pointers to selected items
*/
virtual void getSelectedItems(std::vector<LLPanel*>& selected_items) const;
/**
* Resets selection of items.
*
* It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true"
* argument for current Flat List.
* @param no_commit_on_deselection - if true onCommit callback will not be called
*/
virtual void resetSelection(bool no_commit_on_deselection = false);
/**
* Sets comment text which will be shown in the list is it is empty.
*
* Textbox to hold passed text is created while this method is called at the first time.
*
* @param comment_text - string to be shown as a comment.
*/
void setNoItemsCommentText( const std::string& comment_text);
/** Turn on/off multiple selection support */
void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; }
/** Turn on/off selection support */
void setAllowSelection(bool can_select) { mAllowSelection = can_select; }
/** Sets flag whether onCommit should be fired if selection was changed */
// FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly.
void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; }
/** Get number of selected items in the list */
U32 numSelected() const {return mSelectedItemPairs.size(); }
/** Get number of (visible) items in the list */
U32 size(const bool only_visible_items = true) const;
/** Removes all items from the list */
void clear() override;
/**
* Removes all items that can be detached from the list but doesn't destroy
* them, caller responsible to manage items after they are detached.
* Detachable item should accept "detach" action via notify() method,
* where it disconnect all callbacks, does other valuable routines and
* return 1.
*/
void detachItems(std::vector<LLPanel*>& detached_items);
/**
* Set comparator to use for future sorts.
*
* This class does NOT manage lifetime of the comparator
* but assumes that the comparator is always alive.
*/
void setComparator(const ItemComparator* comp) { mItemComparator = comp; }
void sort();
bool updateValue(const LLSD& old_value, const LLSD& new_value);
void scrollToShowFirstSelectedItem();
void selectFirstItem ();
void selectLastItem ();
S32 notify(const LLSD& info) override;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // <singu> Old-style
virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
typedef std::pair<LLPanel*, LLSD> item_pair_t;
typedef std::list<item_pair_t*> pairs_list_t;
typedef pairs_list_t::iterator pairs_iterator_t;
typedef pairs_list_t::const_iterator pairs_const_iterator_t;
/** An adapter for a ItemComparator */
struct ComparatorAdaptor
{
ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {};
bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) const
{
return mComparator.compare(item_pair1->first, item_pair2->first);
}
const ItemComparator& mComparator;
};
friend class LLUICtrlFactory;
LLFlatListView(const std::string& name, const LLRect& rect, bool opaque, const LLColor4& color, const S32& item_pad, bool allow_select, bool multi_select, bool keep_one_selected, bool keep_selection_visible_on_reshape, const std::string& no_items_text);
/** Manage selection on mouse events */
void onItemMouseClick(item_pair_t* item_pair, MASK mask);
void onItemRightMouseClick(item_pair_t* item_pair, MASK mask);
/**
* Updates position of items.
* It does not take into account invisible items.
*/
virtual void rearrangeItems();
virtual item_pair_t* getItemPair(LLPanel* item) const;
virtual item_pair_t* getItemPair(const LLSD& value) const;
virtual bool selectItemPair(item_pair_t* item_pair, bool select);
virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection);
BOOL canSelectAll() const override;
void selectAll() override;
virtual bool isSelected(item_pair_t* item_pair) const;
virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange);
bool addItemPairs(pairs_list_t panel_list, bool rearrange = true);
/**
* Notify parent about changed size of internal controls with "size_changes" action
*
* Size includes Items Rect width and either Items Rect height or comment text height.
* Comment text height is included if comment text is set and visible.
* List border size is also included into notified size.
*/
void notifyParentItemsRectChanged();
BOOL handleKeyHere(KEY key, MASK mask) override;
BOOL postBuild() override;
void onFocusReceived() override;
void onFocusLost() override;
void draw() override;
LLRect getLastSelectedItemRect();
void ensureSelectedVisible();
private:
void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;}
void setNoItemsCommentVisible(bool visible) const;
protected:
/** Comparator to use when sorting the list. */
const ItemComparator* mItemComparator;
private:
LLPanel* mItemsPanel;
S32 mItemsNoScrollWidth;
S32 mBorderThickness;
/** Items padding */
S32 mItemPad;
/** Selection support flag */
bool mAllowSelection;
/** Multiselection support flag, ignored if selection is not supported */
bool mMultipleSelection;
/**
* Flag specified whether onCommit be called if selection is changed in the list.
*
* Can be ignored in the resetSelection() method.
* @see resetSelection()
*/
bool mCommitOnSelectionChange;
bool mKeepOneItemSelected;
bool mIsConsecutiveSelection;
bool mKeepSelectionVisibleOnReshape;
/** All pairs of the list */
pairs_list_t mItemPairs;
/** Selected pairs for faster access */
pairs_list_t mSelectedItemPairs;
/**
* Rectangle contained previous size of items parent notified last time.
* Is used to reduce amount of parentNotify() calls if size was not changed.
*/
LLRect mPrevNotifyParentRect;
LLTextBox* mNoItemsCommentTextbox;
LLViewBorder* mSelectedItemsBorder;
commit_signal_t mOnReturnSignal;
};
/**
* Extends LLFlatListView functionality to show different messages when there are no items in the
* list depend on whether they are filtered or not.
*
* Class provides one message per case of empty list.
* It also provides protected updateNoItemsMessage() method to be called each time when derived list
* is changed to update base mNoItemsCommentTextbox value.
*
* It is implemented to avoid duplication of this functionality in concrete implementations of the
* lists. It is intended to be used as a base class for lists which should support two different
* messages for empty state. Can be improved to support more than two messages via state-to-message map.
*/
class LLFlatListViewEx : public LLFlatListView
{
public:
LOG_CLASS(LLFlatListViewEx);
struct Params : public LLInitParam::Block<Params, LLFlatListView::Params>
{
/**
* Contains a message for empty list when it does not contain any items at all.
*/
Optional<std::string> no_items_msg;
/**
* Contains a message for empty list when its items are removed by filtering.
*/
Optional<std::string> no_filtered_items_msg;
Params();
};
// *WORKAROUND: two methods to overload appropriate Params due to localization issue:
// no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931
void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; }
void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; }
bool getForceShowingUnmatchedItems();
void setForceShowingUnmatchedItems(bool show);
/**
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str);
std::string getFilterSubString() const { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
*/
void filterItems();
/**
* Returns true if last call of filterItems() found at least one matching item
*/
bool hasMatchedItems();
protected:
LLFlatListViewEx(const Params& p);
/**
* Applies a message for empty list depend on passed argument.
*
* @param filter_string - if is not empty, message for filtered items will be set, otherwise for
* completely empty list. Value of filter string will be passed as search_term in SLURL.
*/
void updateNoItemsMessage(const std::string& filter_string);
/**
* Applies visibility acording to action and LLFlatListView settings.
*
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
void updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;
std::string mNoItemsMsg;
std::string mFilterSubString;
/**
* Show list items that don't match current filter
*/
bool mForceShowingUnmatchedItems;
/**
* True if last call of filterItems() found at least one matching item
*/
bool mHasMatchedItems;
};
#endif

View File

@@ -2,31 +2,25 @@
* @file llscrollbar.cpp
* @brief Scrollbar UI widget
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, 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.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -46,6 +40,7 @@
#include "llwindow.h"
#include "llcontrol.h"
#include "llrender.h"
#include "lluictrlfactory.h"
LLScrollbar::LLScrollbar(
const std::string& name, LLRect rect,
@@ -402,7 +397,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
}
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL;
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL;
handled = TRUE;
}
else
@@ -414,7 +409,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask)
if( !handled )
{
getWindow()->setCursor(UI_CURSOR_ARROW);
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;
LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL;
handled = TRUE;
}
@@ -468,6 +463,13 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask)
return handled;
}
BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask)
{
// just treat a double click as a second click
return handleMouseDown(x, y, mask);
}
void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
if (width == getRect().getWidth() && height == getRect().getHeight()) return;
@@ -509,7 +511,6 @@ void LLScrollbar::draw()
mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f));
}
// Draw background and thumb.
LLUIImage* rounded_rect_imagep = LLUI::getUIImage("Rounded_Square");
@@ -525,6 +526,9 @@ void LLScrollbar::draw()
}
else
{
// Thumb
LLRect outline_rect = mThumbRect;
outline_rect.stretch(2);
// Background
rounded_rect_imagep->drawSolid(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0,
mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0,
@@ -532,9 +536,6 @@ void LLScrollbar::draw()
mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(),
mTrackColor);
// Thumb
LLRect outline_rect = mThumbRect;
outline_rect.stretch(2);
if (gFocusMgr.getKeyboardFocus() == this)
{
@@ -636,3 +637,8 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data )
{
changeLine( mStepSize, TRUE );
}
void LLScrollbar::setThickness(S32 thickness)
{
mThickness = thickness < 0 ? SCROLLBAR_SIZE : thickness;
}

View File

@@ -2,31 +2,25 @@
* @file llscrollbar.h
* @brief Scrollbar UI widget
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -36,6 +30,7 @@
#include "stdtypes.h"
#include "lluictrl.h"
#include "v4color.h"
#include "llbutton.h"
//
// Constants
@@ -59,6 +54,7 @@ public:
callback_t change_callback,
S32 step_size = 1);
public:
virtual ~LLScrollbar();
virtual void setValue(const LLSD& value);
@@ -67,6 +63,7 @@ public:
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask);
virtual BOOL handleHover(S32 x, S32 y, MASK mask);
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
@@ -104,6 +101,9 @@ public:
void onLineUpBtnPressed(const LLSD& data);
void onLineDownBtnPressed(const LLSD& data);
S32 getThickness() const { return mThickness; }
void setThickness(S32 thickness);
void setTrackColor( const LLColor4& color ) { mTrackColor = color; }
void setThumbColor( const LLColor4& color ) { mThumbColor = color; }
void setHighlightColor( const LLColor4& color ) { mHighlightColor = color; }
@@ -145,5 +145,4 @@ private:
};
#endif // LL_SCROLLBAR_H

View File

@@ -218,6 +218,15 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask)
return FALSE;
}
BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char)
{
if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char))
{
return TRUE;
}
return FALSE;
}
BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks )
{
// Give event to my child views - they may have scroll bars
@@ -262,7 +271,6 @@ BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,
EAcceptance* accept,
std::string& tooltip_msg)
{
//S32 scrollbar_size = SCROLLBAR_SIZE;
// Scroll folder view if needed. Never accepts a drag or drop.
*accept = ACCEPT_NO;
BOOL handled = autoScroll(x, y);
@@ -413,6 +421,7 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height
}
}
void LLScrollContainer::draw()
{
S32 scrollbar_size = SCROLLBAR_SIZE;
@@ -525,7 +534,7 @@ bool LLScrollContainer::addChild(LLView* view, S32 tab_group)
void LLScrollContainer::updateScroll()
{
if (!mScrolledView)
if (!getVisible() || !mScrolledView)
{
return;
}
@@ -626,6 +635,7 @@ LLRect LLScrollContainer::getVisibleContentRect()
visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom);
return visible_rect;
}
LLRect LLScrollContainer::getContentWindowRect()
{
updateScroll();
@@ -729,6 +739,13 @@ S32 LLScrollContainer::getBorderWidth() const
return 0;
}
void LLScrollContainer::setSize(S32 size)
{
mSize = size;
mScrollbar[VERTICAL]->setThickness(size);
mScrollbar[HORIZONTAL]->setThickness(size);
}
// virtual
LLXMLNodePtr LLScrollContainer::getXML(bool save_children) const
{

View File

@@ -2,31 +2,25 @@
* @file llscrollcontainer.h
* @brief LLScrollContainer class header file.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -78,7 +72,7 @@ public:
void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; }
LLRect getVisibleContentRect();
LLRect getContentWindowRect();
const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; }
virtual const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; }
void pageUp(S32 overlap = 0);
void pageDown(S32 overlap = 0);
void goToTop();
@@ -90,6 +84,7 @@ public:
// LLView functionality
virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleUnicodeCharHere(llwchar uni_char);
virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks );
virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
@@ -105,9 +100,14 @@ public:
virtual LLXMLNodePtr getXML(bool save_children) const;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
S32 getSize() const { return mSize; }
void setSize(S32 thickness);
protected:
LLView* mScrolledView;
private:
void init();
// internal scrollbar handlers
virtual void scrollHorizontal( S32 new_pos );
virtual void scrollVertical( S32 new_pos );
@@ -117,7 +117,6 @@ public:
private:
LLScrollbar* mScrollbar[SCROLLBAR_COUNT];
LLView* mScrolledView;
S32 mSize;
BOOL mIsOpaque;
LLColor4 mBackgroundColor;

View File

@@ -2712,39 +2712,20 @@ void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node)
node->getAttributeString("menu_file", menu);
if (!menu.empty()) setContextMenu(menu);
}
}
// static
LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
{
LLRect rect;
createRect(node, rect, parent, LLRect());
BOOL multi_select = false;
node->getAttributeBOOL("multi_select", multi_select);
BOOL draw_border = true;
node->getAttributeBOOL("draw_border", draw_border);
BOOL draw_heading = false;
node->getAttributeBOOL("draw_heading", draw_heading);
S32 search_column = 0;
node->getAttributeS32("search_column", search_column);
S32 sort_column = -1;
node->getAttributeS32("sort_column", sort_column);
BOOL sort_ascending = true;
node->getAttributeBOOL("sort_ascending", sort_ascending);
LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading);
if (node->hasAttribute("heading_height"))
{
S32 heading_height;
node->getAttributeS32("heading_height", heading_height);
scroll_list->setHeadingHeight(heading_height);
setHeadingHeight(heading_height);
}
scroll_list->setScrollListParameters(node);
scroll_list->initFromXML(node, parent);
scroll_list->setSearchColumn(search_column);
S32 search_column = 0;
node->getAttributeS32("search_column", search_column);
BOOL sort_ascending = true;
node->getAttributeBOOL("sort_ascending", sort_ascending);
setSearchColumn(search_column);
LLSD columns;
S32 index = 0;
@@ -2755,7 +2736,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
{
if (child->hasName("column") || child->hasName("columns") || child->hasName(kidcolumn) || child->hasName(kidcolumns))
{
std::string labelname("");
std::string labelname;
if (child->getAttributeString("label", labelname))
columns[index]["label"] = labelname;
else if (child->getAttributeString("image", labelname))
@@ -2778,9 +2759,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
}
else // Singu Note: if a scroll list does not provide sort_direction, provide sort_ascending to sort as expected
{
bool sort_ascending = true;
child->getAttribute_bool("sort_ascending", sort_ascending);
columns[index]["sort_ascending"] = sort_ascending;
bool col_sort_ascending = sort_ascending;
child->getAttribute_bool("sort_ascending", col_sort_ascending);
columns[index]["sort_ascending"] = col_sort_ascending;
}
S32 columnwidth = -1;
@@ -2806,12 +2787,7 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
++index;
}
}
scroll_list->setColumnHeadings(columns);
if (sort_column >= 0)
{
scroll_list->sortByColumnIndex(sort_column, sort_ascending);
}
setColumnHeadings(columns);
const std::string kidrow(nodename + "row");
const std::string kidrows(nodename + "rows");
@@ -2856,18 +2832,46 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac
}
}
if(explicit_column)
scroll_list->addElement(row);
addElement(row);
else
{
LLSD entry_id;
if(id_found)
entry_id = id;
scroll_list->addSimpleElement(value,ADD_BOTTOM,entry_id);
addSimpleElement(value,ADD_BOTTOM,entry_id);
}
}
}
scroll_list->setCommentText(node->getTextContents());
S32 sort_column = -1;
node->getAttributeS32("sort_column", sort_column);
if (sort_column >= 0)
{
sortByColumnIndex(sort_column, sort_ascending);
}
setCommentText(node->getTextContents());
}
// static
LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
{
LLRect rect;
createRect(node, rect, parent, LLRect());
BOOL multi_select = false;
node->getAttributeBOOL("multi_select", multi_select);
BOOL draw_border = true;
node->getAttributeBOOL("draw_border", draw_border);
BOOL draw_heading = false;
node->getAttributeBOOL("draw_heading", draw_heading);
LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading);
scroll_list->setScrollListParameters(node);
scroll_list->initFromXML(node, parent);
return scroll_list;
}

View File

@@ -202,7 +202,7 @@ public:
virtual S32 getFirstSelectedIndex() const;
std::vector<LLScrollListItem*> getAllSelected() const;
uuid_vec_t getSelectedIDs() const override final; //Helper. Much like getAllSelected, but just provides a LLUUID vec
S32 getNumSelected() const override final;
S32 getNumSelected() const;
LLScrollListItem* getLastSelectedItem() const { return mLastSelected; }
// iterate over all items

View File

@@ -1896,3 +1896,8 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y)
}
}
S32 LLTabContainer::getTotalTabWidth() const
{
return mTotalTabWidth;
}

View File

@@ -98,6 +98,7 @@ public:
S32 getIndexForPanel(LLPanel* panel);
S32 getPanelIndexByTitle(const std::string& title);
LLPanel* getPanelByName(const std::string& name);
S32 getTotalTabWidth() const;
void setCurrentTabName(const std::string& name);
void selectFirstTab();

View File

@@ -387,6 +387,7 @@ static LFIDBearer::Type get_type_from_url(const std::string& url)
auto type = url.substr(pos + 5, 5);
return type == "agent" ? LFIDBearer::AVATAR
: type == "group" ? LFIDBearer::GROUP
: type == "experience" ? LFIDBearer::EXPERIENCE
: LFIDBearer::OBJECT;
}
return LFIDBearer::NONE;

View File

@@ -38,6 +38,7 @@
#include "lltrans.h"
//#include "lluicolortable.h"
#include "message.h"
#include "llexperiencecache.h"
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp> // <alchemy/>
@@ -1492,6 +1493,58 @@ std::string LLUrlEntryEmail::getUrl(const std::string &string) const
return escapeUrl(string);
}
LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile()
{
mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*",
boost::regex::perl|boost::regex::icase);
mIcon = "Generic_Experience";
mMenuName = "menu_url_experience.xml";
}
std::string LLUrlEntryExperienceProfile::getLabel(const std::string& url, const LLUrlLabelCallback& cb)
{
if (!gCacheName)
{
// probably at the login screen, use short string for layout
return LLTrans::getString("LoadingData");
}
std::string experience_id_string = getIDStringFromUrl(url);
if (experience_id_string.empty())
{
// something went wrong, just give raw url
return unescapeUrl(url);
}
LLUUID experience_id(experience_id_string);
if (experience_id.isNull())
{
return LLTrans::getString("ExperienceNameNull");
}
const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
if (!experience_details.isUndefined())
{
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
return experience_name_string.empty() ? LLTrans::getString("ExperienceNameUntitled") : experience_name_string;
}
addObserver(experience_id_string, url, cb);
LLExperienceCache::instance().get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1));
return LLTrans::getString("LoadingData");
}
void LLUrlEntryExperienceProfile::onExperienceDetails(const LLSD& experience_details)
{
std::string name = experience_details[LLExperienceCache::NAME].asString();
if(name.empty())
{
name = LLTrans::getString("ExperienceNameUntitled");
}
callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null);
}
// <alchemy>
//
// LLUrlEntryJIRA describes a Jira Issue Tracker entry

View File

@@ -323,6 +323,20 @@ private:
/*virtual*/ std::string getName(const LLAvatarName& avatar_name) override;
};
///
/// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g.,
/// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile
/// that displays the experience namethat displays the experience name
class LLUrlEntryExperienceProfile : public LLUrlEntryBase
{
public:
LLUrlEntryExperienceProfile();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
private:
void onExperienceDetails(const LLSD& experience_details);
};
///
/// LLUrlEntryGroup Describes a Second Life group Url, e.g.,
/// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about

View File

@@ -73,6 +73,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryObjectIM());
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntryInventory());
registerUrl(new LLUrlEntryExperienceProfile());
//LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern,
//so it should be registered in the end of list
registerUrl(new LLUrlEntrySL());

View File

@@ -355,6 +355,10 @@ typedef enum e_lscript_state_event_type
LSTT_REMOTE_DATA,
LSTT_HTTP_RESPONSE,
LSTT_HTTP_REQUEST,
LSTT_EXPERMISSIONS,
LSTT_TRANSACTION_RESULT,
LSTT_PATH_UPDATE,
LSTT_EXPERMISSIONS_DENIED,
LSTT_EOF,
LSTT_STATE_BEGIN = LSTT_STATE_ENTRY,
@@ -397,7 +401,11 @@ const U64 LSCRIPTStateBitField[LSTT_EOF] =
0x0000000040000000, // LSTT_OBJECT_REZ
0x0000000080000000, // LSTT_REMOTE_DATA
0x0000000100000000LL, // LSTT_HTTP_RESPOSE
0x0000000200000000LL // LSTT_HTTP_REQUEST
0x0000000200000000LL, // LSTT_HTTP_REQUEST
0x0000000400000000LL, // LSTT_EXPERMISSIONS
0x0000000800000000LL, // LSTT_TRANSACTION_RESULT
0x0000001000000000LL, // LSTT_PATH_UPDATE
0x0000002000000000LL, //LSTT_EXPERMISSIONS_DENIED
};
inline S32 get_event_handler_jump_position(U64 bit_field, LSCRIPTStateEventType type)
@@ -511,6 +519,7 @@ typedef enum e_lscript_runtime_faults
LSRF_TOO_MANY_LISTENS,
LSRF_NESTING_LISTS,
LSRF_CLI,
LSRF_INVALID_STATE,
LSRF_EOF
} LSCRIPTRunTimeFaults;
@@ -551,10 +560,10 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] =
(0x1 << 10),// SCRIPT_PERMISSION_TRACK_CAMERA
(0x1 << 11),// SCRIPT_PERMISSION_CONTROL_CAMERA
(0x1 << 12),// SCRIPT_PERMISSION_TELEPORT
(0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE,
(0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT,
(0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS,
(0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS,
(0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE
(0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT
(0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS
(0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS
};
// http_request string constants

View File

@@ -685,6 +685,23 @@ void parse_string();
"STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); }
"STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); }
"XP_ERROR_NONE" { const char* sval= "no error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_THROTTLED" { const char* sval= "exceeded throttle"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_EXPERIENCES_DISABLED" { const char* sval= "experiences are disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_INVALID_PARAMETERS" { const char* sval= "invalid parameters"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_NOT_PERMITTED" { const char* sval= "operation not permitted"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_NO_EXPERIENCE" { const char* sval= "script not associated with an experience";yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_NOT_FOUND" { const char* sval= "not found"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_INVALID_EXPERIENCE" { const char* sval= "invalid experience"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_EXPERIENCE_DISABLED" { const char* sval= "experience is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_EXPERIENCE_SUSPENDED" { const char* sval= "experience is suspended"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_UNKNOWN_ERROR" { const char* sval= "unknown error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_QUOTA_EXCEEDED" { const char* sval= "experience data quota exceeded"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_STORE_DISABLED" { const char* sval= "key-value store is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_STORAGE_EXCEPTION" { const char* sval= "key-value store communication failed"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_KEY_NOT_FOUND" { const char* sval= "key doesn't exist"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"XP_ERROR_RETRY_UPDATE" { const char* sval= "retry update"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); }
"PROFILE_SCRIPT_NONE" { count(); yylval.ival = LSL_PROFILE_SCRIPT_NONE; return(INTEGER_CONSTANT); }
"PROFILE_SCRIPT_MEMORY" { count(); yylval.ival = LSL_PROFILE_SCRIPT_MEMORY; return(INTEGER_CONSTANT); }

View File

@@ -179,6 +179,8 @@
%type <event> money
%type <event> email
%type <event> run_time_permissions
%type <event> experience_permissions
%type <event> experience_permissions_denied
%type <event> inventory
%type <event> attach
%type <event> dataserver
@@ -787,6 +789,16 @@ event
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| experience_permissions compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| experience_permissions_denied compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
gAllocationManager->addAllocation($$);
}
| inventory compound_statement
{
$$ = new LLScriptEventHandler(gLine, gColumn, $1, $2);
@@ -1039,6 +1051,28 @@ run_time_permissions
}
;
experience_permissions
: EXPERIENCE_PERMISSIONS '(' LLKEY IDENTIFIER ')'
{
LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4);
gAllocationManager->addAllocation(id1);
$$ = new LLScriptEXPEvent(gLine, gColumn, id1);
gAllocationManager->addAllocation($$);
}
;
experience_permissions_denied
: EXPERIENCE_PERMISSIONS_DENIED '(' LLKEY IDENTIFIER ',' INTEGER IDENTIFIER ')'
{
LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4);
gAllocationManager->addAllocation(id1);
LLScriptIdentifier *id2 = new LLScriptIdentifier(gLine, gColumn, $7);
gAllocationManager->addAllocation(id2);
$$ = new LLScriptEXPDeniedEvent(gLine, gColumn, id1, id2);
gAllocationManager->addAllocation($$);
}
;
inventory
: INVENTORY '(' INTEGER IDENTIFIER ')'
{

View File

@@ -3712,6 +3712,155 @@ S32 LLScriptNoSensorEvent::getSize()
return 0;
}
void LLScriptEXPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
{
return;
}
switch(pass)
{
case LSCP_PRETTY_PRINT:
case LSCP_EMIT_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions( key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )\n");
break;
case LSCP_SCOPE_PASS1:
checkForDuplicateHandler(fp, this, scope, "experience_permissions");
if (scope->checkEntry(mName->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY);
}
break;
case LSCP_RESOURCE:
{
// we're just tryng to determine how much space the variable needs
if (mName->mScopeEntry)
{
mName->mScopeEntry->mOffset = (S32)count;
mName->mScopeEntry->mSize = 4;
count += mName->mScopeEntry->mSize;
}
}
break;
case LSCP_EMIT_BYTE_CODE:
{
#ifdef LSL_INCLUDE_DEBUG_INFO
char name[] = "experience_permissions";
chunk->addBytes(name, strlen(name) + 1);
chunk->addBytes(mName->mName, strlen(mName->mName) + 1);
#endif
}
break;
case LSCP_EMIT_CIL_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions( valuetype [ScriptTypes]LindenLab.SecondLife.Key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )");
break;
default:
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
break;
}
}
S32 LLScriptEXPEvent::getSize()
{
// key = 4
return 4;
}
void LLScriptEXPDeniedEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
{
return;
}
switch(pass)
{
case LSCP_PRETTY_PRINT:
case LSCP_EMIT_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions_denied( key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, ", integer ");
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )\n");
break;
case LSCP_SCOPE_PASS1:
checkForDuplicateHandler(fp, this, scope, "experience_permissions_denied");
if (scope->checkEntry(mName->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY);
}
if (scope->checkEntry(mReason->mName))
{
gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME);
}
else
{
mReason->mScopeEntry = scope->addEntry(mReason->mName, LIT_VARIABLE, LST_INTEGER);
}
break;
case LSCP_RESOURCE:
{
// we're just trying to determine how much space the variable needs
if (mName->mScopeEntry)
{
mName->mScopeEntry->mOffset = (S32)count;
mName->mScopeEntry->mSize = 4;
count += mName->mScopeEntry->mSize;
mReason->mScopeEntry->mOffset = (S32)count;
mReason->mScopeEntry->mSize = 4;
count += mReason->mScopeEntry->mSize;
}
}
break;
case LSCP_EMIT_BYTE_CODE:
{
#ifdef LSL_INCLUDE_DEBUG_INFO
char name[] = "experience_permissions_denied";
chunk->addBytes(name, strlen(name) + 1);
chunk->addBytes(mName->mName, strlen(mName->mName) + 1);
chunk->addBytes(mReason->mName, strlen(mReason->mName) + 1);
#endif
}
break;
case LSCP_EMIT_CIL_ASSEMBLY:
fdotabs(fp, tabs, tabsize);
fprintf(fp, "experience_permissions_denied( valuetype [ScriptTypes]LindenLab.SecondLife.Key ");
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, ", int32 ");
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
fprintf(fp, " )");
break;
default:
mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL);
break;
}
}
S32 LLScriptEXPDeniedEvent::getSize()
{
// key = 4 + integer
return LSCRIPTDataSize[LST_KEY]+LSCRIPTDataSize[LST_INTEGER];
}
void LLScriptAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata)
{
if (gErrorToText.getErrors())
@@ -8577,6 +8726,7 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa
}
}
prunearg = TRUE;
break;
case LSCP_TYPE:
// if there is a return expression, it must be promotable to the return type of the function
if (mExpression)
@@ -9775,7 +9925,13 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom
mScopeEntry->mFunctionArgs.addType(LST_STRING);
mScopeEntry->mFunctionArgs.addType(LST_STRING);
break;
case LSTT_EXPERMISSIONS:
mScopeEntry->mFunctionArgs.addType(LST_KEY);
break;
case LSTT_EXPERMISSIONS_DENIED:
mScopeEntry->mFunctionArgs.addType(LST_KEY);
mScopeEntry->mFunctionArgs.addType(LST_INTEGER);
break;
default:
break;
}

View File

@@ -633,6 +633,39 @@ public:
LLScriptIdentifier *mRTPermissions;
};
class LLScriptEXPEvent : public LLScriptEvent
{
public:
LLScriptEXPEvent(S32 line, S32 col, LLScriptIdentifier *name)
: LLScriptEvent(line, col, LSTT_EXPERMISSIONS), mName(name)
{
}
~LLScriptEXPEvent() {}
void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);
S32 getSize();
LLScriptIdentifier *mName;
};
class LLScriptEXPDeniedEvent : public LLScriptEvent
{
public:
LLScriptEXPDeniedEvent(S32 line, S32 col, LLScriptIdentifier *name, LLScriptIdentifier *reason)
: LLScriptEvent(line, col, LSTT_EXPERMISSIONS_DENIED), mName(name), mReason(reason)
{
}
~LLScriptEXPDeniedEvent() {}
void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata);
S32 getSize();
LLScriptIdentifier *mName;
LLScriptIdentifier *mReason;
};
class LLScriptChatEvent : public LLScriptEvent
{
public:

View File

@@ -181,6 +181,7 @@ set(viewer_SOURCE_FILES
lleventinfo.cpp
lleventnotifier.cpp
lleventpoll.cpp
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
llfasttimerview.cpp
@@ -221,6 +222,9 @@ set(viewer_SOURCE_FILES
llfloatereditui.cpp
llfloaterenvsettings.cpp
llfloaterevent.cpp
llfloaterexperiencepicker.cpp
llfloaterexperienceprofile.cpp
llfloaterexperiences.cpp
llfloaterexploreanimations.cpp
llfloaterexploresounds.cpp
llfloaterfeed.cpp
@@ -382,11 +386,16 @@ set(viewer_SOURCE_FILES
llpaneldisplay.cpp
llpaneleditwearable.cpp
llpanelevent.cpp
llpanelexperiencelisteditor.cpp
llpanelexperiencelog.cpp
llpanelexperiencepicker.cpp
llpanelexperiences.cpp
llpanelface.cpp
llpanelgeneral.cpp
llpanelgroup.cpp
llpanelgroupbulk.cpp
llpanelgroupbulkban.cpp
llpanelgroupexperiences.cpp
llpanelgroupgeneral.cpp
llpanelgroupinvite.cpp
llpanelgrouplandmoney.cpp
@@ -715,6 +724,7 @@ set(viewer_HEADER_FILES
lleventinfo.h
lleventnotifier.h
lleventpoll.h
llexperiencelog.h
llexternaleditor.h
llface.h
llfasttimerview.h
@@ -755,6 +765,9 @@ set(viewer_HEADER_FILES
llfloatereditui.h
llfloaterenvsettings.h
llfloaterevent.h
llfloaterexperiencepicker.h
llfloaterexperienceprofile.h
llfloaterexperiences.h
llfloaterexploreanimations.h
llfloaterexploresounds.h
llfloaterfeed.h
@@ -916,12 +929,17 @@ set(viewer_HEADER_FILES
llpaneldisplay.h
llpaneleditwearable.h
llpanelevent.h
llpanelexperiencelisteditor.h
llpanelexperiencelog.h
llpanelexperiencepicker.h
llpanelexperiences.h
llpanelface.h
llpanelgeneral.h
llpanelgroup.h
llpanelgroupbulk.h
llpanelgroupbulkban.h
llpanelgroupbulkimpl.h
llpanelgroupexperiences.h
llpanelgroupgeneral.h
llpanelgroupinvite.h
llpanelgrouplandmoney.h
@@ -1433,6 +1451,7 @@ endif (OPENAL)
if (USE_FMODSTUDIO)
list(APPEND LLSTARTUP_COMPILE_DEFINITIONS "LL_FMODSTUDIO=1")
set_source_files_properties(llpanellogin.cpp PROPERTIES COMPILE_DEFINITIONS "LL_FMODSTUDIO=1")
endif (USE_FMODSTUDIO)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_DEFINITIONS "${LLSTARTUP_COMPILE_DEFINITIONS}")

View File

@@ -1052,5 +1052,28 @@
<map/>
<key>llGetMaxScaleFactor</key>
<map/>
<!-- Experience Tools new functions -->
<key>llAgentInExperience</key>
<map/>
<key>llGetExperienceDetails</key>
<map/>
<key>llRequestExperiencePermissions</key>
<map/>
<key>llReadKeyValue</key>
<map/>
<key>llCreateKeyValue</key>
<map/>
<key>llUpdateKeyValue</key>
<map/>
<key>llDeleteKeyValue</key>
<map/>
<key>llDataSizeKeyValue</key>
<map/>
<key>llKeysKeyValue</key>
<map/>
<key>llKeyCountKeyValue</key>
<map/>
<key>llGetExperienceErrorMessage</key>
<map/>
</map>
</llsd>

View File

@@ -7500,6 +7500,54 @@ This should be as low as possible, but too low may break functionality</string>
<integer>0</integer>
</array>
</map>
<key>FloaterExperiencePickerRect</key>
<map>
<key>Comment</key>
<string>Rectangle for experience picker floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>300</integer>
<integer>600</integer>
<integer>800</integer>
<integer>700</integer>
</array>
</map>
<key>FloaterExperienceProfileRect</key>
<map>
<key>Comment</key>
<string>Rectangle for experience profile floaters</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>377</integer>
<integer>650</integer>
<integer>345</integer>
<integer>128</integer>
</array>
</map>
<key>FloaterExperiencesRect</key>
<map>
<key>Comment</key>
<string>Rectangle for experiences floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Rect</string>
<key>Value</key>
<array>
<integer>300</integer>
<integer>600</integer>
<integer>700</integer>
<integer>700</integer>
</array>
</map>
<key>FloaterFindRect2</key>
<map>
<key>Comment</key>
@@ -8257,7 +8305,7 @@ This should be as low as possible, but too low may break functionality</string>
<array>
<integer>0</integer>
<integer>512</integer>
<integer>480</integer>
<integer>500</integer>
<integer>0</integer>
</array>
</map>
@@ -11677,6 +11725,17 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>344</integer>
</map>
<key>PickerContextOpacity</key>
<map>
<key>Comment</key>
<string>Controls overall opacity of context frustrum connecting color and texture pickers with their swatches</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.34999999404</real>
</map>
<key>RevokePermsOnStandUp</key>
<map>
<key>Comment</key>

View File

@@ -565,6 +565,17 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>AlchemyDisableSimCamConstraint</key>
<map>
<key>Comment</key>
<string>Disable the push the simulator applies when camera collides with objects</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>AscentFlyAlwaysEnabled</key>
<map>
<key>Comment</key>
@@ -1622,6 +1633,17 @@ Changing this setting only affects new text.</string>
<key>IsCOA</key>
<integer>1</integer>
</map>
<key>ToolbarVisibleExperiences</key>
<map>
<key>Comment</key>
<string>Whether or not the button for the experiences floater is on the toolbar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<boolean>0</boolean>
</map>
<key>ToolbarVisibleFastTimers</key>
<map>
<key>Comment</key>

View File

@@ -438,6 +438,12 @@ NVIDIA GTX 770 .*NVIDIA .*GTX *77.* 3 1
NVIDIA GTX 780 .*NVIDIA .*GTX *78.* 3 1
NVIDIA GTX 970 .*NVIDIA .*GTX *97.* 3 1
NVIDIA GTX 980 .*NVIDIA .*GTX *98.* 3 1
NVIDIA GTX 1050 .*NVIDIA.*GTX 105.* 3 1
NVIDIA GTX 1060 .*NVIDIA.*GTX 106.* 3 1
NVIDIA GTX 1070 .*NVIDIA.*GTX 107.* 3 1
NVIDIA GTX 1080 .*NVIDIA.*GTX 108.* 3 1
NVIDIA GTX 1650 .*NVIDIA.*GTX 165.* 3 1
NVIDIA GTX 1660 .*NVIDIA.*GTX 166.* 3 1
NVIDIA GTX TITAN .*NVIDIA .*GTX *TITAN.* 3 1
NVIDIA GeForce/Quadro RTX .*(GeForce|Quadro) .*RTX.* 3 1
NVIDIA RTX TITAN .*NVIDIA .*RTX.*TITAN.* 3 1

View File

@@ -1730,6 +1730,14 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
mAutoPilotFinishedCallback(!user_cancel && dist_vec_squared(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < (mAutoPilotStopDistance * mAutoPilotStopDistance), mAutoPilotCallbackData);
mAutoPilotFinishedCallback = NULL;
}
// Sit response during follow pilot, now complete, resume follow
if (!user_cancel && mAutoPilotBehaviorName == "Sit" && mLeaderID.notNull())
{
startFollowPilot(mLeaderID, true, gSavedSettings.getF32("SinguFollowDistance"));
return;
}
mLeaderID = LLUUID::null;
mAutoPilotNoProgressFrameCount = 0;
@@ -1741,6 +1749,8 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
LLNotificationsUtil::add("CancelledSit");
else if (mAutoPilotBehaviorName == "Attach")
LLNotificationsUtil::add("CancelledAttach");
else if (mAutoPilotBehaviorName == "Follow")
LLNotificationsUtil::add("CancelledFollow");
else
LLNotificationsUtil::add("Cancelled");
}
@@ -1748,22 +1758,79 @@ void LLAgent::stopAutoPilot(BOOL user_cancel)
}
bool LLAgent::getAutoPilotNoProgress() const
{
return mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped;
}
// Returns necessary agent pitch and yaw changes, radians.
//-----------------------------------------------------------------------------
// autoPilot()
//-----------------------------------------------------------------------------
void LLAgent::autoPilot(F32 *delta_yaw)
{
if (mAutoPilot)
if (mAutoPilot && isAgentAvatarValid())
{
bool follow = !mLeaderID.isNull(); //mAutoPilotBehaviorName == "Follow";
U8 follow = mAutoPilotBehaviorName == "Follow";
if (follow)
{
llassert(mLeaderID.notNull());
const auto old_pos = mAutoPilotTargetGlobal;
if (auto object = gObjectList.findObject(mLeaderID))
{
mAutoPilotTargetGlobal = object->getPositionGlobal();
if (const auto& av = object->asAvatar()) // Fly if avatar target is flying
{
setFlying(av->mInAir);
if (av->isSitting() && (!rlv_handler_t::isEnabled() || !gRlvHandler.hasBehaviour(RLV_BHVR_SIT)))
{
if (auto seat = av->getParent())
{
if (gAgentAvatarp->getParent() == seat)
{
mAutoPilotNoProgressFrameCount = 0; // We may have incremented this before making it here, reset it
return; // We're seated with them, nothing more to do
}
else if (!getAutoPilotNoProgress())
{
void handle_object_sit(LLViewerObject*, const LLVector3&);
handle_object_sit(static_cast<LLViewerObject*>(seat), LLVector3::zero);
follow = 2; // Indicate ground sitting is okay if we can't make it
}
else return; // If the server just wouldn't let us sit there, we won't be moving, exit here
}
else // Ground sit, but only if near enough
{
if (dist_vec(av->getPositionAgent(), getPositionAgent()) <= mAutoPilotStopDistance) // We're close enough, sit.
{
if (!gAgentAvatarp->isSittingAvatarOnGround())
setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it now
return; // We're already sitting on the ground, we have nothing to do
}
else // We're not close enough yet
{
if (/*!gAgentAvatarp->isSitting() && */ // RLV takes care of sitting check for us inside standUp
getAutoPilotNoProgress()) // Only stand up if we haven't exhausted our no progress frames
standUp(); // Unsit if need be, so we can move
follow = 2; // Indicate we want to groundsit
}
}
}
else
{
if (dist_vec(av->getPositionAgent(), getPositionAgent()) <= mAutoPilotStopDistance)
{
follow = 3; // We're close enough, indicate no walking
}
if (gAgentAvatarp->isSitting()) // Leader isn't sitting, standUp if needed
{
standUp();
mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it
}
}
}
}
else // We might still have a valid avatar pos
{
@@ -1771,18 +1838,24 @@ void LLAgent::autoPilot(F32 *delta_yaw)
auto pos = get_av_pos(mLeaderID);
if (pos.isExactlyZero()) // Default constructed or invalid from server
{
mAutoPilotBehaviorName.clear(); // Nothing left to follow pilot
stopAutoPilot();
// Wait for them for more follow pilot
return;
}
standUp(); // Leader not rendered, we mustn't be sitting
mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it
mAutoPilotTargetGlobal = pos;
// Should we fly if the height difference is great enough here? Altitude is often invalid...
}
}
if (!isAgentAvatarValid()) return;
setFlying(true); // Should we fly here? Altitude is often invalid...
if (!follow && gAgentAvatarp->mInAir && mAutoPilotAllowFlying)
if (dist_vec(mAutoPilotTargetGlobal, getPositionGlobal()) <= mAutoPilotStopDistance)
{
follow = 3; // We're close enough, indicate no walking
}
}
if (old_pos != mAutoPilotTargetGlobal) // Reset if position changes
mAutoPilotNoProgressFrameCount = 0;
}
if (follow % 2 == 0 && gAgentAvatarp->mInAir && mAutoPilotAllowFlying)
{
setFlying(TRUE);
}
@@ -1794,12 +1867,15 @@ void LLAgent::autoPilot(F32 *delta_yaw)
F32 target_dist = direction.magVec();
if (!follow && target_dist >= mAutoPilotTargetDist)
if (follow % 2 == 0 && target_dist >= mAutoPilotTargetDist)
{
mAutoPilotNoProgressFrameCount++;
if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)
if (getAutoPilotNoProgress())
{
stopAutoPilot();
if (follow) // Well, we tried to reach them, let's just ground sit for now.
setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
else
stopAutoPilot();
return;
}
}
@@ -1841,6 +1917,7 @@ void LLAgent::autoPilot(F32 *delta_yaw)
}
*delta_yaw = yaw;
if (follow == 3) return; // We're close enough, all we need to do is turn
// Compute when to start slowing down
F32 slow_distance;

View File

@@ -593,13 +593,14 @@ public:
public:
BOOL getAutoPilot() const { return mAutoPilot; }
LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; }
LLUUID getAutoPilotLeaderID() const { return mLeaderID; }
const LLUUID& getAutoPilotLeaderID() const { return mLeaderID; }
F32 getAutoPilotStopDistance() const { return mAutoPilotStopDistance; }
F32 getAutoPilotTargetDist() const { return mAutoPilotTargetDist; }
BOOL getAutoPilotUseRotation() const { return mAutoPilotUseRotation; }
LLVector3 getAutoPilotTargetFacing() const { return mAutoPilotTargetFacing; }
F32 getAutoPilotRotationThreshold() const { return mAutoPilotRotationThreshold; }
std::string getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; }
const std::string& getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; }
bool getAutoPilotNoProgress() const;
void startAutoPilotGlobal(const LLVector3d &pos_global,
const std::string& behavior_name = std::string(),

View File

@@ -289,11 +289,6 @@ LLAgentCamera::~LLAgentCamera()
//-----------------------------------------------------------------------------
void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
{
if (gAgent.getAutoPilot())
{
gAgent.stopAutoPilot(TRUE);
}
LLSelectMgr::getInstance()->unhighlightAll();
// By popular request, keep land selection while walking around. JC

View File

@@ -35,13 +35,12 @@
#include "llviewerregion.h"
#include "llinventoryobserver.h"
#include "llviewercontrol.h"
#include <boost/bind.hpp>
///----------------------------------------------------------------------------
/// Classes for AISv3 support.
///----------------------------------------------------------------------------
class AISCommand : public LLHTTPClient::ResponderWithResult
class AISCommand final : public LLHTTPClient::ResponderWithCompleted
{
public:
typedef boost::function<void()> command_func_type;
@@ -60,35 +59,28 @@ public:
(mCommandFunc = func)();
}
char const* getName(void) const
char const* getName(void) const override
{
return mName;
}
void markComplete()
{
mRetryPolicy->onSuccess();
}
protected:
/* virtual */
void httpSuccess()
{
// Command func holds a reference to self, need to release it
// after a success or final failure.
mCommandFunc = no_op;
AISAPI::InvokeAISCommandCoro(this, getURL(), mTargetId, getContent(), mCompletionFunc, (AISAPI::COMMAND_TYPE)mType);
mRetryPolicy->onSuccess();
}
/*virtual*/
void httpFailure()
void malformedResponse() { mStatus = HTTP_INTERNAL_ERROR_OTHER; mReason = llformat("Malformed response contents (original code: %d)", mStatus); }
bool onFailure()
{
LL_WARNS("Inventory") << dumpResponse() << LL_ENDL;
S32 status = getStatus();
const AIHTTPReceivedHeaders& headers = getResponseHeaders();
mRetryPolicy->onFailure(status, headers);
bool retry = mStatus != HTTP_INTERNAL_ERROR_OTHER && mStatus != 410; // We handle these and stop
LL_WARNS("Inventory") << "Inventory error: " << dumpResponse() << LL_ENDL;
if (retry) mRetryPolicy->onFailure(mStatus, getResponseHeaders());
F32 seconds_to_wait;
if (mRetryPolicy->shouldRetry(seconds_to_wait))
if (retry && mRetryPolicy->shouldRetry(seconds_to_wait))
{
doAfterInterval(mCommandFunc,seconds_to_wait);
}
@@ -99,6 +91,13 @@ protected:
// *TODO: Notify user? This seems bad.
mCommandFunc = no_op;
}
return retry;
}
protected:
void httpCompleted() override
{
AISAPI::InvokeAISCommandCoro(this, getURL(), mTargetId, getContent(), mCompletionFunc, (AISAPI::COMMAND_TYPE)mType);
}
command_func_type mCommandFunc;
@@ -313,31 +312,97 @@ void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t
boost::intrusive_ptr< AISCommand > responder = new AISCommand(UPDATEITEM, "UpdateItem",itemId, callback);
responder->run(boost::bind(&LLHTTPClient::patch, url, updates, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, (AIStateMachine*)NULL, 0));
}
void AISAPI::InvokeAISCommandCoro(LLHTTPClient::ResponderWithResult* responder,
std::string url,
void AISAPI::InvokeAISCommandCoro(AISCommand* responder,
std::string url,
LLUUID targetId, LLSD result, completion_t callback, COMMAND_TYPE type)
{
LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
auto status = responder->getStatus();
if (!responder->isGoodStatus(status) || !result.isMap())
{
if (!result.isMap())
{
responder->failureResult(400, "Malformed response contents", result);
return;
responder->malformedResponse();
}
((AISCommand*)responder)->markComplete();
else if (status == 410) //GONE
{
// Item does not exist or was already deleted from server.
// parent folder is out of sync
if (type == REMOVECATEGORY)
{
LLViewerInventoryCategory *cat = gInventory.getCategory(targetId);
if (cat)
{
LL_WARNS("Inventory") << "Purge failed for '" << cat->getName()
<< "' local version:" << cat->getVersion()
<< " since folder no longer exists at server. Descendent count: server == " << cat->getDescendentCount()
<< ", viewer == " << cat->getViewerDescendentCount()
<< LL_ENDL;
gInventory.fetchDescendentsOf(cat->getParentUUID());
// Note: don't delete folder here - contained items will be deparented (or deleted)
// and since we are clearly out of sync we can't be sure we won't get rid of something we need.
// For example folder could have been moved or renamed with items intact, let it fetch first.
}
}
else if (type == REMOVEITEM)
{
LLViewerInventoryItem *item = gInventory.getItem(targetId);
if (item)
{
LL_WARNS("Inventory") << "Purge failed for '" << item->getName()
<< "' since item no longer exists at server." << LL_ENDL;
gInventory.fetchDescendentsOf(item->getParentUUID());
// since item not on the server and exists at viewer, so it needs an update at the least,
// so delete it, in worst case item will be refetched with new params.
gInventory.onObjectDeletedFromServer(targetId);
}
}
}
// Keep these statuses accounted for in the responder too
if (responder->onFailure()) // If we're retrying, exit early.
return;
}
else responder->markComplete();
gInventory.onAISUpdateReceived("AISCommand", result);
if (callback && callback != nullptr)
{
LLUUID id(LLUUID::null);
if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7
uuid_list_t ids;
switch (type)
{
id = result["category_id"];
case COPYLIBRARYCATEGORY:
if (result.has("category_id"))
{
ids.insert(result["category_id"]);
}
break;
case COPYINVENTORY:
{
AISUpdate::parseUUIDArray(result, "_created_items", ids);
AISUpdate::parseUUIDArray(result, "_created_categories", ids);
}
break;
default:
break;
}
callback(id);
// If we were feeling daring we'd call LLInventoryCallback::fire for every item but it would take additional work to investigate whether all LLInventoryCallback derived classes
// were designed to handle multiple fire calls (with legacy link creation only one would ever fire per link creation) so we'll be cautious and only call for the first one for now
// (note that the LL code as written below will always call fire once with the NULL UUID for anything but CopyLibraryCategoryCommand so even the above is an improvement)
callback( (!ids.empty()) ? *ids.begin() : LLUUID::null);
// [/SL:KB]
// LLUUID id(LLUUID::null);
//
// if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
// {
// id = result["category_id"];
// }
//
// callback(id);
}
}
@@ -374,18 +439,17 @@ void AISUpdate::parseMeta(const LLSD& update)
// parse _categories_removed -> mObjectsDeletedIds
uuid_list_t cat_ids;
parseUUIDArray(update,"_categories_removed",cat_ids);
for (uuid_list_t::const_iterator it = cat_ids.begin();
it != cat_ids.end(); ++it)
for (auto cat_id : cat_ids)
{
LLViewerInventoryCategory *cat = gInventory.getCategory(*it);
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
if(cat)
{
mCatDescendentDeltas[cat->getParentUUID()]--;
mObjectsDeletedIds.insert(*it);
mObjectsDeletedIds.insert(cat_id);
}
else
{
LL_WARNS("Inventory") << "removed category not found " << *it << LL_ENDL;
LL_WARNS("Inventory") << "removed category not found " << cat_id << LL_ENDL;
}
}
@@ -393,36 +457,34 @@ void AISUpdate::parseMeta(const LLSD& update)
uuid_list_t item_ids;
parseUUIDArray(update,"_category_items_removed",item_ids);
parseUUIDArray(update,"_removed_items",item_ids);
for (uuid_list_t::const_iterator it = item_ids.begin();
it != item_ids.end(); ++it)
for (auto item_id : item_ids)
{
LLViewerInventoryItem *item = gInventory.getItem(*it);
LLViewerInventoryItem *item = gInventory.getItem(item_id);
if(item)
{
mCatDescendentDeltas[item->getParentUUID()]--;
mObjectsDeletedIds.insert(*it);
mObjectsDeletedIds.insert(item_id);
}
else
{
LL_WARNS("Inventory") << "removed item not found " << *it << LL_ENDL;
LL_WARNS("Inventory") << "removed item not found " << item_id << LL_ENDL;
}
}
// parse _broken_links_removed -> mObjectsDeletedIds
uuid_list_t broken_link_ids;
parseUUIDArray(update,"_broken_links_removed",broken_link_ids);
for (uuid_list_t::const_iterator it = broken_link_ids.begin();
it != broken_link_ids.end(); ++it)
for (auto broken_link_id : broken_link_ids)
{
LLViewerInventoryItem *item = gInventory.getItem(*it);
LLViewerInventoryItem *item = gInventory.getItem(broken_link_id);
if(item)
{
mCatDescendentDeltas[item->getParentUUID()]--;
mObjectsDeletedIds.insert(*it);
mObjectsDeletedIds.insert(broken_link_id);
}
else
{
LL_WARNS("Inventory") << "broken link not found " << *it << LL_ENDL;
LL_WARNS("Inventory") << "broken link not found " << broken_link_id << LL_ENDL;
}
}
@@ -766,7 +828,7 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
void AISUpdate::doUpdate()
{
// Do version/descendent accounting.
// Do version/descendant accounting.
for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin();
catit != mCatDescendentDeltas.end(); ++catit)
{
@@ -787,7 +849,7 @@ void AISUpdate::doUpdate()
continue;
}
// If we have a known descendent count, set that now.
// If we have a known descendant count, set that now.
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
if (cat)
{
@@ -824,7 +886,7 @@ void AISUpdate::doUpdate()
LLUUID category_id(update_it->first);
LLPointer<LLViewerInventoryCategory> new_category = update_it->second;
// Since this is a copy of the category *before* the accounting update, above,
// we need to transfer back the updated version/descendent count.
// we need to transfer back the updated version/descendant count.
LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID());
if (!curr_cat)
{
@@ -868,21 +930,19 @@ void AISUpdate::doUpdate()
}
// DELETE OBJECTS
for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin();
del_it != mObjectsDeletedIds.end(); ++del_it)
for (auto deleted_id : mObjectsDeletedIds)
{
LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL;
gInventory.onObjectDeletedFromServer(*del_it, false, false, false);
LL_DEBUGS("Inventory") << "deleted item " << deleted_id << LL_ENDL;
gInventory.onObjectDeletedFromServer(deleted_id, false, false, false);
}
// TODO - how can we use this version info? Need to be sure all
// changes are going through AIS first, or at least through
// something with a reliable responder.
for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin();
ucv_it != mCatVersionsUpdated.end(); ++ucv_it)
for (auto& ucv_it : mCatVersionsUpdated)
{
const LLUUID id = ucv_it->first;
S32 version = ucv_it->second;
const LLUUID id = ucv_it.first;
S32 version = ucv_it.second;
LLViewerInventoryCategory *cat = gInventory.getCategory(id);
LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL;
if (cat->getVersion() != version)
@@ -898,7 +958,16 @@ void AISUpdate::doUpdate()
// inventory COF is maintained on the viewer through calls to
// LLInventoryModel::accountForUpdate when a changing operation
// is performed. This occasionally gets out of sync however.
cat->setVersion(version);
if (version != LLViewerInventoryCategory::VERSION_UNKNOWN)
{
cat->setVersion(version);
}
else
{
// We do not account for update if version is UNKNOWN, so we shouldn't rise version
// either or viewer will get stuck on descendants count -1, try to refetch folder instead
cat->fetch();
}
}
}

View File

@@ -72,7 +72,7 @@ private:
static std::string getInvCap();
static std::string getLibCap();
static void InvokeAISCommandCoro( LLHTTPClient::ResponderWithResult* responder,
static void InvokeAISCommandCoro(class AISCommand* responder,
std::string url, LLUUID targetId, LLSD body,
completion_t callback, COMMAND_TYPE type);
};
@@ -84,7 +84,10 @@ public:
void parseUpdate(const LLSD& update);
void parseMeta(const LLSD& update);
void parseContent(const LLSD& update);
void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7
static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
// [/SL:KB]
// void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids);
void parseLink(const LLSD& link_map);
void parseItem(const LLSD& link_map);
void parseCategory(const LLSD& link_map);

View File

@@ -4184,7 +4184,7 @@ LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, L
// 2) Stuff with requests via makeLink and makeCopy
// 3) Call dispatch()
// 4) Let the LLPointer go out of scope.
class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce
class LLCreateLegacyOutfit final : public LLBoostFuncInventoryCallbackFireOnce
{
public:
LLCreateLegacyOutfit(const LLUUID& folder_id, inventory_func_type fire_func, nullary_func_type destroy_func = no_op) :

View File

@@ -95,6 +95,7 @@
// Linden library includes
#include "llavatarnamecache.h"
#include "lldiriterator.h"
#include "llexperiencecache.h"
#include "llimagej2c.h"
#include "llmemory.h"
#include "llprimitive.h"
@@ -2287,7 +2288,9 @@ bool LLAppViewer::initConfiguration()
LL_INFOS() << "Loading settings file list" << settings_file_list << LL_ENDL;
if (0 == settings_control.loadFromFile(settings_file_list))
{
LL_ERRS() << "Cannot load default configuration file " << settings_file_list << LL_ENDL;
OSMessageBox("Cannot load default configuration file " + settings_file_list + " The installation may be corrupted.",
LLStringUtil::null,OSMB_OK);
return false;
}
mSettingsLocationList = settings_control.getLLSD("Locations");
@@ -4177,6 +4180,7 @@ void LLAppViewer::idle()
// floating throughout the various object lists.
//
idleNameCache();
if (gAgent.getRegion()) LLExperienceCache::instance().idleCoro();
gFrameStats.start(LLFrameStats::IDLE_NETWORK);
stop_glerror();
@@ -4841,6 +4845,12 @@ void LLAppViewer::disconnectViewer()
}
saveNameCache();
if (LLExperienceCache::instanceExists())
{
// TODO: LLExperienceCache::cleanup() logic should be moved to
// cleanupSingleton().
LLExperienceCache::instance().cleanup();
}
// close inventory interface, close all windows
LLPanelMainInventory::cleanup();

View File

@@ -171,6 +171,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier)
body["item_id"] = data.mItemId;
body["is_script_running"] = data.mIsRunning;
body["target"] = data.mIsTargetMono? "mono" : "lsl2";
body["experience"] = data.mExperienceId;
std::string url = "";
LLViewerObject* object = gObjectList.findObject(data.mTaskId);
@@ -194,7 +195,8 @@ void LLAssetUploadQueue::queue(const std::string& filename,
const LLUUID& queue_id,
U8* script_data,
U32 data_size,
std::string script_name)
std::string script_name,
const LLUUID& experience_id)
{
UploadData data;
data.mTaskId = task_id;
@@ -206,6 +208,7 @@ void LLAssetUploadQueue::queue(const std::string& filename,
data.mData = script_data;
data.mDataSize = data_size;
data.mScriptName = script_name;
data.mExperienceId = experience_id;
mQueue.push_back(data);

View File

@@ -56,7 +56,8 @@ public:
const LLUUID& queue_id,
U8* data,
U32 data_size,
std::string script_name);
std::string script_name,
const LLUUID& experience_id);
bool isEmpty() const {return mQueue.empty();}
@@ -75,6 +76,7 @@ private:
U8* mData;
U32 mDataSize;
std::string mScriptName;
LLUUID mExperienceId;
};
// Ownership of mSupplier passed to currently waiting responder

View File

@@ -1197,7 +1197,7 @@ void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::stri
calling_card_folder_id);
LLSD args;
args["TO_NAME"] = target_name;
args["TO_NAME"] = getSLURL(target_id);
LLSD payload;
payload["from_id"] = target_id;

View File

@@ -65,6 +65,7 @@
#include "lltrans.h"
#include "llselectmgr.h"
#include "llexperiencecache.h"
// *TODO: This should be separated into the script queue, and the floater views of that queue.
// There should only be one floater class that can view any queue type
@@ -76,12 +77,12 @@
struct LLScriptQueueData
{
LLUUID mQueueID;
std::string mScriptName;
LLPointer<LLInventoryItem> mItemp;
LLUUID mTaskId;
LLUUID mItemId;
LLScriptQueueData(const LLUUID& q_id, const std::string& name, const LLUUID& task_id, const LLUUID& item_id) :
mQueueID(q_id), mScriptName(name), mTaskId(task_id), mItemId(item_id) {}
LLUUID mExperienceId;
LLHost mHost;
LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item, const LLHost& host) :
mQueueID(q_id), mTaskId(task_id), mItemp(item), mHost(host) {}
};
///----------------------------------------------------------------------------
@@ -220,7 +221,7 @@ BOOL LLFloaterScriptQueue::nextObject()
LL_INFOS() << "LLFloaterScriptQueue::nextObject() - " << count
<< " objects left to process." << LL_ENDL;
mCurrentObjectID.setNull();
if(count > 0)
if (count > 0)
{
successful_start = popNext();
}
@@ -228,7 +229,7 @@ BOOL LLFloaterScriptQueue::nextObject()
<< (successful_start ? "successful" : "unsuccessful")
<< LL_ENDL;
} while((mObjectIDs.size() > 0) && !successful_start);
if(isDone() && !mDone)
if (isDone() && !mDone)
{
mDone = true;
getChild<LLScrollListCtrl>("queue output")->addSimpleElement(getString("Done"), ADD_BOTTOM);
@@ -245,14 +246,14 @@ BOOL LLFloaterScriptQueue::popNext()
// the inventory.
BOOL rv = FALSE;
S32 count = mObjectIDs.size();
if(mCurrentObjectID.isNull() && (count > 0))
if (mCurrentObjectID.isNull() && (count > 0))
{
mCurrentObjectID = mObjectIDs.at(0);
LL_INFOS() << "LLFloaterScriptQueue::popNext() - mCurrentID: "
<< mCurrentObjectID << LL_ENDL;
mObjectIDs.erase(mObjectIDs.begin());
LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID);
if(obj)
if (obj)
{
LL_INFOS() << "LLFloaterScriptQueue::popNext() requesting inv for "
<< mCurrentObjectID << LL_ENDL;
@@ -270,35 +271,21 @@ BOOL LLFloaterScriptQueue::startQueue()
return nextObject();
}
#if 0 // Singu TODO: Experiences
class CompileQueueExperienceResponder : public LLHTTPClient::ResponderWithResult
class CompileQueueExperienceResponder final : public LLHTTPClient::ResponderWithResult
{
const LLUUID mParent;
public:
CompileQueueExperienceResponder(const LLUUID& parent):mParent(parent)
{
}
CompileQueueExperienceResponder(const LLUUID& parent): mParent(parent) {}
LLUUID mParent;
/*virtual*/ void httpSuccess()
{
sendResult(getContent());
}
/*virtual*/ void httpFailure()
{
sendResult(LLSD());
}
void httpSuccess() override { sendResult(getContent()); }
void httpFailure() override { sendResult(LLSD()); }
void sendResult(const LLSD& content)
{
LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mParent);
if(!queue)
return;
queue->experienceIdsReceived(content["experience_ids"]);
if (auto queue = static_cast<LLFloaterCompileQueue*>(LLFloaterCompileQueue::findInstance(mParent)))
queue->experienceIdsReceived(content["experience_ids"]);
}
/*virtual*/ char const* getName() const { return "RequiredRubbish"; }
char const* getName() const override { return "CompileQueueExperienceResponder"; }
};
#endif
@@ -318,7 +305,7 @@ public:
virtual LLAssetUploadQueue* get() const
{
LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId);
if(NULL == queue)
if (NULL == queue)
{
return NULL;
}
@@ -328,7 +315,7 @@ public:
virtual void log(std::string message) const
{
LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId);
if(NULL == queue)
if (NULL == queue)
{
return;
}
@@ -363,6 +350,21 @@ LLFloaterCompileQueue::~LLFloaterCompileQueue()
{
}
void LLFloaterCompileQueue::experienceIdsReceived(const LLSD& content)
{
for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it)
{
mExperienceIds.insert(it->asUUID());
}
nextObject();
}
BOOL LLFloaterCompileQueue::hasExperience(const LLUUID& id) const
{
return mExperienceIds.find(id) != mExperienceIds.end();
}
void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
LLInventoryObject::object_list_t* inv)
{
@@ -376,7 +378,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
LLInventoryObject::object_list_t::const_iterator end = inv->end();
for ( ; it != end; ++it)
{
if((*it)->getType() == LLAssetType::AT_LSL_TEXT)
if ((*it)->getType() == LLAssetType::AT_LSL_TEXT)
{
LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
// Check permissions before allowing the user to retrieve data.
@@ -397,31 +399,68 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object,
}
else
{
// request all of the assets.
uuid_item_map::iterator iter;
for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++)
LLViewerRegion* region = viewer_object->getRegion();
std::string url = std::string();
if (region)
{
LLInventoryItem *itemp = iter->second;
LLScriptQueueData* datap = new LLScriptQueueData(getID(),
itemp->getName(),
viewer_object->getID(),
itemp->getUUID());
url = region->getCapability("GetMetadata");
}
//LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL;
gAssetStorage->getInvItemAsset(viewer_object->getRegion()->getHost(),
gAgent.getID(),
gAgent.getSessionID(),
itemp->getPermissions().getOwner(),
viewer_object->getID(),
itemp->getUUID(),
itemp->getAssetUUID(),
itemp->getType(),
LLFloaterCompileQueue::scriptArrived,
(void*)datap);
const auto& host = region->getHost();
const auto& obj_id = viewer_object->getID();
// request all of the assets.
for(const auto& pair : asset_item_map)
{
LLInventoryItem *itemp = pair.second;
LLScriptQueueData* datap = new LLScriptQueueData(getID(),
obj_id,
itemp,
host);
LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(),
boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1));
}
}
}
void LLFloaterCompileQueue::requestAsset(LLScriptQueueData* datap, const LLSD& experience)
{
LLFloaterCompileQueue* queue = static_cast<LLFloaterCompileQueue*>(findInstance(datap->mQueueID));
if (!queue)
{
delete datap;
return;
}
if (experience.has(LLExperienceCache::EXPERIENCE_ID))
{
datap->mExperienceId = experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
if (!queue->hasExperience(datap->mExperienceId))
{
std::string buffer = LLTrans::getString("CompileNoExperiencePerm", LLSD::emptyMap()
.with("SCRIPT", datap->mItemp->getName())
.with("EXPERIENCE", experience[LLExperienceCache::NAME].asString()));
queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
queue->removeItemByItemID(datap->mItemp->getUUID());
delete datap;
return;
}
}
//LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL;
gAssetStorage->getInvItemAsset(datap->mHost,
gAgent.getID(),
gAgent.getSessionID(),
datap->mItemp->getPermissions().getOwner(),
datap->mTaskId,
datap->mItemp->getUUID(),
datap->mItemp->getAssetUUID(),
datap->mItemp->getType(),
LLFloaterCompileQueue::scriptArrived,
(void*)datap);
}
// This is the callback for when each script arrives
// static
@@ -438,9 +477,9 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
LLFloaterCompileQueue* queue = static_cast<LLFloaterCompileQueue*> (LLFloaterScriptQueue::findInstance(data->mQueueID));
std::string buffer;
if(queue && (0 == status))
if (queue && (0 == status))
{
//LL_INFOS() << "ITEM NAME 3: " << data->mScriptName << LL_ENDL;
//LL_INFOS() << "ITEM NAME 3: " << data->mItemp->getName() << LL_ENDL;
// Dump this into a file on the local disk so we can compile it.
std::string filename;
@@ -454,7 +493,7 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
if (object)
{
std::string url = object->getRegion()->getCapability("UpdateScriptTask");
if(!url.empty())
if (!url.empty())
{
// Read script source in to buffer.
U32 script_size = file.getSize();
@@ -462,17 +501,17 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
file.read(script_data, script_size);
queue->mUploadQueue->queue(filename, data->mTaskId,
data->mItemId, is_running, queue->mMono, queue->getID(),
script_data, script_size, data->mScriptName);
data->mItemp->getUUID(), is_running, queue->mMono, queue->getID(),
script_data, script_size, data->mItemp->getName(), data->mExperienceId);
}
else
{
std::string text = LLTrans::getString("CompileQueueProblemUploading");
LLChat chat(text);
LLFloaterChat::addChat(chat);
buffer = text + LLTrans::getString(":") + ' ' + data->mScriptName;
buffer = text + LLTrans::getString(":") + ' ' + data->mItemp->getName();
LL_WARNS() << "Problem uploading script asset." << LL_ENDL;
if(queue) queue->removeItemByItemID(data->mItemId);
if(queue) queue->removeItemByItemID(data->mItemp->getUUID());
}
}
}
@@ -480,29 +519,29 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
{
LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status )
if ( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status )
{
LLChat chat(LLTrans::getString("CompileQueueScriptNotFound"));
LLFloaterChat::addChat(chat);
buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + ' ' + data->mScriptName;
buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + ' ' + data->mItemp->getName();
}
else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
{
LLChat chat(LLTrans::getString("CompileQueueInsufficientPermDownload"));
LLFloaterChat::addChat(chat);
buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + ' ' + data->mScriptName;
buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + ' ' + data->mItemp->getName();
}
else
{
buffer = LLTrans::getString("CompileQueueUnknownFailure") + ' ' + data->mScriptName;
buffer = LLTrans::getString("CompileQueueUnknownFailure") + ' ' + data->mItemp->getName();
}
LL_WARNS() << "Problem downloading script asset." << LL_ENDL;
if(queue) queue->removeItemByItemID(data->mItemId);
if(queue) queue->removeItemByItemID(data->mItemp->getUUID());
}
if(queue && (buffer.size() > 0))
if (queue && (buffer.size() > 0))
{
queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(buffer, ADD_BOTTOM);
}
@@ -528,7 +567,7 @@ void LLFloaterCompileQueue::saveItemByItemID(const LLUUID& asset_id)
{
LL_INFOS() << "LLFloaterCompileQueue::saveItemByAssetID()" << LL_ENDL;
LLViewerObject* viewer_object = gObjectList.findObject(mCurrentObjectID);
if(viewer_object)
if (viewer_object)
{
S32 count = mCurrentScripts.size();
for(S32 i = 0; i < count; ++i)
@@ -582,7 +621,7 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t::const_iterator end = inv->end();
for ( ; it != end; ++it)
{
if((*it)->getType() == LLAssetType::AT_LSL_TEXT)
if ((*it)->getType() == LLAssetType::AT_LSL_TEXT)
{
LLViewerObject* object = gObjectList.findObject(viewer_obj->getID());
@@ -641,7 +680,7 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t::const_iterator end = inv->end();
for ( ; it != end; ++it)
{
if((*it)->getType() == LLAssetType::AT_LSL_TEXT)
if ((*it)->getType() == LLAssetType::AT_LSL_TEXT)
{
LLViewerObject* object = gObjectList.findObject(viewer_obj->getID());
@@ -716,17 +755,16 @@ void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id)
BOOL LLFloaterCompileQueue::startQueue()
{
/* Singu TODO: Experiences
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
std::string lookup_url=region->getCapability("GetCreatorExperiences");
if(!lookup_url.empty())
std::string lookup_url = region->getCapability("GetCreatorExperiences");
if (!lookup_url.empty())
{
LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(getKey().asUUID()));
LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(mID));
return TRUE;
}
}*/
}
return nextObject();
}
@@ -741,7 +779,7 @@ void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t::const_iterator end = inv->end();
for ( ; it != end; ++it)
{
if((*it)->getType() == LLAssetType::AT_LSL_TEXT)
if ((*it)->getType() == LLAssetType::AT_LSL_TEXT)
{
LLViewerObject* object = gObjectList.findObject(viewer_obj->getID());

View File

@@ -103,7 +103,7 @@ protected:
// Get this instance's ID.
const LLUUID& getID() const { return mID; }
protected:
// UI
LLScrollListCtrl* mMessages;
@@ -149,8 +149,8 @@ public:
LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; }
void experienceIdsReceived( const LLSD& content );
BOOL hasExperience(const LLUUID& id)const;
void experienceIdsReceived(const LLSD& content);
BOOL hasExperience(const LLUUID& id) const;
protected:
LLFloaterCompileQueue(const std::string& name, const LLRect& rect);
@@ -160,6 +160,9 @@ protected:
virtual void handleInventory(LLViewerObject* viewer_obj,
LLInventoryObject::object_list_t* inv);
static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience);
// This is the callback for when each script arrives
static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id,
LLAssetType::EType type,

View File

@@ -0,0 +1,287 @@
/**
* @file llexperiencelog.cpp
* @brief llexperiencelog implementation
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llexperiencelog.h"
#include "lldispatcher.h"
#include "llsdserialize.h"
#include "llviewergenericmessage.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llerror.h"
#include "lldate.h"
class LLExperienceLogDispatchHandler : public LLDispatchHandler
{
public:
bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings) override
{
LLSD message;
sparam_t::const_iterator it = strings.begin();
if(it != strings.end()){
const std::string& llsdRaw = *it++;
std::istringstream llsdData(llsdRaw);
if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
{
LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
}
}
message["public_id"] = invoice;
// Object Name
if(it != strings.end())
{
message["ObjectName"] = *it++;
}
// parcel Name
if(it != strings.end())
{
message["ParcelName"] = *it++;
}
message["Count"] = 1;
LLExperienceLog::instance().handleExperienceMessage(message);
return true;
}
};
static LLExperienceLogDispatchHandler experience_log_dispatch_handler;
void LLExperienceLog::handleExperienceMessage(LLSD& message)
{
time_t now;
time(&now);
char daybuf[16];/* Flawfinder: ignore */
char time_of_day[16];/* Flawfinder: ignore */
strftime(daybuf, 16, "%Y-%m-%d", localtime(&now));
strftime(time_of_day, 16, " %H:%M:%S", localtime(&now));
message["Time"] = time_of_day;
std::string day = daybuf;
if(!mEvents.has(day))
{
mEvents[day] = LLSD::emptyArray();
}
LLSD& dayEvents = mEvents[day];
if(dayEvents.size() > 0)
{
LLSD& last = *(dayEvents.rbeginArray());
if( last["public_id"].asUUID() == message["public_id"].asUUID()
&& last["ObjectName"].asString() == message["ObjectName"].asString()
&& last["OwnerID"].asUUID() == message["OwnerID"].asUUID()
&& last["ParcelName"].asString() == message["ParcelName"].asString()
&& last["Permission"].asInteger() == message["Permission"].asInteger())
{
last["Count"] = last["Count"].asInteger() + 1;
last["Time"] = time_of_day;
mSignals(last);
return;
}
}
message["Time"] = time_of_day;
mEvents[day].append(message);
mSignals(message);
}
LLExperienceLog::LLExperienceLog()
: mMaxDays(7)
, mPageSize(25)
, mNotifyNewEvent(false)
{
}
void LLExperienceLog::initialize()
{
loadEvents();
if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent"))
{
gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler);
}
}
std::string LLExperienceLog::getFilename()
{
return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml");
}
std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base )
{
std::ostringstream buf;
if(message.has("Permission"))
{
buf << base << message["Permission"].asInteger();
std::string entry;
if(LLTrans::findString(entry, buf.str()))
{
buf.str(entry);
}
}
if(buf.str().empty())
{
buf << base << "Unknown";
buf.str(LLTrans::getString(buf.str(), message));
}
return buf.str();
}
void LLExperienceLog::notify( LLSD& message )
{
message["EventType"] = getPermissionString(message, "ExperiencePermission");
if(message.has("IsAttachment") && message["IsAttachment"].asBoolean())
{
LLNotificationsUtil::add("ExperienceEventAttachment", message);
}
else
{
LLNotificationsUtil::add("ExperienceEvent", message);
}
message.erase("EventType");
}
void LLExperienceLog::saveEvents()
{
eraseExpired();
std::string filename = getFilename();
LLSD settings = LLSD::emptyMap().with("Events", mEvents);
settings["MaxDays"] = (int)mMaxDays;
settings["Notify"] = mNotifyNewEvent;
settings["PageSize"] = (int)mPageSize;
llofstream stream(filename.c_str());
LLSDSerialize::toPrettyXML(settings, stream);
}
void LLExperienceLog::loadEvents()
{
LLSD settings = LLSD::emptyMap();
std::string filename = getFilename();
llifstream stream(filename.c_str());
LLSDSerialize::fromXMLDocument(settings, stream);
if(settings.has("MaxDays"))
{
setMaxDays((U32)settings["MaxDays"].asInteger());
}
if(settings.has("Notify"))
{
setNotifyNewEvent(settings["Notify"].asBoolean());
}
if(settings.has("PageSize"))
{
setPageSize((U32)settings["PageSize"].asInteger());
}
mEvents.clear();
if(mMaxDays > 0 && settings.has("Events"))
{
mEvents = settings["Events"];
}
eraseExpired();
}
LLExperienceLog::~LLExperienceLog()
{
saveEvents();
}
void LLExperienceLog::eraseExpired()
{
std::vector<std::string> expired;
std::for_each(mEvents.beginMap(), mEvents.endMap(),
[&](const auto& event_pair)
{
const std::string& date = event_pair.first;
if (isExpired(date))
{
expired.push_back(date);
}
});
for (const auto& date : expired)
{
mEvents.erase(date);
}
}
bool LLExperienceLog::isExpired(const std::string& date)
{
S32 month, day, year = 0;
S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day);
if (matched != 3) return false;
LLDate event_date;
event_date.fromYMDHMS(year, month, day);
return event_date.secondsSinceEpoch() <= (LLDate::now().secondsSinceEpoch() - F64(getMaxDays() * 86400U));
}
const LLSD& LLExperienceLog::getEvents() const
{
return mEvents;
}
void LLExperienceLog::clear()
{
mEvents.clear();
}
void LLExperienceLog::setMaxDays( U32 val )
{
mMaxDays = val;
}
LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb )
{
return mSignals.connect(cb);
}
void LLExperienceLog::setNotifyNewEvent( bool val )
{
mNotifyNewEvent = val;
if(!val && mNotifyConnection.connected())
{
mNotifyConnection.disconnect();
}
else if( val && !mNotifyConnection.connected())
{
mNotifyConnection = addUpdateSignal(std::function<void(LLSD&)>(LLExperienceLog::notify));
}
}

View File

@@ -0,0 +1,86 @@
/**
* @file llexperiencelog.h
* @brief llexperiencelog and related class definitions
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#ifndef LL_LLEXPERIENCELOG_H
#define LL_LLEXPERIENCELOG_H
#include "llsingleton.h"
class LLExperienceLog final : public LLSingleton<LLExperienceLog>
{
friend class LLSingleton<LLExperienceLog>;
LLExperienceLog();
public:
typedef boost::signals2::signal<void(LLSD&)>
callback_signal_t;
typedef callback_signal_t::slot_type callback_slot_t;
typedef boost::signals2::connection callback_connection_t;
callback_connection_t addUpdateSignal(const callback_slot_t& cb);
void initialize();
U32 getMaxDays() const { return mMaxDays; }
void setMaxDays(U32 val);
bool getNotifyNewEvent() const { return mNotifyNewEvent; }
void setNotifyNewEvent(bool val);
U32 getPageSize() const { return mPageSize; }
void setPageSize(U32 val) { mPageSize = val; }
const LLSD& getEvents()const;
void clear();
virtual ~LLExperienceLog();
static void notify(LLSD& message);
static std::string getFilename();
static std::string getPermissionString(const LLSD& message, const std::string& base);
bool isExpired(const std::string& date);
protected:
void handleExperienceMessage(LLSD& message);
void loadEvents();
void saveEvents();
void eraseExpired();
LLSD mEvents;
callback_signal_t mSignals;
callback_connection_t mNotifyConnection;
U32 mMaxDays;
U32 mPageSize;
bool mNotifyNewEvent;
friend class LLExperienceLogDispatchHandler;
};
#endif // LL_LLEXPERIENCELOG_H

View File

@@ -3,38 +3,31 @@
* @author James Cook, Ian Wilkes
* @brief Implementation of the auction floater.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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 "llfloaterauction.h"
#include "lldir.h"
#include "llgl.h"
#include "llimagej2c.h"
#include "llimagetga.h"
@@ -46,17 +39,21 @@
#include "llagent.h"
#include "llcombobox.h"
#include "llmimetypes.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llnotificationsutil.h"
#include "llviewertexturelist.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
#include "llviewerdisplay.h"
#include "llviewercontrol.h"
#include "llui.h"
#include "lluictrlfactory.h"
#include "llrender.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lltrans.h"
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
@@ -74,8 +71,8 @@ void auction_tga_upload_done(const LLUUID& asset_id,
LLFloaterAuction* LLFloaterAuction::sInstance = NULL;
// Default constructor
LLFloaterAuction::LLFloaterAuction() :
LLFloater(std::string("floater_auction")),
LLFloaterAuction::LLFloaterAuction()
: LLFloater(std::string("floater_auction")),
mParcelID(-1)
{
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_auction.xml");
@@ -86,13 +83,13 @@ LLFloaterAuction::LLFloaterAuction() :
onCommitControlSetting(gSavedSettings), (void*)"AuctionShowFence");
childSetAction("snapshot_btn", onClickSnapshot, this);
childSetAction("ok_btn", onClickOK, this);
childSetAction("ok_btn", onClickStartAuction, this);
}
// Destroys the object
LLFloaterAuction::~LLFloaterAuction()
{
sInstance = NULL;
sInstance = nullptr;
}
// static
@@ -104,12 +101,23 @@ void LLFloaterAuction::show()
sInstance->center();
sInstance->setFocus(TRUE);
}
sInstance->initialize();
sInstance->open(); /*Flawfinder: ignore*/
}
BOOL LLFloaterAuction::postBuild()
{
return TRUE;
}
void LLFloaterAuction::onOpen()
{
initialize();
}
void LLFloaterAuction::initialize()
{
mParcelUpdateCapUrl.clear();
mParcelp = LLViewerParcelMgr::getInstance()->getParcelSelection();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
LLParcel* parcelp = mParcelp->getParcel();
@@ -117,28 +125,30 @@ void LLFloaterAuction::initialize()
{
mParcelHost = region->getHost();
mParcelID = parcelp->getLocalID();
mParcelUpdateCapUrl = region->getCapability("ParcelPropertiesUpdate");
childSetText("parcel_text", parcelp->getName());
childEnable("snapshot_btn");
childEnable("ok_btn");
getChild<LLUICtrl>("parcel_text")->setValue(parcelp->getName());
getChildView("snapshot_btn")->setEnabled(TRUE);
getChildView("ok_btn")->setEnabled(true);
}
else
{
mParcelHost.invalidate();
if(parcelp && parcelp->getForSale())
{
childSetText("parcel_text", getString("already for sale"));
getChild<LLUICtrl>("parcel_text")->setValue(getString("already for sale"));
}
else
{
childSetText("parcel_text", LLStringUtil::null);
getChild<LLUICtrl>("parcel_text")->setValue(LLStringUtil::null);
}
mParcelID = -1;
childSetEnabled("snapshot_btn", false);
childSetEnabled("ok_btn", false);
getChildView("snapshot_btn")->setEnabled(false);
getChildView("ok_btn")->setEnabled(false);
}
mImageID.setNull();
mImage = NULL;
mImage = nullptr;
}
void LLFloaterAuction::draw()
@@ -147,9 +157,10 @@ void LLFloaterAuction::draw()
if(!isMinimized() && mImage.notNull())
{
LLRect rect;
if (childGetRect("snapshot_icon", rect))
LLView* snapshot_icon = findChild<LLView>("snapshot_icon");
if (snapshot_icon)
{
LLRect rect = snapshot_icon->getRect();
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f));
@@ -176,7 +187,7 @@ void LLFloaterAuction::onClickSnapshot(void* data)
LLPointer<LLImageRaw> raw = new LLImageRaw;
gForceRenderLandFence = self->childGetValue("fence_check").asBoolean();
gForceRenderLandFence = self->getChild<LLUICtrl>("fence_check")->getValue().asBoolean();
BOOL success = gViewerWindow->rawSnapshot(raw,
gViewerWindow->getWindowWidth(),
gViewerWindow->getWindowHeight(),
@@ -218,13 +229,13 @@ void LLFloaterAuction::onClickSnapshot(void* data)
}
// static
void LLFloaterAuction::onClickOK(void* data)
void LLFloaterAuction::onClickStartAuction(void* data)
{
LLFloaterAuction* self = (LLFloaterAuction*)(data);
if(self->mImageID.notNull())
{
LLSD parcel_name = self->childGetValue("parcel_text");
LLSD parcel_name = self->getChild<LLUICtrl>("parcel_text")->getValue();
// create the asset
std::string* name = new std::string(parcel_name.asString());
@@ -257,11 +268,243 @@ void LLFloaterAuction::onClickOK(void* data)
msg->sendReliable(self->mParcelHost);
// clean up floater, and get out
self->mImageID.setNull();
self->mImage = NULL;
self->mParcelID = -1;
self->mParcelHost.invalidate();
self->close();
self->cleanupAndClose();
}
void LLFloaterAuction::cleanupAndClose()
{
mImageID.setNull();
mImage = nullptr;
mParcelID = -1;
mParcelHost.invalidate();
close();
}
// static glue
void LLFloaterAuction::onClickResetParcel(void* data)
{
LLFloaterAuction* self = (LLFloaterAuction*)(data);
if (self)
{
self->doResetParcel();
}
}
// Reset all the values for the parcel in preparation for a sale
void LLFloaterAuction::doResetParcel()
{
LLParcel* parcelp = mParcelp->getParcel();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if (parcelp
&& region
&& !mParcelUpdateCapUrl.empty())
{
LLSD body;
std::string empty;
// request new properties update from simulator
U32 message_flags = 0x01;
body["flags"] = ll_sd_from_U32(message_flags);
// Set all the default parcel properties for auction
body["local_id"] = parcelp->getLocalID();
U32 parcel_flags = PF_ALLOW_LANDMARK |
PF_ALLOW_FLY |
PF_CREATE_GROUP_OBJECTS |
PF_ALLOW_ALL_OBJECT_ENTRY |
PF_ALLOW_GROUP_OBJECT_ENTRY |
PF_ALLOW_GROUP_SCRIPTS |
PF_RESTRICT_PUSHOBJECT |
PF_SOUND_LOCAL |
PF_ALLOW_VOICE_CHAT |
PF_USE_ESTATE_VOICE_CHAN;
body["parcel_flags"] = ll_sd_from_U32(parcel_flags);
// Build a parcel name like "Ahern (128,128) PG 4032m"
std::ostringstream parcel_name;
LLVector3 center_point( parcelp->getCenterpoint() );
center_point.snap(0); // Get rid of fractions
parcel_name << region->getName()
<< " ("
<< (S32) center_point.mV[VX]
<< ","
<< (S32) center_point.mV[VY]
<< ") "
<< region->getSimAccessString()
<< " "
<< parcelp->getArea()
<< "m";
std::string new_name(parcel_name.str());
body["name"] = new_name;
getChild<LLUICtrl>("parcel_text")->setValue(new_name); // Set name in dialog as well, since it won't get updated otherwise
body["sale_price"] = (S32) 0;
body["description"] = empty;
body["music_url"] = empty;
body["media_url"] = empty;
body["media_desc"] = empty;
body["media_type"] = LLMIMETypes::getDefaultMimeType();
body["media_width"] = (S32) 0;
body["media_height"] = (S32) 0;
body["auto_scale"] = (S32) 0;
body["media_loop"] = (S32) 0;
body["obscure_media"] = (S32) 0; // OBSOLETE - no longer used
body["obscure_music"] = (S32) 0; // OBSOLETE - no longer used
body["media_id"] = LLUUID::null;
body["group_id"] = MAINTENANCE_GROUP_ID; // Use maintenance group
body["pass_price"] = (S32) 10; // Defaults to $10
body["pass_hours"] = 0.0f;
body["category"] = (U8) LLParcel::C_NONE;
body["auth_buyer_id"] = LLUUID::null;
body["snapshot_id"] = LLUUID::null;
body["user_location"] = ll_sd_from_vector3( LLVector3::zero );
body["user_look_at"] = ll_sd_from_vector3( LLVector3::zero );
body["landing_type"] = (U8) LLParcel::L_DIRECT;
LL_INFOS() << "Sending parcel update to reset for auction via capability to: "
<< mParcelUpdateCapUrl << LL_ENDL;
LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore());
// Send a message to clear the object return time
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ParcelSetOtherCleanTime);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_ParcelData);
msg->addS32Fast(_PREHASH_LocalID, parcelp->getLocalID());
msg->addS32Fast(_PREHASH_OtherCleanTime, 5); // 5 minute object auto-return
msg->sendReliable(region->getHost());
// Clear the access lists
clearParcelAccessList(parcelp, region, AL_ACCESS);
clearParcelAccessList(parcelp, region, AL_BAN);
clearParcelAccessList(parcelp, region, AL_ALLOW_EXPERIENCE);
clearParcelAccessList(parcelp, region, AL_BLOCK_EXPERIENCE);
}
}
void LLFloaterAuction::clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list)
{
if (!region || !parcel) return;
LLUUID transactionUUID;
transactionUUID.generate();
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ParcelAccessListUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast(_PREHASH_Data);
msg->addU32Fast(_PREHASH_Flags, list);
msg->addS32(_PREHASH_LocalID, parcel->getLocalID() );
msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID);
msg->addS32Fast(_PREHASH_SequenceID, 1); // sequence_id
msg->addS32Fast(_PREHASH_Sections, 0); // num_sections
// pack an empty block since there will be no data
msg->nextBlockFast(_PREHASH_List);
msg->addUUIDFast(_PREHASH_ID, LLUUID::null );
msg->addS32Fast(_PREHASH_Time, 0 );
msg->addU32Fast(_PREHASH_Flags, 0 );
msg->sendReliable( region->getHost() );
}
// static - 'Sell to Anyone' clicked, throw up a confirmation dialog
void LLFloaterAuction::onClickSellToAnyone(void* data)
{
LLFloaterAuction* self = (LLFloaterAuction*)(data);
if (self)
{
LLParcel* parcelp = self->mParcelp->getParcel();
// Do a confirmation
S32 sale_price = parcelp->getArea(); // Selling for L$1 per meter
S32 area = parcelp->getArea();
LLSD args;
args["LAND_SIZE"] = llformat("%d", area);
args["SALE_PRICE"] = llformat("%d", sale_price);
args["NAME"] = LLTrans::getString("Anyone");
LLNotification::Params params("ConfirmLandSaleChange"); // Re-use existing dialog
params.substitutions(args)
.functor/*.function*/(boost::bind(&LLFloaterAuction::onSellToAnyoneConfirmed, self, _1, _2));
params.name("ConfirmLandSaleToAnyoneChange");
// ask away
LLNotifications::instance().add(params);
}
}
// Sell confirmation clicked
bool LLFloaterAuction::onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
doSellToAnyone();
}
return false;
}
// Reset all the values for the parcel in preparation for a sale
void LLFloaterAuction::doSellToAnyone()
{
LLParcel* parcelp = mParcelp->getParcel();
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
if (parcelp
&& region
&& !mParcelUpdateCapUrl.empty())
{
LLSD body;
// request new properties update from simulator
U32 message_flags = 0x01;
body["flags"] = ll_sd_from_U32(message_flags);
// Set all the default parcel properties for auction
body["local_id"] = parcelp->getLocalID();
// Set 'for sale' flag
U32 parcel_flags = parcelp->getParcelFlags() | PF_FOR_SALE;
// Ensure objects not included
parcel_flags &= ~PF_FOR_SALE_OBJECTS;
body["parcel_flags"] = ll_sd_from_U32(parcel_flags);
body["sale_price"] = parcelp->getArea(); // Sell for L$1 per square meter
body["auth_buyer_id"] = LLUUID::null; // To anyone
LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: "
<< mParcelUpdateCapUrl << LL_ENDL;
LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore());
// clean up floater, and get out
cleanupAndClose();
}
}

View File

@@ -3,31 +3,25 @@
* @author James Cook, Ian Wilkes
* @brief llfloaterauction class header file
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, 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.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -36,7 +30,7 @@
#include "llfloater.h"
#include "lluuid.h"
#include "llmemory.h"
#include "llsafehandle.h"
#include "llviewertexture.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -45,34 +39,50 @@
// Class which holds the functionality to start auctions.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLParcelSelection;
class LLParcel;
class LLViewerRegion;
class LLFloaterAuction : public LLFloater
class LLFloaterAuction final : public LLFloater
{
public:
// LLFloater interface
/*virtual*/ void onClose(bool app_quitting) { setVisible(FALSE); }
/*virtual*/ void draw();
/*virtual*/ void onOpen() override;
/*virtual*/ void onClose(bool app_quitting) override { setVisible(FALSE); }
/*virtual*/ void draw() override;
// LLFloaterAuction interface
static void show();
private:
LLFloaterAuction();
~LLFloaterAuction();
void initialize();
static void onClickSnapshot(void* data);
static void onClickOK(void* data);
static void onClickResetParcel(void* data);
static void onClickSellToAnyone(void* data); // Sell to anyone clicked
bool onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response); // Sell confirmation clicked
static void onClickStartAuction(void* data);
static LLFloaterAuction* sInstance;
/*virtual*/ BOOL postBuild() override;
void doResetParcel();
void doSellToAnyone();
void clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list);
void cleanupAndClose();
private:
LLTransactionID mTransactionID;
LLAssetID mImageID;
LLPointer<LLViewerTexture> mImage;
LLSafeHandle<LLParcelSelection> mParcelp;
S32 mParcelID;
LLHost mParcelHost;
std::string mParcelUpdateCapUrl; // "ParcelPropertiesUpdate" capability
};

View File

@@ -0,0 +1,167 @@
/**
* @file llfloaterexperiencepicker.cpp
* @brief Implementation of llfloaterexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llfloaterexperiencepicker.h"
#include "lllineeditor.h"
//#include "llfloaterreg.h"
#include "lluictrlfactory.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "llexperiencecache.h"
#include "llslurl.h"
#include "llavatarnamecache.h"
#include "llfloaterexperienceprofile.h"
#include "llcombobox.h"
#include "llviewercontrol.h"
#include "lldraghandle.h"
#include "llpanelexperiencepicker.h"
// <singu>
LLFloaterExperiencePicker* show_xp_picker(const LLSD& key)
{
LLFloaterExperiencePicker* floater =
LLFloaterExperiencePicker::getInstance(key);
if (!floater)
{
floater = new LLFloaterExperiencePicker(key);
}
floater->open();
return floater;
}
// </singu>
LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin )
{
LLFloaterExperiencePicker* floater = show_xp_picker(key);
if (floater->mSearchPanel)
{
floater->mSearchPanel->mSelectionCallback = callback;
floater->mSearchPanel->mCloseOnSelect = close_on_select;
floater->mSearchPanel->setAllowMultiple(allow_multiple);
floater->mSearchPanel->setDefaultFilters();
floater->mSearchPanel->addFilters(filters.begin(), filters.end());
floater->mSearchPanel->filterContent();
}
if(frustumOrigin)
{
floater->mFrustumOrigin = frustumOrigin->getHandle();
}
return floater;
}
void LLFloaterExperiencePicker::drawFrustum()
{
if(mFrustumOrigin.get())
{
LLView * frustumOrigin = mFrustumOrigin.get();
LLRect origin_rect;
frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this);
// draw context cone connecting color picker with color swatch in parent floater
LLRect local_rect = getLocalRect();
if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f)
{
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
LLGLEnable<GL_CULL_FACE> cull_face;
gGL.begin(LLRender::TRIANGLE_STRIP);
{
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mRight, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mRight, origin_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mRight, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom);
gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity);
gGL.vertex2i(local_rect.mLeft, local_rect.mTop);
gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity);
gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop);
}
gGL.end();
}
if (gFocusMgr.childHasMouseCapture(getDragHandle()))
{
mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime));
}
else
{
mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime));
}
}
}
void LLFloaterExperiencePicker::draw()
{
drawFrustum();
LLFloater::draw();
}
LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
:LLFloater()
,LLInstanceTracker<LLFloaterExperiencePicker, LLUUID>(key.asUUID())
,mSearchPanel(nullptr)
,mContextConeOpacity(0.f)
,mContextConeInAlpha(0.f)
,mContextConeOutAlpha(0.f)
,mContextConeFadeTime(0.f)
{
mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experience_search.xml", NULL, false);
//buildFromFile("floater_experience_search.xml");
}
LLFloaterExperiencePicker::~LLFloaterExperiencePicker()
{
gFocusMgr.releaseFocusIfNeeded( this );
}
BOOL LLFloaterExperiencePicker::postBuild()
{
mSearchPanel = new LLPanelExperiencePicker();
addChild(mSearchPanel);
mSearchPanel->setOrigin(0, 0);
return LLFloater::postBuild();
}

View File

@@ -0,0 +1,69 @@
/**
* @file llfloaterexperiencepicker.h
* @brief Header file for llfloaterexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#ifndef LL_LLFLOATEREXPERIENCEPICKER_H
#define LL_LLFLOATEREXPERIENCEPICKER_H
#include "llfloater.h"
#include "llinstancetracker.h"
class LLScrollListCtrl;
class LLLineEditor;
class LLPanelExperiencePicker;
class LLFloaterExperiencePicker : public LLFloater
, public LLInstanceTracker<LLFloaterExperiencePicker, LLUUID>
{
public:
typedef std::function<void (const uuid_vec_t&)> select_callback_t;
// filter function for experiences, return true if the experience should be hidden.
typedef std::function<bool (const LLSD&)> filter_function;
typedef std::vector<filter_function> filter_list;
static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin);
LLFloaterExperiencePicker(const LLSD& key);
virtual ~LLFloaterExperiencePicker();
BOOL postBuild() override;
void draw() override;
private:
LLPanelExperiencePicker* mSearchPanel;
void drawFrustum();
LLHandle <LLView> mFrustumOrigin;
F32 mContextConeOpacity;
F32 mContextConeInAlpha;
F32 mContextConeOutAlpha;
F32 mContextConeFadeTime;
};
#endif // LL_LLFLOATEREXPERIENCEPICKER_H

View File

@@ -0,0 +1,939 @@
/**
* @file llfloaterexperienceprofile.cpp
* @brief llfloaterexperienceprofile and related class definitions
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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 "llfloaterexperienceprofile.h"
#include "llagent.h"
#include "llappviewer.h"
#include "llavatarnamecache.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llcommandhandler.h"
//#include "llexpandabletextbox.h"
#include "llexperiencecache.h"
//#include "llfloaterreg.h"
#include "llgroupactions.h"
#include "lluictrlfactory.h"
#include "lllayoutstack.h"
#include "lllineeditor.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llslurl.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltexteditor.h"
#include "lltexturectrl.h"
#include "lltrans.h"
#include "llviewerregion.h"
#include "llevents.h"
#include "llfloatergroups.h"
#include "llnotifications.h"
#include "llfloaterreporter.h"
#include "llurlaction.h"
#define XML_PANEL_EXPERIENCE_PROFILE "floater_experienceprofile.xml"
#define TF_NAME "experience_title"
#define TF_DESC "experience_description"
#define TF_SLURL "LocationTextText"
#define TF_MRKT "marketplace"
#define TF_MATURITY "ContentRatingText"
#define TF_OWNER "OwnerText"
#define TF_GROUP "GroupText"
#define TF_GRID_WIDE "grid_wide"
#define TF_PRIVILEGED "privileged"
#define EDIT "edit_"
#define IMG_LOGO "logo"
#define PNL_TOP "top panel"
#define PNL_IMAGE "image_panel"
#define PNL_DESC "description panel"
#define PNL_LOC "location panel"
#define PNL_MRKT "marketplace panel"
#define PNL_GROUP "group_panel"
#define PNL_PERMS "perm panel"
#define BTN_ALLOW "allow_btn"
#define BTN_BLOCK "block_btn"
#define BTN_CANCEL "cancel_btn"
#define BTN_CLEAR_LOCATION "clear_btn"
#define BTN_EDIT "edit_btn"
#define BTN_ENABLE "enable_btn"
#define BTN_FORGET "forget_btn"
#define BTN_PRIVATE "private_btn"
#define BTN_REPORT "report_btn"
#define BTN_SAVE "save_btn"
#define BTN_SET_GROUP "Group_btn"
#define BTN_SET_LOCATION "location_btn"
class LLExperienceHandler : public LLCommandHandler
{
public:
LLExperienceHandler() : LLCommandHandler("experience", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web) override
{
if (params.size() != 2 || params[1].asString() != "profile")
return false;
LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1));
return true;
}
void experienceCallback(const LLSD& experienceDetails)
{
if (!experienceDetails.has(LLExperienceCache::MISSING))
{
LLFloaterExperienceProfile::showInstance(experienceDetails[LLExperienceCache::EXPERIENCE_ID].asUUID());
}
}
};
LLExperienceHandler gExperienceHandler;
void LLFloaterExperienceProfile::showInstance(const LLSD& data)
{
bool is_map = data.has("experience_id");
LLFloaterExperienceProfile* floater = getInstance(is_map ? data["experience_id"].asUUID() : data.asUUID());
if (!floater) floater = new LLFloaterExperienceProfile(data);
else if (is_map && data.has("edit_experience") && data["edit_experience"].asBoolean())
floater->changeToEdit();
floater->open();
}
LLFloaterExperienceProfile::LLFloaterExperienceProfile(const LLSD& data)
: LLFloater(), LLInstanceTracker<LLFloaterExperienceProfile, LLUUID>(data.asUUID())
, mSaveCompleteAction(NOTHING)
, mDirty(false)
, mForceClose(false)
{
if (data.has("experience_id"))
{
mExperienceId = data["experience_id"].asUUID();
mPostEdit = data.has("edit_experience") && data["edit_experience"].asBoolean();
}
else
{
mExperienceId = data.asUUID();
mPostEdit = false;
}
LLUICtrlFactory::getInstance()->buildFloater(this, XML_PANEL_EXPERIENCE_PROFILE, NULL, false);
//buildFromFile(XML_PANEL_EXPERIENCE_PROFILE);
}
LLFloaterExperienceProfile::~LLFloaterExperienceProfile()
{
}
BOOL LLFloaterExperienceProfile::postBuild()
{
if (mExperienceId.notNull())
{
LLExperienceCache::instance().fetch(mExperienceId, true);
LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback,
getDerivedHandle<LLFloaterExperienceProfile>(), _1));
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind(
&LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
}
childSetAction(BTN_EDIT, boost::bind(&LLFloaterExperienceProfile::onClickEdit, this));
childSetAction(BTN_ALLOW, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Allow"));
childSetAction(BTN_FORGET, boost::bind(&LLFloaterExperienceProfile::onClickForget, this));
childSetAction(BTN_BLOCK, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Block"));
childSetAction(BTN_CANCEL, boost::bind(&LLFloaterExperienceProfile::onClickCancel, this));
childSetAction(BTN_SAVE, boost::bind(&LLFloaterExperienceProfile::onClickSave, this));
childSetAction(BTN_SET_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickLocation, this));
childSetAction(BTN_CLEAR_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickClear, this));
childSetAction(BTN_SET_GROUP, boost::bind(&LLFloaterExperienceProfile::onPickGroup, this));
childSetAction(BTN_REPORT, boost::bind(&LLFloaterExperienceProfile::onReportExperience, this));
getChild<LLTextEditor>(EDIT TF_DESC)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this));
getChild<LLUICtrl>(EDIT TF_MATURITY)->setCommitCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this));
getChild<LLLineEditor>(EDIT TF_MRKT)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this));
getChild<LLLineEditor>(EDIT TF_NAME)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this));
childSetCommitCallback(EDIT BTN_ENABLE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr);
childSetCommitCallback(EDIT BTN_PRIVATE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr);
childSetCommitCallback(EDIT IMG_LOGO, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr);
if (auto logo = findChild<LLTextureCtrl>(IMG_LOGO))
{
void show_picture(const LLUUID& id, const std::string& name);
LLTextBox* name = getChild<LLTextBox>(TF_NAME);
std::function<void()> cb = [logo, name]() { show_picture(logo->getImageAssetID(), "Experience Picture: " + name->getText()); };
logo->setMouseUpCallback(boost::bind(cb));
}
getChild<LLTextEditor>(EDIT TF_DESC)->setCommitOnFocusLost(TRUE);
LLEventPumps::instance().obtain("experience_permission").listen(mExperienceId.asString()+"-profile",
boost::bind(&LLFloaterExperienceProfile::experiencePermission, getDerivedHandle<LLFloaterExperienceProfile>(this), _1));
if (mPostEdit && mExperienceId.notNull())
{
mPostEdit = false;
changeToEdit();
}
return TRUE;
}
void LLFloaterExperienceProfile::experienceCallback(LLHandle<LLFloaterExperienceProfile> handle, const LLSD& experience )
{
LLFloaterExperienceProfile* pllpep = handle.get();
if (pllpep)
{
pllpep->refreshExperience(experience);
}
}
bool LLFloaterExperienceProfile::experiencePermission( LLHandle<LLFloaterExperienceProfile> handle, const LLSD& permission )
{
LLFloaterExperienceProfile* pllpep = handle.get();
if (pllpep)
{
pllpep->updatePermission(permission);
}
return false;
}
void LLFloaterExperienceProfile::onClickEdit()
{
changeToEdit();
}
void LLFloaterExperienceProfile::onClickCancel()
{
changeToView();
}
void LLFloaterExperienceProfile::onClickSave()
{
doSave(NOTHING);
}
void LLFloaterExperienceProfile::onClickPermission(const char* perm)
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind(
&LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
void LLFloaterExperienceProfile::onClickForget()
{
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind(
&LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo )
{
//LLStyle::Params style; // Singu Note: Nope.
std::string access;
if (maturity <= SIM_ACCESS_PG)
{
//style.image(LLUI::getUIImage(getString("maturity_icon_general"))); // Singu Note: Nope.
access = LLTrans::getString("SIM_ACCESS_PG");
combo->setCurrentByIndex(2);
}
else if (maturity <= SIM_ACCESS_MATURE)
{
//style.image(LLUI::getUIImage(getString("maturity_icon_moderate"))); // Singu Note: Nope.
access = LLTrans::getString("SIM_ACCESS_MATURE");
combo->setCurrentByIndex(1);
}
else if (maturity <= SIM_ACCESS_ADULT)
{
//style.image(LLUI::getUIImage(getString("maturity_icon_adult"))); // Singu Note: Nope.
access = LLTrans::getString("SIM_ACCESS_ADULT");
combo->setCurrentByIndex(0);
}
else
{
return false;
}
/* Singu Note: Nope.
child->setText(LLStringUtil::null);
child->appendImageSegment(style);
*/
child->setText(access);
return true;
}
void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience )
{
mExperienceDetails = experience;
mPackage = experience;
LLLayoutPanel* imagePanel = getChild<LLLayoutPanel>(PNL_IMAGE);
LLLayoutPanel* descriptionPanel = getChild<LLLayoutPanel>(PNL_DESC);
LLLayoutPanel* locationPanel = getChild<LLLayoutPanel>(PNL_LOC);
LLLayoutPanel* marketplacePanel = getChild<LLLayoutPanel>(PNL_MRKT);
LLLayoutPanel* topPanel = getChild<LLLayoutPanel>(PNL_TOP);
imagePanel->setVisible(FALSE);
descriptionPanel->setVisible(FALSE);
locationPanel->setVisible(FALSE);
marketplacePanel->setVisible(FALSE);
topPanel->setVisible(FALSE);
LLTextBox* child = getChild<LLTextBox>(TF_NAME);
//child->setText(experience[LLExperienceCache::NAME].asString());
child->setValue(experience[LLExperienceCache::EXPERIENCE_ID].asUUID());
LLLineEditor* linechild = getChild<LLLineEditor>(EDIT TF_NAME);
linechild->setText(experience[LLExperienceCache::NAME].asString());
std::string value = experience[LLExperienceCache::DESCRIPTION].asString();
LLTextEditor* exchild = getChild<LLTextEditor>(TF_DESC);
exchild->setText(value);
descriptionPanel->setVisible(value.length()>0);
LLTextEditor* edit_child = getChild<LLTextEditor>(EDIT TF_DESC);
edit_child->setText(value);
mLocationSLURL = experience[LLExperienceCache::SLURL].asString();
edit_child = getChild<LLTextEditor>(TF_SLURL);
bool has_slurl = !mLocationSLURL.empty() && mLocationSLURL != "last";
locationPanel->setVisible(has_slurl);
if (has_slurl) mLocationSLURL = LLSLURL(mLocationSLURL).getSLURLString();
edit_child->setText(mLocationSLURL);
edit_child = getChild<LLTextEditor>(EDIT TF_SLURL);
if (has_slurl)
{
edit_child->setText(mLocationSLURL);
}
else
{
edit_child->setText(getString("empty_slurl"));
}
setMaturityString((U8)(experience[LLExperienceCache::MATURITY].asInteger()), getChild<LLTextBox>(TF_MATURITY), getChild<LLComboBox>(EDIT TF_MATURITY));
LLUUID agent_id = experience[LLExperienceCache::AGENT_ID].asUUID();
getChild<LLTextBox>(TF_OWNER)->setValue(agent_id);
LLUUID id = experience[LLExperienceCache::GROUP_ID].asUUID();
bool id_null = id.isNull();
if (!id_null)
{
getChild<LLTextBox>(TF_GROUP)->setValue(id);
}
getChild<LLLayoutPanel>(PNL_GROUP)->setVisible(!id_null);
setEditGroup(id);
getChild<LLButton>(BTN_SET_GROUP)->setEnabled(agent_id == gAgentID);
LLCheckBoxCtrl* enable = getChild<LLCheckBoxCtrl>(EDIT BTN_ENABLE);
S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger();
enable->set(!(properties & LLExperienceCache::PROPERTY_DISABLED));
enable = getChild<LLCheckBoxCtrl>(EDIT BTN_PRIVATE);
enable->set(properties & LLExperienceCache::PROPERTY_PRIVATE);
topPanel->setVisible(TRUE);
child=getChild<LLTextBox>(TF_GRID_WIDE);
child->setVisible(TRUE);
if(properties & LLExperienceCache::PROPERTY_GRID)
{
child->setText(LLTrans::getString("Grid-Scope"));
}
else
{
child->setText(LLTrans::getString("Land-Scope"));
}
if (getChild<LLButton>(BTN_EDIT)->getVisible())
{
topPanel->setVisible(TRUE);
}
if (properties & LLExperienceCache::PROPERTY_PRIVILEGED)
{
child = getChild<LLTextBox>(TF_PRIVILEGED);
child->setVisible(TRUE);
}
else
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind(
&LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1));
}
}
value=experience[LLExperienceCache::METADATA].asString();
if (value.empty())
return;
LLPointer<LLSDParser> parser = new LLSDXMLParser();
LLSD data;
std::istringstream is(value);
if (LLSDParser::PARSE_FAILURE != parser->parse(is, data, value.size()))
{
value.clear();
if (data.has(TF_MRKT))
{
value=data[TF_MRKT].asString();
edit_child = getChild<LLTextEditor>(TF_MRKT);
edit_child->setText(value);
if(!value.empty())
{
marketplacePanel->setVisible(TRUE);
}
else
{
marketplacePanel->setVisible(FALSE);
}
}
else
{
marketplacePanel->setVisible(FALSE);
}
linechild = getChild<LLLineEditor>(EDIT TF_MRKT);
linechild->setText(value);
if (data.has(IMG_LOGO))
{
LLTextureCtrl* logo = getChild<LLTextureCtrl>(IMG_LOGO);
LLUUID id = data[IMG_LOGO].asUUID();
logo->setImageAssetID(id);
imagePanel->setVisible(TRUE);
logo = getChild<LLTextureCtrl>(EDIT IMG_LOGO);
logo->setImageAssetID(data[IMG_LOGO].asUUID());
imagePanel->setVisible(id.notNull());
}
}
else
{
marketplacePanel->setVisible(FALSE);
imagePanel->setVisible(FALSE);
}
mDirty=false;
mForceClose = false;
getChild<LLButton>(BTN_SAVE)->setEnabled(mDirty);
}
void LLFloaterExperienceProfile::setPreferences( const LLSD& content )
{
S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger();
if (properties & LLExperienceCache::PROPERTY_PRIVILEGED)
{
return;
}
const LLSD& experiences = content["experiences"];
const LLSD& blocked = content["blocked"];
for(LLSD::array_const_iterator it = experiences.beginArray(); it != experiences.endArray() ; ++it)
{
if (it->asUUID()==mExperienceId)
{
experienceAllowed();
return;
}
}
for(LLSD::array_const_iterator it = blocked.beginArray(); it != blocked.endArray() ; ++it)
{
if (it->asUUID()==mExperienceId)
{
experienceBlocked();
return;
}
}
experienceForgotten();
}
void LLFloaterExperienceProfile::onFieldChanged()
{
updatePackage();
if (!getChild<LLButton>(BTN_EDIT)->getVisible())
{
return;
}
LLSD::map_const_iterator st = mExperienceDetails.beginMap();
LLSD::map_const_iterator dt = mPackage.beginMap();
mDirty = false;
while(!mDirty && st != mExperienceDetails.endMap() && dt != mPackage.endMap())
{
mDirty = st->first != dt->first || st->second.asString() != dt->second.asString();
++st;++dt;
}
if (!mDirty && (st != mExperienceDetails.endMap() || dt != mPackage.endMap()))
{
mDirty = true;
}
getChild<LLButton>(BTN_SAVE)->setEnabled(mDirty);
}
BOOL LLFloaterExperienceProfile::canClose()
{
if (mForceClose || !mDirty)
{
return TRUE;
}
else
{
// Bring up view-modal dialog: Save changes? Yes, No, Cancel
LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, CLOSE));
return FALSE;
}
}
bool LLFloaterExperienceProfile::handleSaveChangesDialog( const LLSD& notification, const LLSD& response, PostSaveAction action )
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
switch( option )
{
case 0: // "Yes"
// close after saving
doSave( action );
break;
case 1: // "No"
if (action != NOTHING)
{
mForceClose = TRUE;
if (action==CLOSE)
{
close();
}
else
{
changeToView();
}
}
break;
case 2: // "Cancel"
default:
// If we were quitting, we didn't really mean it.
LLAppViewer::instance()->abortQuit();
break;
}
return false;
}
void LLFloaterExperienceProfile::doSave( int success_action )
{
mSaveCompleteAction=success_action;
LLViewerRegion* region = gAgent.getRegion();
if (!region)
return;
LLExperienceCache::instance().updateExperience(mPackage, boost::bind(
&LLFloaterExperienceProfile::experienceUpdateResult,
getDerivedHandle<LLFloaterExperienceProfile>(), _1));
}
void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content )
{
LLUUID id = getExperienceId();
if (content.has("removed"))
{
const LLSD& removed = content["removed"];
LLSD::map_const_iterator it = removed.beginMap();
for(/**/; it != removed.endMap(); ++it)
{
const std::string& field = it->first;
if (field == LLExperienceCache::EXPERIENCE_ID)
{
//this message should be removed by the experience api
continue;
}
const LLSD& data = it->second;
std::string error_tag = data["error_tag"].asString()+ "ExperienceProfileMessage";
LLSD fields;
if (LLNotificationTemplates::instance().templateExists(error_tag))
{
fields["field"] = field;
fields["extra_info"] = data["extra_info"];
LLNotificationsUtil::add(error_tag, fields);
}
else
{
fields["MESSAGE"] = data["en"];
LLNotificationsUtil::add("GenericAlert", fields);
}
}
}
if (!content.has("experience_keys"))
{
LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with bad content" << LL_ENDL;
return;
}
const LLSD& experiences = content["experience_keys"];
LLSD::array_const_iterator it = experiences.beginArray();
if (it == experiences.endArray())
{
LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with empty content" << LL_ENDL;
return;
}
if (!it->has(LLExperienceCache::EXPERIENCE_ID) || ((*it)[LLExperienceCache::EXPERIENCE_ID].asUUID() != id))
{
LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with unexpected experience id" << LL_ENDL;
return;
}
refreshExperience(*it);
LLExperienceCache::instance().insert(*it);
LLExperienceCache::instance().fetch(id, true);
if (mSaveCompleteAction == VIEW)
{
LLTabContainer* tabs = getChild<LLTabContainer>("tab_container");
tabs->selectTabByName("panel_experience_info");
}
else if (mSaveCompleteAction == CLOSE)
{
close();
}
}
void LLFloaterExperienceProfile::changeToView()
{
if (mForceClose || !mDirty)
{
refreshExperience(mExperienceDetails);
LLTabContainer* tabs = getChild<LLTabContainer>("tab_container");
tabs->selectTabByName("panel_experience_info");
}
else
{
// Bring up view-modal dialog: Save changes? Yes, No, Cancel
LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, VIEW));
}
}
void LLFloaterExperienceProfile::changeToEdit()
{
LLTabContainer* tabs = getChild<LLTabContainer>("tab_container");
tabs->selectTabByName("edit_panel_experience_info");
}
void LLFloaterExperienceProfile::onClickLocation()
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
auto child = getChild<LLTextEditor>(EDIT TF_SLURL);
mLocationSLURL = LLSLURL(region->getName(), gAgent.getPositionGlobal()).getSLURLString();
child->setText(mLocationSLURL);
onFieldChanged();
}
}
void LLFloaterExperienceProfile::onClickClear()
{
auto child = getChild<LLTextEditor>(EDIT TF_SLURL);
mLocationSLURL.clear();
child->setText(getString("empty_slurl"));
onFieldChanged();
}
void LLFloaterExperienceProfile::updatePermission(const LLSD& permission)
{
if (permission.has("experience"))
{
if (permission["experience"].asUUID() != mExperienceId)
{
return;
}
std::string str = permission[mExperienceId.asString()]["permission"].asString();
if (str == "Allow")
{
experienceAllowed();
}
else if (str == "Block")
{
experienceBlocked();
}
else if (str == "Forget")
{
experienceForgotten();
}
}
else
{
setPreferences(permission);
}
}
void LLFloaterExperienceProfile::experienceAllowed()
{
LLButton* button=getChild<LLButton>(BTN_ALLOW);
button->setEnabled(FALSE);
button=getChild<LLButton>(BTN_FORGET);
button->setEnabled(TRUE);
button=getChild<LLButton>(BTN_BLOCK);
button->setEnabled(TRUE);
}
void LLFloaterExperienceProfile::experienceForgotten()
{
LLButton* button=getChild<LLButton>(BTN_ALLOW);
button->setEnabled(TRUE);
button=getChild<LLButton>(BTN_FORGET);
button->setEnabled(FALSE);
button=getChild<LLButton>(BTN_BLOCK);
button->setEnabled(TRUE);
}
void LLFloaterExperienceProfile::experienceBlocked()
{
LLButton* button=getChild<LLButton>(BTN_ALLOW);
button->setEnabled(TRUE);
button=getChild<LLButton>(BTN_FORGET);
button->setEnabled(TRUE);
button=getChild<LLButton>(BTN_BLOCK);
button->setEnabled(FALSE);
}
void LLFloaterExperienceProfile::onClose( bool app_quitting )
{
LLEventPumps::instance().obtain("experience_permission").stopListening(mExperienceId.asString()+"-profile");
LLFloater::onClose(app_quitting);
}
void LLFloaterExperienceProfile::updatePackage()
{
mPackage[LLExperienceCache::NAME] = getChild<LLLineEditor>(EDIT TF_NAME)->getText();
mPackage[LLExperienceCache::DESCRIPTION] = getChild<LLTextEditor>(EDIT TF_DESC)->getText();
if (mLocationSLURL.empty())
{
mPackage[LLExperienceCache::SLURL] = LLStringUtil::null;
}
else
{
mPackage[LLExperienceCache::SLURL] = mLocationSLURL;
}
mPackage[LLExperienceCache::MATURITY] = getChild<LLComboBox>(EDIT TF_MATURITY)->getSelectedValue().asInteger();
LLSD metadata;
metadata[TF_MRKT] = getChild<LLLineEditor>(EDIT TF_MRKT)->getText();
metadata[IMG_LOGO] = getChild<LLTextureCtrl>(EDIT IMG_LOGO)->getImageAssetID();
LLPointer<LLSDXMLFormatter> formatter = new LLSDXMLFormatter();
std::ostringstream os;
if (formatter->format(metadata, os))
{
mPackage[LLExperienceCache::METADATA] = os.str();
}
int properties = mPackage[LLExperienceCache::PROPERTIES].asInteger();
LLCheckBoxCtrl* enable = getChild<LLCheckBoxCtrl>(EDIT BTN_ENABLE);
if (enable->get())
{
properties &= ~LLExperienceCache::PROPERTY_DISABLED;
}
else
{
properties |= LLExperienceCache::PROPERTY_DISABLED;
}
enable = getChild<LLCheckBoxCtrl>(EDIT BTN_PRIVATE);
if (enable->get())
{
properties |= LLExperienceCache::PROPERTY_PRIVATE;
}
else
{
properties &= ~LLExperienceCache::PROPERTY_PRIVATE;
}
mPackage[LLExperienceCache::PROPERTIES] = properties;
}
void LLFloaterExperienceProfile::onPickGroup()
{
LLFloater* parent_floater = gFloaterView->getParentFloater(this);
LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(gAgent.getID());
if (widget)
{
widget->setSelectGroupCallback(boost::bind(&LLFloaterExperienceProfile::setEditGroup, this, _1));
if (parent_floater)
{
LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget);
widget->setOrigin(new_rect.mLeft, new_rect.mBottom);
parent_floater->addDependentFloater(widget);
}
}
}
void LLFloaterExperienceProfile::setEditGroup( LLUUID group_id )
{
LLTextBox* child = getChild<LLTextBox>(EDIT TF_GROUP);
child->setValue(group_id);
mPackage[LLExperienceCache::GROUP_ID] = group_id;
onFieldChanged();
}
void LLFloaterExperienceProfile::onReportExperience()
{
LLFloaterReporter::showFromExperience(mExperienceId);
}
/*static*/
bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test)
{
if (!content.has(name))
return false;
const LLSD& list = content[name];
LLSD::array_const_iterator it = list.beginArray();
while (it != list.endArray())
{
if (it->asUUID() == test)
{
return true;
}
++it;
}
return false;
}
/*static*/
void LLFloaterExperienceProfile::experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result)
{
std::string permission("Forget");
if (hasPermission(result, "experiences", exprienceId))
permission = "Allow";
else if (hasPermission(result, "blocked", exprienceId))
permission = "Block";
LLSD experience;
LLSD message;
experience["permission"] = permission;
message["experience"] = exprienceId;
message[exprienceId.asString()] = experience;
LLEventPumps::instance().obtain("experience_permission").post(message);
}
/*static*/
void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
{
LLFloaterExperienceProfile* parent = handle.get();
if (!parent)
return;
bool enabled = true;
LLViewerRegion* region = gAgent.getRegion();
if (!region)
{
enabled = false;
}
else
{
std::string url = region->getCapability("UpdateExperience");
if (url.empty())
enabled = false;
}
if (enabled && result["status"].asBoolean())
{
parent->getChild<LLLayoutPanel>(PNL_TOP)->setVisible(TRUE);
parent->getChild<LLButton>(BTN_EDIT)->setVisible(TRUE);
}
}
/*static*/
void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result)
{
LLFloaterExperienceProfile* parent = handle.get();
if (parent)
{
parent->onSaveComplete(result);
}
}

View File

@@ -0,0 +1,113 @@
/**
* @file llfloaterexperienceprofile.h
* @brief llfloaterexperienceprofile and related class definitions
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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$
*/
#ifndef LL_LLFLOATEREXPERIENCEPROFILE_H
#define LL_LLFLOATEREXPERIENCEPROFILE_H
#include "llfloater.h"
#include "lluuid.h"
#include "llsd.h"
class LLLayoutPanel;
class LLTextBox;
class LLComboBox;
class LLFloaterExperienceProfile final : public LLFloater
, public LLInstanceTracker<LLFloaterExperienceProfile, LLUUID>
{
LOG_CLASS(LLFloaterExperienceProfile);
public:
enum PostSaveAction
{
NOTHING,
CLOSE,
VIEW,
};
static void experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result);
static void showInstance(const LLSD& data);
LLFloaterExperienceProfile(const LLSD& data);
virtual ~LLFloaterExperienceProfile();
LLUUID getExperienceId() const { return mExperienceId; }
void setPreferences( const LLSD& content );
void refreshExperience(const LLSD& experience);
void onSaveComplete( const LLSD& content );
BOOL canClose() override;
void onClose(bool app_quitting) override;
protected:
void onClickEdit();
void onClickPermission(const char* permission);
void onClickForget();
void onClickCancel();
void onClickSave();
void onClickLocation();
void onClickClear();
void onPickGroup();
void onFieldChanged();
void onReportExperience();
void setEditGroup(LLUUID group_id);
void changeToView();
void changeToEdit();
void experienceForgotten();
void experienceBlocked();
void experienceAllowed();
static void experienceCallback(LLHandle<LLFloaterExperienceProfile> handle, const LLSD& experience);
static bool experiencePermission(LLHandle<LLFloaterExperienceProfile> handle, const LLSD& permission);
BOOL postBuild() override;
bool setMaturityString(U8 maturity, LLTextBox* child, LLComboBox* combo);
bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response, PostSaveAction action);
void doSave( int success_action );
void updatePackage();
void updatePermission( const LLSD& permission );
LLUUID mExperienceId;
LLSD mExperienceDetails;
LLSD mPackage;
std::string mLocationSLURL;
int mSaveCompleteAction;
bool mDirty;
bool mForceClose;
bool mPostEdit; // edit experience after opening and updating it
private:
static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test);
static void experienceIsAdmin(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
static void experienceUpdateResult(LLHandle<LLFloaterExperienceProfile> handle, const LLSD &result);
};
#endif // LL_LLFLOATEREXPERIENCEPROFILE_H

View File

@@ -0,0 +1,377 @@
/**
* @file llfloaterexperiences.cpp
* @brief LLFloaterExperiences class implementation
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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 "llfloaterexperiences.h"
#include "llagent.h"
#include "llcororesponder.h"
#include "llevents.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
#include "llfloaterregioninfo.h"
#include "llnotificationsutil.h"
#include "llpanelexperiencelog.h"
#include "llpanelexperiencepicker.h"
#include "llpanelexperiences.h"
#include "lltabcontainer.h"
#include "lltrans.h"
#include "lluictrlfactory.h"
#include "llviewerregion.h"
#define SHOW_RECENT_TAB (0)
LLFloaterExperiences::LLFloaterExperiences(const LLSD& data)
:LLFloater(data)
{
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experiences.xml", NULL, false);
//buildFromFile("floater_experiences.xml");
}
LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name, bool select)
{
LLPanelExperiences* newPanel = LLPanelExperiences::create(name);
getChild<LLTabContainer>("xp_tabs")->addTabPanel(
newPanel,
LLTrans::getString(name),
select);
return newPanel;
}
BOOL LLFloaterExperiences::postBuild()
{
LLPanel* panel = new LLPanelExperiencePicker();
getChild<LLTabContainer>("xp_tabs")->addTabPanel(panel, panel->getLabel());
addTab("Allowed_Experiences_Tab", true);
addTab("Blocked_Experiences_Tab", false);
addTab("Admin_Experiences_Tab", false);
addTab("Contrib_Experiences_Tab", false);
LLPanelExperiences* owned = addTab("Owned_Experiences_Tab", false);
owned->setButtonAction("acquire", boost::bind(&LLFloaterExperiences::sendPurchaseRequest, this));
owned->enableButton(false);
#if SHOW_RECENT_TAB
addTab("Recent_Experiences_Tab", false);
#endif //SHOW_RECENT_TAB
panel = new LLPanelExperienceLog();
getChild<LLTabContainer>("xp_tabs")->addTabPanel(panel, panel->getLabel());
resizeToTabs();
return TRUE;
}
void LLFloaterExperiences::clearFromRecent(const LLSD& ids)
{
#if SHOW_RECENT_TAB
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab");
if(!tab)
return;
tab->removeExperiences(ids);
#endif // SHOW_RECENT_TAB
}
void LLFloaterExperiences::setupRecentTabs()
{
#if SHOW_RECENT_TAB
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab");
if(!tab)
return;
LLSD recent;
const LLExperienceCache::cache_t& experiences = LLExperienceCache::getCached();
LLExperienceCache::cache_t::const_iterator it = experiences.begin();
while( it != experiences.end() )
{
if(!it->second.has(LLExperienceCache::MISSING))
{
recent.append(it->first);
}
++it;
}
tab->setExperienceList(recent);
#endif // SHOW_RECENT_TAB
}
void LLFloaterExperiences::resizeToTabs()
{
const S32 TAB_WIDTH_PADDING = 16;
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLRect rect = getRect();
if(rect.getWidth() < tabs->getTotalTabWidth() + TAB_WIDTH_PADDING)
{
rect.mRight = rect.mLeft + tabs->getTotalTabWidth() + TAB_WIDTH_PADDING;
}
reshape(rect.getWidth(), rect.getHeight(), FALSE);
}
void LLFloaterExperiences::refreshContents()
{
setupRecentTabs();
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
NameMap_t tabMap;
LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
tabMap["experiences"]="Allowed_Experiences_Tab";
tabMap["blocked"]="Blocked_Experiences_Tab";
tabMap["experience_ids"]="Owned_Experiences_Tab";
retrieveExperienceList(region->getCapability("GetExperiences"), handle, tabMap);
updateInfo("GetAdminExperiences","Admin_Experiences_Tab");
updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
retrieveExperienceList(region->getCapability("AgentExperiences"), handle, tabMap,
"ExperienceAcquireFailed", boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2));
}
}
void LLFloaterExperiences::onOpen()
{
LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences");
LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences",
boost::bind(&LLFloaterExperiences::updatePermissions, this, _1));
LLViewerRegion* region = gAgent.getRegion();
if(region)
{
if(region->capabilitiesReceived())
{
refreshContents();
return;
}
region->setCapabilitiesReceivedCallback(boost::bind(&LLFloaterExperiences::refreshContents, this));
return;
}
}
bool LLFloaterExperiences::updatePermissions( const LLSD& permission )
{
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLUUID experience;
std::string permission_string;
if(permission.has("experience"))
{
experience = permission["experience"].asUUID();
permission_string = permission[experience.asString()]["permission"].asString();
}
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Allowed_Experiences_Tab");
if(tab)
{
if(permission.has("experiences"))
{
tab->setExperienceList(permission["experiences"]);
}
else if(experience.notNull())
{
if(permission_string != "Allow")
{
tab->removeExperience(experience);
}
else
{
tab->addExperience(experience);
}
}
}
tab = (LLPanelExperiences*)tabs->getPanelByName("Blocked_Experiences_Tab");
if(tab)
{
if(permission.has("blocked"))
{
tab->setExperienceList(permission["blocked"]);
}
else if(experience.notNull())
{
if(permission_string != "Block")
{
tab->removeExperience(experience);
}
else
{
tab->addExperience(experience);
}
}
}
return false;
}
void LLFloaterExperiences::onClose( bool app_quitting )
{
LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences");
LLFloater::onClose(app_quitting);
}
void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content) const
{
panel->enableButton(content.has("purchase"));
LLFloaterExperiences::findInstance()->updateInfo("GetAdminExperiences","Admin_Experiences_Tab");
LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab");
}
void LLFloaterExperiences::checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const
{
checkPurchaseInfo(panel, content);
// determine new item
const LLSD& response_ids = content["experience_ids"];
if (mPrepurchaseIds.size() + 1 == response_ids.size())
{
// we have a new element
for (LLSD::array_const_iterator it = response_ids.beginArray(); it != response_ids.endArray(); ++it)
{
LLUUID experience_id = it->asUUID();
if (std::find(mPrepurchaseIds.begin(), mPrepurchaseIds.end(), experience_id) == mPrepurchaseIds.end())
{
// new element found, open it
LLSD args;
args["experience_id"] = experience_id;
args["edit_experience"] = true;
LLFloaterExperienceProfile::showInstance(args);
break;
}
}
}
}
void LLFloaterExperiences::updateInfo(std::string experienceCap, std::string tab)
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
NameMap_t tabMap;
LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
tabMap["experience_ids"] = tab;
retrieveExperienceList(region->getCapability(experienceCap), handle, tabMap);
}
}
void LLFloaterExperiences::sendPurchaseRequest()
{
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
NameMap_t tabMap;
const std::string tab_owned_name = "Owned_Experiences_Tab";
LLHandle<LLFloaterExperiences> handle = getDerivedHandle<LLFloaterExperiences>();
tabMap["experience_ids"] = tab_owned_name;
// extract ids for experiences that we already have
LLTabContainer* tabs = getChild<LLTabContainer>("xp_tabs");
LLPanelExperiences* tab_owned = (LLPanelExperiences*)tabs->getPanelByName(tab_owned_name);
mPrepurchaseIds.clear();
if (tab_owned)
{
tab_owned->getExperienceIdsList(mPrepurchaseIds);
}
requestNewExperience(region->getCapability("AgentExperiences"), handle, tabMap, "ExperienceAcquireFailed",
boost::bind(&LLFloaterExperiences::checkAndOpen, this, _1, _2));
}
}
void LLFloaterExperiences::retrieveExperienceList(const std::string &url,
const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
const std::string &errorNotify, Callback_t cback, bool post)
{
if (url.empty())
{
LL_WARNS() << "retrieveExperienceListCoro called with empty capability!" << LL_ENDL;
return;
}
auto responder = new LLCoroResponder(
boost::bind(LLFloaterExperiences::retrieveExperienceListCoro, _1,
hparent, tabMapping, errorNotify, cback));
if (post)
LLHTTPClient::post(url, LLSD(), responder);
else
LLHTTPClient::get(url, responder);
}
void LLFloaterExperiences::retrieveExperienceListCoro(const LLCoroResponder& responder,
LLHandle<LLFloaterExperiences> hparent, NameMap_t tabMapping,
std::string errorNotify, Callback_t cback)
{
LLSD result = responder.getContent();
if (!responder.isGoodStatus(responder.getStatus()))
{
LLSD subs;
subs["ERROR_MESSAGE"] = responder.getReason();
LLNotificationsUtil::add(errorNotify, subs);
return;
}
if (hparent.isDead())
return;
LLFloaterExperiences* parent = hparent.get();
LLTabContainer* tabs = parent->getChild<LLTabContainer>("xp_tabs");
for (auto& it : tabMapping)
{
if (result.has(it.first))
{
LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it.second);
if (tab)
{
const LLSD& ids = result[it.first];
tab->setExperienceList(ids);
if (cback != nullptr)
{
cback(tab, result);
}
}
}
}
}

View File

@@ -0,0 +1,78 @@
/**
* @file llfloaterexperiences.h
* @brief LLFloaterExperiences class definition
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
#ifndef LL_LLFLOATEREXPERIENCES_H
#define LL_LLFLOATEREXPERIENCES_H
#include "llfloater.h"
class LLPanelExperiences;
class LLFloaterExperiences final :
public LLFloater
, public LLFloaterSingleton<LLFloaterExperiences>
{
friend class LLUISingleton<LLFloaterExperiences, VisibilityPolicy<LLFloater> >;
public:
LLFloaterExperiences(const LLSD& data);
void onClose(bool app_quitting) override;
void onOpen(/*const LLSD& key*/) override;
protected:
typedef std::map<std::string, std::string> NameMap_t;
typedef std::function<void(LLPanelExperiences*, const LLSD&)> Callback_t;
void clearFromRecent(const LLSD& ids);
void resizeToTabs();
/*virtual*/ BOOL postBuild() override;
void refreshContents();
void setupRecentTabs();
LLPanelExperiences* addTab(const std::string& name, bool select);
bool updatePermissions(const LLSD& permission);
void sendPurchaseRequest();
void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const;
void checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const;
void updateInfo(std::string experiences, std::string tab);
void retrieveExperienceList(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
const std::string &errorNotify = std::string("ErrorMessage"), Callback_t cback = Callback_t(), bool post = false);
void requestNewExperience(const std::string &url, const LLHandle<LLFloaterExperiences> &hparent, const NameMap_t &tabMapping,
const std::string &errorNotify, Callback_t cback)
{
retrieveExperienceList(url, hparent, tabMapping, errorNotify, cback, true);
}
private:
static void retrieveExperienceListCoro(const struct LLCoroResponder& responder, LLHandle<LLFloaterExperiences> hparent,
NameMap_t tabMapping, std::string errorNotify, Callback_t cback);
uuid_vec_t mPrepurchaseIds;
};
#endif //LL_LLFLOATEREXPERIENCES_H

File diff suppressed because it is too large Load Diff

View File

@@ -3,43 +3,33 @@
* @author James Cook
* @brief "About Land" floater, allowing display and editing of land parcel properties.
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
*
* Copyright (c) 2002-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLFLOATERLAND_H
#define LL_LLFLOATERLAND_H
#include <set>
#include <vector>
#include "llfloater.h"
#include "llpointer.h" // LLPointer<>
//#include "llviewertexturelist.h"
#include "llsafehandle.h"
const F32 CACHE_REFRESH_TIME = 2.5f;
@@ -49,6 +39,7 @@ class LLCheckBoxCtrl;
class LLRadioGroup;
class LLComboBox;
class LLLineEditor;
class LLMessageSystem;
class LLNameListCtrl;
class LLRadioGroup;
class LLParcelSelectionObserver;
@@ -58,7 +49,6 @@ class LLTextBox;
class LLTextEditor;
class LLTextureCtrl;
class LLUIImage;
class LLViewerTextEditor;
class LLParcelSelection;
class LLPanelLandGeneral;
@@ -71,9 +61,11 @@ class LLPanelLandBan;
class LLPanelLandRenters;
class LLPanelLandCovenant;
class LLParcel;
class LLPanelLandExperiences;
class LLFloaterLand
: public LLFloater, public LLFloaterSingleton<LLFloaterLand>
class LLFloaterLand final
: public LLFloater
, public LLFloaterSingleton<LLFloaterLand>
{
friend class LLUISingleton<LLFloaterLand, VisibilityPolicy<LLFloater> >;
public:
@@ -85,24 +77,23 @@ public:
LLParcel* getCurrentSelectedParcel();
// Destroys itself on close.
virtual void onClose(bool app_quitting);
virtual void onOpen();
virtual BOOL postBuild();
void onClose(bool app_quitting) override;
void onOpen() override;
BOOL postBuild() override;
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
virtual void open();
void open() override;
// [/RLVa:KB]
protected:
private:
// Does its own instance management, so clients not allowed
// to allocate or destroy.
LLFloaterLand(const LLSD& seed);
virtual ~LLFloaterLand();
/*virtual*/ void refresh();
protected:
/*virtual*/ void refresh() override;
static void* createPanelLandGeneral(void* data);
static void* createPanelLandCovenant(void* data);
@@ -111,12 +102,15 @@ protected:
static void* createPanelLandAudio(void* data);
static void* createPanelLandMedia(void* data);
static void* createPanelLandAccess(void* data);
static void* createPanelLandExperiences(void* data);
static void* createPanelLandBan(void* data);
protected:
static LLParcelSelectionObserver* sObserver;
static S32 sLastTab;
friend class LLPanelLandObjects;
LLTabContainer* mTabLand;
LLPanelLandGeneral* mPanelGeneral;
LLPanelLandObjects* mPanelObjects;
@@ -125,6 +119,7 @@ protected:
LLPanelLandMedia* mPanelMedia;
LLPanelLandAccess* mPanelAccess;
LLPanelLandCovenant* mPanelCovenant;
LLPanelLandExperiences* mPanelExperiences;
LLSafeHandle<LLParcelSelection> mParcel;
@@ -137,25 +132,25 @@ public:
};
class LLPanelLandGeneral
class LLPanelLandGeneral final
: public LLPanel
{
public:
LLPanelLandGeneral(LLSafeHandle<LLParcelSelection>& parcelp);
virtual ~LLPanelLandGeneral();
/*virtual*/ void refresh();
/*virtual*/ void refresh() override;
void refreshNames();
void setGroup(const LLUUID& group_id);
void onClickSetGroup();
static void onClickDeed(void*);
static void onClickBuyLand(void* data);
static void onClickScriptLimits(void* data);
static void onClickRelease(void*);
static void onClickReclaim(void*);
static void onClickBuyPass(void* deselect_when_done);
void onClickDeed();
void onClickScriptLimits();
void onClickRelease();
void onClickReclaim();
static BOOL enableBuyPass(void*);
static void onCommitAny(LLUICtrl* ctrl, void *userdata);
void onCommitAny();
static void finalizeCommit(void * userdata);
static void onForSaleChange(LLUICtrl *ctrl, void * userdata);
static void finalizeSetSellChange(void * userdata);
@@ -163,20 +158,20 @@ public:
static bool cbBuyPass(const LLSD& notification, const LLSD& response);
static void onClickSellLand(void* data);
static void onClickStopSellLand(void* data);
static void onClickSet(void* data);
static void onClickClear(void* data);
static void onClickShow(void* data);
void onClickSellLand();
void onClickStopSellLand();
void onClickSet();
void onClickClear();
void onClickShow();
static void callbackAvatarPick(const std::vector<std::string>& names, const uuid_vec_t& ids, void* data);
static void finalizeAvatarPick(void* data);
static void callbackHighlightTransferable(S32 option, void* userdata);
static void onClickStartAuction(void*);
void onClickStartAuction();
// sale change confirmed when "is for sale", "sale price", "sell to whom" fields are changed
static void confirmSaleChange(S32 landSize, S32 salePrice, std::string authorizedName, void(*callback)(void*), void* userdata);
static void callbackConfirmSaleChange(S32 option, void* userdata);
virtual BOOL postBuild();
BOOL postBuild() override;
protected:
LLLineEditor* mEditName;
@@ -235,36 +230,36 @@ protected:
static LLHandle<LLFloater> sBuyPassDialogHandle;
};
class LLPanelLandObjects
class LLPanelLandObjects final
: public LLPanel
{
public:
LLPanelLandObjects(LLSafeHandle<LLParcelSelection>& parcelp);
virtual ~LLPanelLandObjects();
/*virtual*/ void refresh();
/*virtual*/ void refresh() override;
bool callbackReturnOwnerObjects(const LLSD& notification, const LLSD& response);
bool callbackReturnGroupObjects(const LLSD& notification, const LLSD& response);
bool callbackReturnOtherObjects(const LLSD& notification, const LLSD& response);
bool callbackReturnOwnerList(const LLSD& notification, const LLSD& response);
static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = 0);
static void onClickShowOwnerObjects(void*);
static void onClickShowGroupObjects(void*);
static void onClickShowOtherObjects(void*);
static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = nullptr);
void onClickShowOwnerObjects();
void onClickShowGroupObjects();
void onClickShowOtherObjects();
static void onClickReturnOwnerObjects(void*);
static void onClickReturnGroupObjects(void*);
static void onClickReturnOtherObjects(void*);
static void onClickReturnOwnerList(void*);
static void onClickRefresh(void*);
void onClickReturnOwnerObjects();
void onClickReturnGroupObjects();
void onClickReturnOtherObjects();
void onClickReturnOwnerList();
void onClickRefresh();
void onCommitList();
static void onLostFocus(LLFocusableElement* caller, void* user_data);
static void onCommitClean(LLUICtrl* caller, void* user_data);
void onCommitClean();
static void processParcelObjectOwnersReply(LLMessageSystem *msg, void **);
virtual BOOL postBuild();
BOOL postBuild() override;
protected:
@@ -304,23 +299,23 @@ protected:
};
class LLPanelLandOptions
class LLPanelLandOptions final
: public LLPanel
{
public:
LLPanelLandOptions(LLSafeHandle<LLParcelSelection>& parcelp);
virtual ~LLPanelLandOptions();
/*virtual*/ BOOL postBuild();
/*virtual*/ void draw();
/*virtual*/ void refresh();
/*virtual*/ BOOL postBuild() override;
/*virtual*/ void draw() override;
/*virtual*/ void refresh() override;
private:
// Refresh the "show in search" checkbox and category selector.
void refreshSearch();
static void onCommitAny(LLUICtrl* ctrl, void *userdata);
static void onClickSet(void* userdata);
static void onClickClear(void* userdata);
void onCommitAny();
void onClickSet();
void onClickClear();
static void onClickPublishHelp(void*);
private:
@@ -355,24 +350,24 @@ private:
};
class LLPanelLandAccess
class LLPanelLandAccess final
: public LLPanel
{
public:
LLPanelLandAccess(LLSafeHandle<LLParcelSelection>& parcelp);
virtual ~LLPanelLandAccess();
void refresh();
void refresh() override;
void refresh_ui();
void refreshNames();
virtual void draw();
void draw() override;
static void onCommitPublicAccess(LLUICtrl* ctrl, void *userdata);
static void onCommitAny(LLUICtrl* ctrl, void *userdata);
static void onCommitGroupCheck(LLUICtrl* ctrl, void *userdata);
static void onClickRemoveAccess(void*);
static void onClickRemoveBanned(void*);
void onCommitPublicAccess(LLUICtrl* ctrl);
void onCommitAny();
void onCommitGroupCheck(LLUICtrl* ctrl);
void onClickRemoveAccess();
void onClickRemoveBanned();
virtual BOOL postBuild();
BOOL postBuild() override;
void onClickAddAccess();
void onClickAddBanned();
@@ -387,15 +382,14 @@ protected:
LLSafeHandle<LLParcelSelection>& mParcel;
};
class LLPanelLandCovenant
class LLPanelLandCovenant final
: public LLPanel
{
public:
LLPanelLandCovenant(LLSafeHandle<LLParcelSelection>& parcelp);
virtual ~LLPanelLandCovenant();
virtual BOOL postBuild();
void refresh();
BOOL postBuild() override;
void refresh() override;
static void updateCovenantText(const std::string& string);
static void updateEstateName(const std::string& name);
static void updateLastModified(const std::string& text);
@@ -403,6 +397,10 @@ public:
protected:
LLSafeHandle<LLParcelSelection>& mParcel;
private:
LLUUID mLastRegionID;
F64 mNextUpdateTime; //seconds since client start
};
#endif

View File

@@ -94,14 +94,13 @@ BOOL LLPanelMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL
std::string& tooltip_msg)
{
LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
BOOL handled = (handled_view != NULL);
// Special case the drop zone
if (handled && (handled_view->getName() == "marketplace_drop_zone"))
// Special case the drop zone, also we're a giant drop zone
if (!handled_view || (handled_view->getName() == "marketplace_drop_zone"))
{
LLFolderView* root_folder = getRootFolder();
handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
return root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
}
return handled;
return false;
}
void LLPanelMarketplaceListings::buildAllPanels()
@@ -224,7 +223,7 @@ void LLPanelMarketplaceListings::onTabChange()
// Show/hide the drop zone and resize the inventory tabs panel accordingly
LLPanel* drop_zone = (LLPanel*)getChild<LLPanel>("marketplace_drop_zone");
bool drop_zone_visible = drop_zone->getVisible();
bool allow_drop_on_root = panel->getAllowDropOnRoot() && gSavedSettings.getBOOL("LiruEnableWIPUI");
bool allow_drop_on_root = panel->getAllowDropOnRoot();
if (drop_zone_visible != allow_drop_on_root)
{
LLPanel* tabs = (LLPanel*)getChild<LLPanel>("tab_container_panel");

View File

@@ -44,11 +44,10 @@ bool LLCrossParcelFunctor::apply(LLViewerObject* obj)
mBoundingBox.addBBoxAgent(LLBBox(obj->getPositionRegion(), obj->getRotationRegion(), obj->getScale() * -0.5f, obj->getScale() * 0.5f).getAxisAligned());
// Extend the bounding box across all the children.
LLViewerObject::const_child_list_t children = obj->getChildren();
for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin();
iter != children.end(); iter++)
LLViewerObject::const_child_list_t const& children = obj->getChildren();
for (const auto& iter : children)
{
LLViewerObject* child = *iter;
LLViewerObject* child = iter;
mBoundingBox.addBBoxAgent(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned());
}
@@ -67,16 +66,16 @@ bool LLCrossParcelFunctor::apply(LLViewerObject* obj)
LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key)
: LLFloater(key),
mSelectedObjects(NULL),
mSelectedPrims(NULL),
mSelectedDownloadWeight(NULL),
mSelectedPhysicsWeight(NULL),
mSelectedServerWeight(NULL),
mSelectedDisplayWeight(NULL),
mSelectedOnLand(NULL),
mRezzedOnLand(NULL),
mRemainingCapacity(NULL),
mTotalCapacity(NULL)
mSelectedObjects(nullptr),
mSelectedPrims(nullptr),
mSelectedDownloadWeight(nullptr),
mSelectedPhysicsWeight(nullptr),
mSelectedServerWeight(nullptr),
mSelectedDisplayWeight(nullptr),
mSelectedOnLand(nullptr),
mRezzedOnLand(nullptr),
mRemainingCapacity(nullptr),
mTotalCapacity(nullptr)
{
//buildFromFile("floater_tools.xml");
LLUICtrlFactory::getInstance()->buildFloater(this,"floater_object_weights.xml", NULL, false);
@@ -142,7 +141,8 @@ void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reaso
void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel)
{
if (!parcel || LLSelectMgr::getInstance()->getSelection()->isEmpty())
auto selection = LLSelectMgr::instance().getSelection();
if (!parcel || !selection || selection->isEmpty())
{
updateIfNothingSelected();
}
@@ -161,24 +161,24 @@ void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel)
void LLFloaterObjectWeights::refresh()
{
LLSelectMgr* sel_mgr = LLSelectMgr::getInstance();
auto selection = LLSelectMgr::instance().getSelection();
if (sel_mgr->getSelection()->isEmpty())
if (!selection || selection->isEmpty())
{
updateIfNothingSelected();
}
else
{
S32 prim_count = sel_mgr->getSelection()->getObjectCount();
S32 link_count = sel_mgr->getSelection()->getRootObjectCount();
F32 prim_equiv = sel_mgr->getSelection()->getSelectedLinksetCost();
S32 prim_count = selection->getObjectCount();
S32 link_count = selection->getRootObjectCount();
F32 prim_equiv = selection->getSelectedLinksetCost();
mSelectedObjects->setText(llformat("%d", link_count));
mSelectedPrims->setText(llformat("%d", prim_count));
mSelectedOnLand->setText(llformat("%.1d", (S32)prim_equiv));
LLCrossParcelFunctor func;
if (sel_mgr->getSelection()->applyToRootObjects(&func, true))
if (selection->applyToRootObjects(&func, true))
{
// Some of the selected objects cross parcel bounds.
// We don't display object weights and land impacts in this case.
@@ -194,8 +194,8 @@ void LLFloaterObjectWeights::refresh()
LLViewerRegion* region = gAgent.getRegion();
if (region && region->capabilitiesReceived())
{
for (LLObjectSelection::valid_root_iterator iter = sel_mgr->getSelection()->valid_root_begin();
iter != sel_mgr->getSelection()->valid_root_end(); ++iter)
for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin();
iter != selection->valid_root_end(); ++iter)
{
LLAccountingCostManager::getInstance()->addObject((*iter)->getObject()->getID());
}
@@ -212,7 +212,6 @@ void LLFloaterObjectWeights::refresh()
}
else
{
//LL_WARNS() << "Failed to get region capabilities" << LL_ENDL;
LL_WARNS() << "Failed to get region capabilities" << LL_ENDL;
}
}

View File

@@ -44,6 +44,8 @@
#include "llavataractions.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcororesponder.h"
#include "llexperiencecache.h"
#include "llgroupactions.h"
#include "llinventorymodel.h"
#include "llinventoryobserver.h"
@@ -51,8 +53,8 @@
#include "llradiogroup.h"
#include "llresmgr.h"
#include "roles_constants.h"
#include "llnamebox.h"
#include "llselectmgr.h"
#include "lltextbox.h"
#include "lltrans.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
@@ -64,11 +66,6 @@
#include "lfsimfeaturehandler.h"
#include "hippogridmanager.h"
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]
bool can_set_export(const U32& base, const U32& own, const U32& next);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -81,7 +78,7 @@ bool can_set_export(const U32& base, const U32& own, const U32& next);
// from the inventory observer list when destroyed, which could
// happen after gInventory has already been destroyed if a singleton.
// Instead, do our own ref counting and create / destroy it as needed
class LLPropertiesObserver : public LLInventoryObserver
class LLPropertiesObserver final : public LLInventoryObserver
{
public:
LLPropertiesObserver(LLFloaterProperties* floater)
@@ -93,9 +90,10 @@ public:
{
gInventory.removeObserver(this);
}
virtual void changed(U32 mask);
void changed(U32 mask) override;
private:
LLFloaterProperties* mFloater;
LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver
};
void LLPropertiesObserver::changed(U32 mask)
@@ -154,7 +152,7 @@ LLFloaterProperties::LLFloaterProperties(const std::string& name, const LLRect&
LLFloaterProperties::~LLFloaterProperties()
{
delete mPropertiesObserver;
mPropertiesObserver = NULL;
mPropertiesObserver = nullptr;
}
// virtual
@@ -216,7 +214,7 @@ void LLFloaterProperties::refresh()
mDirty = TRUE;
const char* enableNames[]={
static constexpr std::array<const char*, 21> enableNames{{
"LabelItemName",
"LabelItemDesc",
"LabelCreatorName",
@@ -238,21 +236,21 @@ void LLFloaterProperties::refresh()
"CheckPurchase",
"RadioSaleType",
"Edit Cost"
};
for(size_t t=0; t<LL_ARRAY_SIZE(enableNames); ++t)
}};
for(const char* name : enableNames)
{
getChildView(enableNames[t])->setEnabled(false);
getChildView(name)->setEnabled(false);
}
const char* hideNames[]={
static constexpr std::array<const char*,5> hideNames{{
"BaseMaskDebug",
"OwnerMaskDebug",
"GroupMaskDebug",
"EveryoneMaskDebug",
"NextMaskDebug"
};
for(size_t t=0; t<LL_ARRAY_SIZE(hideNames); ++t)
}};
for(const char* name : hideNames)
{
getChildView(hideNames[t])->setVisible(false);
getChildView(name)->setVisible(false);
}
}
}
@@ -290,7 +288,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
// You need permission to modify the object to modify an inventory
// item in it.
LLViewerObject* object = NULL;
LLViewerObject* object = nullptr;
if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID);
BOOL is_obj_modify = TRUE;
if(object)
@@ -298,6 +296,21 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
is_obj_modify = object->permOwnerModify();
}
if (item->getInventoryType() == LLInventoryType::IT_LSL)
{
getChildView("LabelItemExperienceTitle")->setVisible(TRUE);
LLTextBox* tb = getChild<LLTextBox>("LabelItemExperience");
tb->setText(getString("loading_experience"));
tb->setVisible(TRUE);
std::string url = std::string();
if(object && object->getRegion())
{
url = object->getRegion()->getCapability("GetMetadata");
}
LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), url,
boost::bind(&LLFloaterProperties::setAssociatedExperience, getDerivedHandle<LLFloaterProperties>(), _1));
}
//////////////////////
// ITEM NAME & DESC //
//////////////////////
@@ -403,11 +416,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChild<LLUICtrl>("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY)));
getChildView("CheckOwnerTransfer")->setEnabled(FALSE);
getChild<LLUICtrl>("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER)));
getChildView("CheckOwnerExport")->setEnabled(FALSE);
getChild<LLUICtrl>("CheckOwnerExport")->setValue(LLSD((BOOL)(owner_mask & PERM_EXPORT)));
bool supports_export = LFSimFeatureHandler::instance().simSupportsExport();
getChildView("CheckOwnerExport")->setEnabled(false);
getChild<LLUICtrl>("CheckOwnerExport")->setValue(LLSD((BOOL)(supports_export && owner_mask & PERM_EXPORT)));
if (!gHippoGridManager->getCurrentGrid()->isSecondLife())
if (!supports_export)
getChildView("CheckOwnerExport")->setVisible(false);
///////////////////////
@@ -520,6 +533,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
const LLSaleInfo& sale_info = item->getSaleInfo();
BOOL is_for_sale = sale_info.isForSale();
LLRadioGroup* radioSaleType = getChild<LLRadioGroup>("RadioSaleType");
LLUICtrl* edit_cost = getChild<LLUICtrl>("Edit Cost");
// Check for ability to change values.
if (is_obj_modify && can_agent_sell
&& gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE))
@@ -533,9 +549,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChildView("CheckNextOwnerCopy")->setEnabled(no_export && (base_mask & PERM_COPY) && !cannot_restrict_permissions);
getChildView("CheckNextOwnerTransfer")->setEnabled(no_export && (next_owner_mask & PERM_COPY) && !cannot_restrict_permissions);
getChildView("RadioSaleType")->setEnabled(is_complete && is_for_sale);
radioSaleType->setEnabled(is_complete && is_for_sale);
getChildView("TextPrice")->setEnabled(is_complete && is_for_sale);
getChildView("Edit Cost")->setEnabled(is_complete && is_for_sale);
edit_cost->setEnabled(is_complete && is_for_sale);
}
else
{
@@ -547,30 +563,55 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
getChildView("CheckNextOwnerCopy")->setEnabled(FALSE);
getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE);
getChildView("RadioSaleType")->setEnabled(FALSE);
radioSaleType->setEnabled(FALSE);
getChildView("TextPrice")->setEnabled(FALSE);
getChildView("Edit Cost")->setEnabled(FALSE);
edit_cost->setEnabled(FALSE);
}
// Set values.
getChild<LLUICtrl>("CheckPurchase")->setValue(is_for_sale);
getChildView("Edit Cost")->setEnabled(is_for_sale);
edit_cost->setEnabled(is_for_sale);
getChild<LLUICtrl>("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY)));
getChild<LLUICtrl>("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY)));
getChild<LLUICtrl>("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER)));
LLRadioGroup* radioSaleType = getChild<LLRadioGroup>("RadioSaleType");
if (is_for_sale)
{
radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1);
S32 numerical_price;
numerical_price = sale_info.getSalePrice();
getChild<LLUICtrl>("Edit Cost")->setValue(llformat("%d",numerical_price));
edit_cost->setValue(llformat("%d",numerical_price));
radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1);
}
else
{
edit_cost->setValue("0");
radioSaleType->setSelectedIndex(-1);
getChild<LLUICtrl>("Edit Cost")->setValue(llformat("%d",0));
}
}
void LLFloaterProperties::setAssociatedExperience(LLHandle<LLFloaterProperties> hInfo, const LLSD& experience)
{
LLFloaterProperties* info = hInfo.get();
if(info)
{
LLUUID id;
if (experience.has(LLExperienceCache::EXPERIENCE_ID))
{
id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID();
}
if (id.notNull())
{
//info->getChild<LLTextBox>("LabelItemExperience")->setText(LLSLURL("experience", id, "profile").getSLURLString();
if (LLNameBox* tb = info->getChild<LLNameBox>("LabelItemExperience"))
{
tb->setValue(id);
}
}
else
{
info->getChild<LLTextBox>("LabelItemExperience")->setText(LLTrans::getString("ExperienceNameNull"));
}
}
}
@@ -687,11 +728,6 @@ void LLFloaterProperties::onCommitPermissions()
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(),
CheckEveryoneCopy->get(), PERM_COPY);
}
LLCheckBoxCtrl* CheckExport = getChild<LLCheckBoxCtrl>("CheckExport");
if(CheckExport)
{
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT);
}
LLCheckBoxCtrl* CheckNextOwnerModify = getChild<LLCheckBoxCtrl>("CheckNextOwnerModify");
if(CheckNextOwnerModify)
@@ -711,6 +747,13 @@ void LLFloaterProperties::onCommitPermissions()
perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(),
CheckNextOwnerTransfer->get(), PERM_TRANSFER);
}
LLCheckBoxCtrl* CheckExport = getChild<LLCheckBoxCtrl>("CheckExport");
if(CheckExport && CheckExport->getVisible())
{
perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT);
}
if(perm != item->getPermissions()
&& item->isFinished())
{
@@ -884,7 +927,7 @@ void LLFloaterProperties::updateSaleInfo()
LLInventoryItem* LLFloaterProperties::findItem() const
{
LLInventoryItem* item = NULL;
LLInventoryItem* item = nullptr;
if(mObjectID.isNull())
{
// it is in agent inventory

View File

@@ -86,6 +86,8 @@ protected:
void refreshFromItem(LLInventoryItem* item);
virtual void draw();
static void setAssociatedExperience(LLHandle<LLFloaterProperties> hInfo, const LLSD& experience);
protected:
// The item id of the inventory item in question.
LLUUID mItemID;

View File

@@ -3,31 +3,25 @@
* @author Aaron Brashears
* @brief Implementation of the region info and controls floater and panels.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -65,6 +59,7 @@
#include "llfloaterregiondebugconsole.h"
#include "llfloatertelehub.h"
#include "llinventorymodel.h"
#include "lllayoutstack.h"
#include "lllineeditor.h"
#include "llnamelistctrl.h"
#include "llnotifications.h"
@@ -88,6 +83,11 @@
#include "llvlcomposition.h"
#include "llwaterparammanager.h"
#include "llagentui.h"
#include "llpanelexperiencelisteditor.h"
#include <boost/function.hpp>
#include "llpanelexperiencepicker.h"
#include "llexperiencecache.h"
#include "llpanelexperiences.h"
#include "hippogridmanager.h"
// [RLVa:KB]
#include "rlvhandler.h"
@@ -126,6 +126,18 @@ public:
const sparam_t& strings);
};
class LLDispatchSetEstateExperience : public LLDispatchHandler
{
public:
virtual bool operator()(
const LLDispatcher* dispatcher,
const std::string& key,
const LLUUID& invoice,
const sparam_t& strings);
LLSD getIDs(sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count);
};
/*
void unpack_request_params(
@@ -256,6 +268,13 @@ BOOL LLFloaterRegionInfo::postBuild()
LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml");
mTab->addTabPanel(panel, panel->getLabel(), FALSE);
if (!gAgent.getRegion()->getCapability("RegionExperiences").empty())
{
panel = new LLPanelRegionExperiences;
mInfoPanels.push_back(panel);
mTab->addTabPanel(panel, panel->getLabel(), FALSE);
}
gMessageSystem->setHandlerFunc(
"EstateOwnerMessage",
&processEstateOwnerRequest);
@@ -531,6 +550,16 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain()
return panel;
}
LLPanelRegionExperiences* LLFloaterRegionInfo::getPanelExperiences()
{
LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
if (!floater) return NULL;
LLTabContainer* tab_container = floater->getChild<LLTabContainer>("region_panels");
return (LLPanelRegionExperiences*)tab_container->getChild<LLPanel>("Experiences");
}
void LLFloaterRegionInfo::onTabSelected(const LLSD& param)
{
LLPanelRegionInfo* active_panel = getChild<LLPanelRegionInfo>(param.asString());
@@ -1538,6 +1567,11 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch)
static LLDispatchSetEstateAccess set_access;
dispatch.addHandler(name, &set_access);
name.assign("setexperience");
static LLDispatchSetEstateAccess set_experience;
dispatch.addHandler(name, &set_experience);
estate_dispatch_initialized = true;
}
@@ -3043,7 +3077,6 @@ void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok)
}
}
#if 0 // Singu TODO: Experiences
LLPanelRegionExperiences::LLPanelRegionExperiences()
: mTrusted(nullptr)
, mAllowed(nullptr)
@@ -3314,7 +3347,6 @@ void LLPanelRegionExperiences::itemChanged( U32 event_type, const LLUUID& id )
onChangeAnything();
}
#endif // Singu TODO: Experiences
LLPanelEstateAccess::LLPanelEstateAccess()
: LLPanelRegionInfo(), mPendingUpdate(false)
@@ -4358,10 +4390,11 @@ void LLFloaterRegionInfo::open()
{
const LLViewerRegion* region(gAgent.getRegion());
// Should be able to call LLRegion::canManageEstate() but then we can fake god like
if (!(region && region->isEstateManager() && region->getOwner() == gAgentID))
if (!region || !region->isEstateManager() || region->getOwner() != gAgentID)
return;
}
LLFloater::open();
}
// [/RLVa:KB]

View File

@@ -3,31 +3,25 @@
* @author Aaron Brashears
* @brief Declaration of the region info and controls floater and panels.
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
* Copyright (C) 2010, Linden Research, Inc.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
* 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.
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
* 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.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* 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$
*/
@@ -42,6 +36,7 @@
#include "llenvmanager.h" // for LLEnvironmentSettings
class LLAvatarName;
class LLDispatcher;
struct LLEstateAccessChangeInfo;
class LLLineEditor;
class LLMessageSystem;
@@ -57,6 +52,7 @@ class LLRadioGroup;
class LLSliderCtrl;
class LLSpinCtrl;
class LLTextBox;
class LLVFS;
class AIFilePicker;
class LLPanelRegionGeneralInfo;
@@ -64,8 +60,17 @@ class LLPanelRegionDebugInfo;
class LLPanelRegionTerrainInfo;
class LLPanelEstateInfo;
class LLPanelEstateCovenant;
class LLPanelExperienceListEditor;
class LLPanelExperiences;
class LLPanelRegionExperiences;
class LLPanelEstateAccess;
class LLEventTimer;
class LLEnvironmentSettings;
class LLWLParamManager;
class LLWaterParamManager;
class LLWLParamSet;
class LLWaterParamSet;
class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton<LLFloaterRegionInfo>
{
@@ -73,11 +78,11 @@ class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton<LLFloate
public:
/*virtual*/ void onOpen();
/*virtual*/ void onClose(bool app_quitting);
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(/*const LLSD& key*/) override;
/*virtual*/ void onClose(bool app_quitting) override;
/*virtual*/ BOOL postBuild() override;
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
/*virtual*/ void open();
/*virtual*/ void open() override;
// [/RLVa:KB]
static void processEstateOwnerRequest(LLMessageSystem* msg, void**);
@@ -94,9 +99,10 @@ public:
static LLPanelEstateAccess* getPanelAccess();
static LLPanelEstateCovenant* getPanelCovenant();
static LLPanelRegionTerrainInfo* getPanelRegionTerrain();
static LLPanelRegionExperiences* getPanelExperiences();
// from LLPanel
virtual void refresh();
void refresh() override;
void requestRegionInfo();
void requestMeshRezInfo();
@@ -139,7 +145,7 @@ public:
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
virtual BOOL postBuild();
BOOL postBuild() override;
virtual void updateChild(LLUICtrl* child_ctrl);
virtual void onOpen(const LLSD& key) {}
@@ -183,13 +189,14 @@ public:
: LLPanelRegionInfo() {}
~LLPanelRegionGeneralInfo() {}
virtual bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
// LLPanel
virtual BOOL postBuild();
BOOL postBuild() override;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
void onClickKick();
void onKickCommit(const uuid_vec_t& ids);
static void onClickKickAll(void* userdata);
@@ -208,12 +215,12 @@ public:
: LLPanelRegionInfo(), mTargetAvatar() {}
~LLPanelRegionDebugInfo() {}
// LLPanel
virtual BOOL postBuild();
BOOL postBuild() override;
virtual bool refreshFromRegion(LLViewerRegion* region);
bool refreshFromRegion(LLViewerRegion* region) override;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
void onClickChooseAvatar();
void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName>& names);
@@ -240,9 +247,9 @@ public:
LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {}
~LLPanelRegionTerrainInfo() {}
virtual BOOL postBuild(); // LLPanel
BOOL postBuild() override; // LLPanel
virtual bool refreshFromRegion(LLViewerRegion* region); // refresh local settings from region update from simulator
bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
void setEnvControls(bool available); // Whether environment settings are available for this region
BOOL validateTextureSizes();
@@ -251,7 +258,7 @@ protected:
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
static void onClickDownloadRaw(void*);
void onClickDownloadRaw_continued(AIFilePicker* filepicker);
@@ -294,13 +301,13 @@ public:
static void updateEstateName(const std::string& name);
static void updateEstateOwnerID(const LLUUID& id);
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg);
bool refreshFromRegion(LLViewerRegion* region) override;
bool estateUpdate(LLMessageSystem* msg) override;
// LLPanel
virtual BOOL postBuild();
virtual void updateChild(LLUICtrl* child_ctrl);
virtual void refresh();
BOOL postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
void refresh() override;
void refreshFromEstate();
@@ -309,7 +316,7 @@ public:
const std::string getOwnerName() const;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
// confirmation dialog callback
bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response);
@@ -330,16 +337,16 @@ public:
~LLPanelEstateCovenant() {}
// LLPanel
virtual BOOL postBuild();
virtual void updateChild(LLUICtrl* child_ctrl);
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg);
BOOL postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
bool refreshFromRegion(LLViewerRegion* region) override;
bool estateUpdate(LLMessageSystem* msg) override;
// LLView overrides
BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop, EDragAndDropType cargo_type,
void *cargo_data, EAcceptance *accept,
std::string& tooltip_msg);
std::string& tooltip_msg) override;
static bool confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response);
static void resetCovenantID(void* userdata);
static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response);
@@ -372,7 +379,7 @@ public:
} EAssetStatus;
protected:
virtual BOOL sendUpdate();
BOOL sendUpdate() override;
LLTextBox* mEstateNameText;
LLTextBox* mEstateOwnerText;
LLTextBox* mLastModifiedText;
@@ -392,17 +399,17 @@ public:
LLPanelEnvironmentInfo();
// LLPanel
/*virtual*/ BOOL postBuild();
/*virtual*/ void onOpen(const LLSD& key);
/*virtual*/ BOOL postBuild() override;
/*virtual*/ void onOpen(const LLSD& key) override;
// LLView
/*virtual*/ void handleVisibilityChange(BOOL new_visibility);
/*virtual*/ void handleVisibilityChange(BOOL new_visibility) override;
// LLPanelRegionInfo
/*virtual*/ bool refreshFromRegion(LLViewerRegion* region);
/*virtual*/ bool refreshFromRegion(LLViewerRegion* region) override;
private:
void refresh();
void refresh() override;
void setControlsEnabled(bool enabled);
void setApplyProgress(bool started);
void setDirty(bool dirty);
@@ -444,7 +451,6 @@ private:
LLComboBox* mDayCyclePresetCombo;
};
#if 0 // Singu TODO: Experiences
class LLPanelRegionExperiences : public LLPanelRegionInfo
{
LOG_CLASS(LLPanelEnvironmentInfo);
@@ -477,7 +483,6 @@ private:
LLUUID mDefaultExperience;
};
#endif // Singu TODO: Experiences
class LLPanelEstateAccess : public LLPanelRegionInfo
{

View File

@@ -82,6 +82,9 @@
#include "llagentui.h"
#include "lltrans.h"
#include "llexperiencecache.h"
#include "llcororesponder.h"
#include "rlvhandler.h"
@@ -137,7 +140,7 @@ BOOL LLFloaterReporter::postBuild()
// Default text to be blank
getChild<LLUICtrl>("object_name")->setValue(LLStringUtil::null);
getChild<LLUICtrl>("owner_name")->setValue(LLStringUtil::null);
getChild<LLUICtrl>("owner_name")->setValue(LLUUID::null);
mOwnerName = LLStringUtil::null;
getChild<LLUICtrl>("summary_edit")->setFocus(TRUE);
@@ -171,15 +174,34 @@ BOOL LLFloaterReporter::postBuild()
childSetAction("send_btn", onClickSend, this);
childSetAction("cancel_btn", onClickCancel, this);
// grab the user's name
std::string reporter;
LLAgentUI::buildFullname(reporter);
getChild<LLUICtrl>("reporter_field")->setValue(reporter);
getChild<LLUICtrl>("reporter_field")->setValue(gAgent.getID());
// request categories
if (gAgent.getRegion()
&& gAgent.getRegion()->capabilitiesReceived())
{
std::string cap_url = gAgent.getRegionCapability("AbuseCategories");
if (!cap_url.empty())
{
std::string lang = gSavedSettings.getString("Language");
if (lang != "default" && !lang.empty())
{
cap_url += "?lc=";
cap_url += lang;
}
LLHTTPClient::get(cap_url, new LLCoroResponder(
boost::bind(LLFloaterReporter::requestAbuseCategoriesCoro, _1, cap_url, this->getHandle())));
}
}
center();
return TRUE;
}
// virtual
LLFloaterReporter::~LLFloaterReporter()
{
@@ -204,16 +226,10 @@ LLFloaterReporter::~LLFloaterReporter()
delete mResourceDatap;
}
// virtual
void LLFloaterReporter::draw()
{
LLFloater::draw();
}
void LLFloaterReporter::enableControls(BOOL enable)
{
getChildView("category_combo")->setEnabled(enable);
getChildView("screenshot")->setEnabled(false);
getChildView("screenshot")->setEnabled(FALSE);
getChildView("pick_btn")->setEnabled(enable);
getChildView("summary_edit")->setEnabled(enable);
getChildView("details_edit")->setEnabled(enable);
@@ -221,6 +237,30 @@ void LLFloaterReporter::enableControls(BOOL enable)
getChildView("cancel_btn")->setEnabled(enable);
}
void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id)
{
mExperienceID = experience_id;
if (LLUUID::null != mExperienceID)
{
const LLSD& experience = LLExperienceCache::instance().get(mExperienceID);
std::stringstream desc;
if (experience.isDefined())
{
setFromAvatarID(experience[LLExperienceCache::AGENT_ID]);
desc << "Experience id: " << mExperienceID;
}
else
{
desc << "Unable to retrieve details for id: "<< mExperienceID;
}
LLUICtrl* details = getChild<LLUICtrl>("details_edit");
details->setValue(desc.str());
}
}
void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
{
// TODO --
@@ -249,6 +289,14 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id)
if (regionp)
{
getChild<LLUICtrl>("sim_field")->setValue(regionp->getName());
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
/*
if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) )
{
childSetText("sim_field", RlvStrings::getString(RLV_STRING_HIDDEN_REGION));
}
*/
// [/RLVa:KB]
LLVector3d global_pos;
global_pos.setVec(objectp->getPositionRegion());
setPosBox(global_pos);
@@ -305,6 +353,7 @@ void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vecto
void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id)
{
mAbuserID = mObjectID = avatar_id;
getChild<LLUICtrl>("owner_name")->setValue(mObjectID);
if (mAvatarNameCacheConnection.connected())
{
@@ -321,12 +370,74 @@ void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvata
{
mOwnerName = av_name.getNSName();
const std::string& name(((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(avatar_id)) ? RlvStrings::getString(RLV_STRING_HIDDEN) : mOwnerName);
getChild<LLUICtrl>("owner_name")->setValue(name);
getChild<LLUICtrl>("owner_name")->setValue(avatar_id);
getChild<LLUICtrl>("object_name")->setValue(name);
getChild<LLUICtrl>("abuser_name_edit")->setValue(name);
}
}
void LLFloaterReporter::requestAbuseCategoriesCoro(const LLCoroResponder& responder, std::string url, LLHandle<LLFloater> handle)
{
LLSD result = responder.getContent();
if (!responder.isGoodStatus(responder.getStatus()) || !result.has("categories")) // success = httpResults["success"].asBoolean();
{
LL_WARNS() << "Error requesting Abuse Categories from capability: " << url << LL_ENDL;
return;
}
if (handle.isDead())
{
// nothing to do
return;
}
LLFloater* floater = handle.get();
LLComboBox* combo = floater->getChild<LLComboBox>("category_combo");
if (!combo)
{
LL_WARNS() << "categories category_combo not found!" << LL_ENDL;
return;
}
//get selection (in case capability took a while)
S32 selection = combo->getCurrentIndex();
// Combobox should have a "Select category" element;
// This is a bit of workaround since there is no proper and simple way to save array of
// localizable strings in xml along with data (value). For now combobox is initialized along
// with placeholders, and first element is "Select category" which we want to keep, so remove
// everything but first element.
// Todo: once sim with capability fully releases, just remove this string and all unnecessary
// items from combobox since they will be obsolete (or depending on situation remake this to
// something better, for example move "Select category" to separate string)
while (combo->remove(1));
LLSD contents = result["categories"];
LLSD::array_iterator i = contents.beginArray();
LLSD::array_iterator iEnd = contents.endArray();
for (; i != iEnd; ++i)
{
const LLSD &message_data(*i);
std::string label = message_data["description_localized"];
const auto& cat = message_data["category"];
combo->add(label, cat);
switch(cat.asInteger())
{
// Fraud
case 47: combo->add(floater->getString("Ridiculous3"), 1000); break;
// Harassment
case 51: combo->add(floater->getString("Ridiculous1"), 1000); break;
// Land &gt; Encroachment
case 63: combo->add(floater->getString("Ridiculous2"), 1000); break;
default: break;
}
}
//restore selection
combo->selectNthItem(selection);
}
// static
void LLFloaterReporter::onClickSend(void *userdata)
@@ -413,7 +524,7 @@ void LLFloaterReporter::onClickObjPicker(void *userdata)
LLToolMgr::getInstance()->setTransientTool(LLToolObjPicker::getInstance());
self->mPicking = TRUE;
self->getChild<LLUICtrl>("object_name")->setValue(LLStringUtil::null);
self->getChild<LLUICtrl>("owner_name")->setValue(LLStringUtil::null);
self->getChild<LLUICtrl>("owner_name")->setValue(LLUUID::null);
self->mOwnerName = LLStringUtil::null;
LLButton* pick_btn = self->getChild<LLButton>("pick_btn");
if (pick_btn) pick_btn->setToggleState(TRUE);
@@ -454,7 +565,7 @@ void LLFloaterReporter::showFromMenu(EReportType report_type)
}
// static
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name)
void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name, const LLUUID& experience_id)
{
LLFloaterReporter* f = getInstance();
@@ -467,6 +578,23 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
{
f->setFromAvatarID(object_id);
}
if (experience_id.notNull())
{
f->getExperienceInfo(experience_id);
}
// Need to deselect on close
f->mDeselectOnClose = TRUE;
f->open(); /* Flawfinder: ignore */
}
void LLFloaterReporter::showFromExperience(const LLUUID& experience_id)
{
LLFloaterReporter* f = getInstance();
f->getExperienceInfo(experience_id);
// Need to deselect on close
f->mDeselectOnClose = TRUE;
@@ -476,9 +604,9 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_
// static
void LLFloaterReporter::showFromObject(const LLUUID& object_id)
void LLFloaterReporter::showFromObject(const LLUUID& object_id, const LLUUID& experience_id)
{
show(object_id);
show(object_id, LLStringUtil::null, experience_id);
}
// static
@@ -500,7 +628,7 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name
}
else
{
getChild<LLUICtrl>("owner_name")->setValue(owner_name);
getChild<LLUICtrl>("owner_name")->setValue(owner_id);
getChild<LLUICtrl>("abuser_name_edit")->setValue(owner_name);
}
mAbuserID = owner_id;
@@ -513,7 +641,7 @@ bool LLFloaterReporter::validateReport()
// Ensure user selected a category from the list
LLSD category_sd = getChild<LLUICtrl>("category_combo")->getValue();
U8 category = (U8)category_sd.asInteger();
if(category >= 100) //This is here for reasons (like shenanigans)
if(category == 1000) //This is here for reasons (like shenanigans)
{
LLNotificationsUtil::add("HelpReportNope");
return false;
@@ -604,7 +732,7 @@ LLSD LLFloaterReporter::gatherReport()
std::ostringstream details;
details << "V" << LLVersionInfo::getVersion() << std::endl; // client version moved to body of email for abuse reports
details << 'V' << LLVersionInfo::getVersion() << "\n\n"; // client version moved to body of email for abuse reports
std::string object_name = getChild<LLUICtrl>("object_name")->getValue().asString();
if (!object_name.empty() && !mOwnerName.empty())
@@ -628,12 +756,16 @@ LLSD LLFloaterReporter::gatherReport()
gGLManager.mGLRenderer.c_str(),
gGLManager.mDriverVersionVendorString.c_str());
// only send a screenshot ID if we're asked to and the email is
// going to LL - Estate Owners cannot see the screenshot asset
LLUUID screenshot_id = getChild<LLUICtrl>("screenshot")->getValue().asUUID();
LLSD report = LLSD::emptyMap();
report["report-type"] = (U8) mReportType;
report["category"] = getChild<LLUICtrl>("category_combo")->getValue();
report["position"] = mPosition.getValue();
report["check-flags"] = (U8)0; // this is not used
report["screenshot-id"] = getChild<LLUICtrl>("screenshot")->getValue();
report["screenshot-id"] = screenshot_id;
report["object-id"] = mObjectID;
report["abuser-id"] = mAbuserID;
report["abuse-region-name"] = "";
@@ -672,7 +804,7 @@ void LLFloaterReporter::sendReportViaLegacy(const LLSD & report)
msg->sendReliable(regionp->getHost());
}
class LLUserReportScreenshotResponder : public LLAssetUploadResponder
class LLUserReportScreenshotResponder final : public LLAssetUploadResponder
{
public:
LLUserReportScreenshotResponder(const LLSD & post_data,
@@ -692,17 +824,17 @@ public:
LLUploadDialog::modalUploadFinished();
}
/*virtual*/ char const* getName(void) const { return "LLUserReportScreenshotResponder"; }
char const* getName() const override { return "LLUserReportScreenshotResponder"; }
};
class LLUserReportResponder : public LLHTTPClient::ResponderWithCompleted
class LLUserReportResponder final : public LLHTTPClient::ResponderWithCompleted
{
LOG_CLASS(LLUserReportResponder);
public:
LLUserReportResponder() { }
private:
void httpCompleted()
void httpCompleted() override
{
if (!isGoodStatus(mStatus))
{
@@ -712,7 +844,7 @@ private:
// we don't care about what the server returns
LLUploadDialog::modalUploadFinished();
}
char const* getName() const { return "LLUserReportResponder"; }
char const* getName() const override { return "LLUserReportResponder"; }
};
void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report)
@@ -778,7 +910,7 @@ void LLFloaterReporter::takeScreenshot()
image_in_list->createGLTexture(0, raw, nullptr, TRUE, LLViewerTexture::OTHER);
// the texture picker then uses that texture
LLTexturePicker* texture = getChild<LLTextureCtrl>("screenshot");
LLTextureCtrl* texture = getChild<LLTextureCtrl>("screenshot");
if (texture)
{
texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid);
@@ -853,6 +985,7 @@ void LLFloaterReporter::setPosBox(const LLVector3d &pos)
getChild<LLUICtrl>("pos_field")->setValue(pos_string);
}
//void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd)
//{
// LLFloaterReporter *self = getInstance();

View File

@@ -77,22 +77,22 @@ enum EReportType
CS_REQUEST_REPORT = 4
};
class LLFloaterReporter
class LLFloaterReporter final
: public LLFloater, public LLSingleton<LLFloaterReporter>
{
public:
LLFloaterReporter();
/*virtual*/ ~LLFloaterReporter();
/*virtual*/ BOOL postBuild();
virtual void draw();
/*virtual*/ BOOL postBuild() override;
void setReportType(EReportType type) { mReportType = type; }
// Enables all buttons
static void showFromMenu(EReportType report_type);
static void showFromObject(const LLUUID& object_id);
static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null);
static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name);
static void showFromExperience(const LLUUID& experience_id);
static void onClickSend (void *userdata);
static void onClickCancel (void *userdata);
@@ -100,13 +100,13 @@ public:
void onClickSelectAbuser ();
static void closePickTool (void *userdata);
static void uploadDoneCallback(const LLUUID &uuid, void* user_data, S32 result, LLExtStat ext_status);
static void addDescription(const std::string& description, LLMeanCollisionData *mcd = NULL);
static void setDescription(const std::string& description, LLMeanCollisionData *mcd = NULL);
static void addDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr);
static void setDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr);
void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id);
private:
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null);
static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null);
void takeScreenshot();
void sendReportViaCaps(std::string url);
@@ -118,16 +118,20 @@ private:
void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report);
void setPosBox(const LLVector3d &pos);
void enableControls(BOOL own_avatar);
void getExperienceInfo(const LLUUID& object_id);
void getObjectInfo(const LLUUID& object_id);
void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName>& names);
void setFromAvatarID(const LLUUID& avatar_id);
void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name);
static void requestAbuseCategoriesCoro(const struct LLCoroResponder& responder, std::string url, LLHandle<LLFloater> handle);
private:
EReportType mReportType;
LLUUID mObjectID;
LLUUID mScreenID;
LLUUID mAbuserID;
LLUUID mExperienceID;
// Store the real name, not the link, for upstream reporting
std::string mOwnerName;
BOOL mDeselectOnClose;

View File

@@ -339,10 +339,10 @@ void LLFloaterSettingsDebug::updateControl()
mValSpinner2->setMaxValue(F32_MAX);
mValSpinner3->setMaxValue(F32_MAX);
mValSpinner4->setMaxValue(F32_MAX);
mValSpinner1->setMinValue(F32_MIN);
mValSpinner2->setMinValue(F32_MIN);
mValSpinner3->setMinValue(F32_MIN);
mValSpinner4->setMinValue(F32_MIN);
mValSpinner1->setMinValue(-F32_MAX);
mValSpinner2->setMinValue(-F32_MAX);
mValSpinner3->setMinValue(-F32_MAX);
mValSpinner4->setMinValue(-F32_MAX);
if (!mValSpinner1->hasFocus())
{
mValSpinner1->setIncrement(0.1f);

View File

@@ -66,6 +66,7 @@
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerwindow.h"
#include "llvoavatarself.h"
#include "llglheaders.h"
#include "llviewertexturelist.h"
//#include "lltoolobjpicker.h"
@@ -271,7 +272,7 @@ void LLHoverView::updateText()
line.clear();
if (hit_object->isAvatar())
{
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS))
if (gAgentAvatarp != hit_object && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS))
return; // No tag, no tip.
LLNameValue* title = hit_object->getNVPair("Title");
LLNameValue* firstname = hit_object->getNVPair("FirstName");
@@ -307,7 +308,7 @@ void LLHoverView::updateText()
}
mText.push_back(line);
mText.push_back(llformat("ARC: %d", hit_object->asAvatar()->getVisualComplexity()));
mText.push_back(LLTrans::getString("Complexity", LLSD().with("NUM", static_cast<LLSD::Integer>(hit_object->asAvatar()->getVisualComplexity()))));
}
else
{

File diff suppressed because it is too large Load Diff

View File

@@ -192,14 +192,14 @@ private:
**/
//--------------------------------------------------------------------
// Descendents
// Descendants
//--------------------------------------------------------------------
public:
// Make sure we have the descendents in the structure. Returns true
// Make sure we have the descendants in the structure. Returns true
// if a fetch was performed.
bool fetchDescendentsOf(const LLUUID& folder_id) const;
// Return the direct descendents of the id provided.Set passed
// Return the direct descendants of the id provided.Set passed
// in values to NULL if the call fails.
// NOTE: The array provided points straight into the guts of
// this object, and should only be used for read operations, since
@@ -211,10 +211,10 @@ public:
void getDirectDescendentsOf(const LLUUID& cat_id,
cat_array_t*& categories) const;
// Compute a hash of direct descendent names (for detecting child name changes)
// Compute a hash of direct descendant names (for detecting child name changes)
LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const;
// Starting with the object specified, add its descendents to the
// Starting with the object specified, add its descendants to the
// array provided, but do not add the inventory object specified
// by id. There is no guaranteed order.
// NOTE: Neither array will be erased before adding objects to it.
@@ -340,7 +340,7 @@ public:
U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0);
// Change an existing item with the matching id or add
// the category. No notifcation will be sent to observers. This
// the category. No notification will be sent to observers. This
// method will only generate network traffic if the item had to be
// reparented.
// NOTE: In usage, you will want to perform cache accounting
@@ -378,7 +378,7 @@ public:
bool update_parent_version = true,
bool do_notify_observers = true);
// Update model after all descendents removed from server.
// Update model after all descendants removed from server.
void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
// Update model after an existing item gets updated on server.
@@ -499,10 +499,12 @@ public:
// Call to explicitly update everyone on a new state.
void notifyObservers();
// Allows outsiders to tell the inventory if something has
// been changed 'under the hood', but outside the control of the
// inventory. The next notify will include that notification.
void addChangedMask(U32 mask, const LLUUID& referent);
const changed_items_t& getChangedIDs() const { return mChangedItemIDs; }
const changed_items_t& getAddedIDs() const { return mAddedItemIDs; }
protected:
@@ -556,6 +558,7 @@ protected:
static bool loadFromFile(const std::string& filename,
cat_array_t& categories,
item_array_t& items,
changed_items_t& cats_to_update,
bool& is_cache_obsolete);
static bool saveToFile(const std::string& filename,
const cat_array_t& categories,

View File

@@ -289,6 +289,7 @@ LLVector3d getRegionPosFromGlobalPos(const LLVector3d& global_pos, const LLSimIn
LLVector3d local_pos;
local_pos[0] = fmod(global_pos[0], siminfo ? siminfo->getSizeX() : 256);
local_pos[1] = fmod(global_pos[1], siminfo ? siminfo->getSizeY() : 256);
local_pos[2] = global_pos[2];
return local_pos;
}

View File

@@ -281,8 +281,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);;
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Get /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -345,8 +349,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);;
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Post /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -404,8 +412,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Get /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -480,8 +492,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Put /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -557,8 +573,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -629,8 +649,12 @@ public:
std::string body;
decode_raw_body(channels, buffer, body);
auto json = nlohmann::json::parse(body);
LLSD result = LlsdFromJson(json);
LLSD result = LlsdFromJsonString(body);
if (result.isUndefined())
{
log_SLM_warning("Delete /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response");
return;
}
if (!isGoodStatus(mStatus))
{
@@ -1265,7 +1289,7 @@ void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type&
}
log_SLM_infos("LLHTTPClient::get", url, LLStringUtil::null);
LLHTTPClient::get(url, LLSD(), new LLSLMGetMerchantResponder);
LLHTTPClient::get(url, new LLSLMGetMerchantResponder);
}
void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb)

View File

@@ -64,6 +64,7 @@
#include "llfloaterdisplayname.h"
#include "llfloatereditui.h"
#include "llfloaterenvsettings.h"
#include "llfloaterexperiences.h"
#include "llfloaterexploreanimations.h"
#include "llfloaterexploresounds.h"
#include "llfloaterfonttest.h"
@@ -119,6 +120,7 @@
void handle_debug_avatar_textures(void*);
template<typename T> void handle_singleton_toggle(void*);
void show_outfit_dialog() { new LLMakeOutfitDialog(false); }
class LLFloaterExperiencePicker* show_xp_picker(const LLSD& key);
void toggle_build() { LLToolMgr::getInstance()->toggleBuildMode(); }
void toggle_control(const std::string& name) { if (LLControlVariable* control = gSavedSettings.getControl(name)) control->set(!control->get()); }
void toggle_search_floater();
@@ -126,7 +128,7 @@ void toggle_always_run() { gAgent.getAlwaysRun() ? gAgent.clearAlwaysRun() : gAg
void toggle_sit();
void toggle_mouselook() { gAgentCamera.cameraMouselook() ? gAgentCamera.changeCameraToDefault() : gAgentCamera.changeCameraToMouselook(); }
bool is_visible_view(boost::function<LLView* ()> get)
bool is_visible_view(std::function<LLView* ()> get)
{
if (LLView* v = get())
return v->getVisible();
@@ -146,7 +148,7 @@ struct CommWrapper
struct MenuFloaterDict : public LLSingleton<MenuFloaterDict>
{
typedef std::map<const std::string, std::pair<boost::function<void ()>, boost::function<bool ()> > > menu_floater_map_t;
typedef std::map<const std::string, std::pair<std::function<void ()>, std::function<bool ()> > > menu_floater_map_t;
menu_floater_map_t mEntries;
MenuFloaterDict()
@@ -162,7 +164,7 @@ struct MenuFloaterDict : public LLSingleton<MenuFloaterDict>
registerConsole("texture size console", gTextureSizeView);
}
registerConsole("velocity", gVelocityBar);
registerFloater("about", boost::bind(&LLFloaterAbout::show,(void*)NULL));
registerFloater("about", boost::bind(&LLFloaterAbout::show,nullptr));
registerFloater("always run", boost::bind(toggle_always_run), boost::bind(&LLAgent::getAlwaysRun, &gAgent));
registerFloater("anims_explorer", boost::bind(LLFloaterExploreAnimations::show));
registerFloater("appearance", boost::bind(LLFloaterCustomize::show));
@@ -172,37 +174,38 @@ struct MenuFloaterDict : public LLSingleton<MenuFloaterDict>
registerFloater("buy land", boost::bind(&LLViewerParcelMgr::startBuyLand, boost::bind(LLViewerParcelMgr::getInstance), false));
registerFloater("complaint reporter", boost::bind(LLFloaterReporter::showFromMenu, COMPLAINT_REPORT));
registerFloater("DayCycle", boost::bind(LLFloaterDayCycle::show), boost::bind(LLFloaterDayCycle::isOpen));
registerFloater("debug avatar", boost::bind(handle_debug_avatar_textures, (void*)NULL));
registerFloater("debug settings", boost::bind(handle_singleton_toggle<LLFloaterSettingsDebug>, (void*)NULL));
registerFloater("edit ui", boost::bind(LLFloaterEditUI::show, (void*)NULL));
registerFloater("debug avatar", boost::bind(handle_debug_avatar_textures, nullptr));
registerFloater("debug settings", boost::bind(handle_singleton_toggle<LLFloaterSettingsDebug>, nullptr));
registerFloater("edit ui", boost::bind(LLFloaterEditUI::show, nullptr));
registerFloater("EnvSettings", boost::bind(LLFloaterEnvSettings::show), boost::bind(LLFloaterEnvSettings::isOpen));
registerFloater("experience_search", boost::bind(show_xp_picker, LLSD()));
registerFloater("fly", boost::bind(LLAgent::toggleFlying));
registerFloater("font test", boost::bind(LLFloaterFontTest::show, (void*)NULL));
registerFloater("god tools", boost::bind(LLFloaterGodTools::show, (void*)NULL));
registerFloater("grid options", boost::bind(LLFloaterBuildOptions::show, (void*)NULL));
registerFloater("font test", boost::bind(LLFloaterFontTest::show, nullptr));
registerFloater("god tools", boost::bind(LLFloaterGodTools::show, nullptr));
registerFloater("grid options", boost::bind(LLFloaterBuildOptions::show, nullptr));
registerFloater("group titles", boost::bind(HBFloaterGroupTitles::toggle));
//Singu TODO: Re-implement f1 help.
//registerFloater("help f1", boost::bind(/*gViewerHtmlHelp.show*/));
registerFloater("help tutorial", boost::bind(LLFloaterHUD::showHUD));
registerFloater("inventory", boost::bind(LLPanelMainInventory::toggleVisibility, (void*)NULL), boost::bind(is_visible_view, static_cast<boost::function<LLView* ()> >(LLPanelMainInventory::getActiveInventory)));
registerFloater("inventory", boost::bind(LLPanelMainInventory::toggleVisibility, nullptr), boost::bind(is_visible_view, static_cast<std::function<LLView* ()> >(LLPanelMainInventory::getActiveInventory)));
registerFloater("local assets", boost::bind(FloaterLocalAssetBrowser::show, (void*)0));
registerFloater("mean events", boost::bind(LLFloaterBump::show, (void*)NULL));
registerFloater("media ticker", boost::bind(handle_ticker_toggle, (void*)NULL), boost::bind(SHFloaterMediaTicker::instanceExists));
registerFloater("memleak", boost::bind(LLFloaterMemLeak::show, (void*)NULL));
registerFloater("mean events", boost::bind(LLFloaterBump::show, nullptr));
registerFloater("media ticker", boost::bind(handle_ticker_toggle, nullptr), boost::bind(SHFloaterMediaTicker::instanceExists));
registerFloater("memleak", boost::bind(LLFloaterMemLeak::show, nullptr));
registerFloater("messagelog", boost::bind(LLFloaterMessageLog::show));
registerFloater("mouselook", boost::bind(toggle_mouselook));
registerFloater("my land", boost::bind(LLFloaterLandHoldings::show, (void*)NULL));
registerFloater("my land", boost::bind(LLFloaterLandHoldings::show, nullptr));
registerFloater("outfit", boost::bind(show_outfit_dialog));
registerFloater("preferences", boost::bind(LLFloaterPreference::show, (void*)NULL));
registerFloater("preferences", boost::bind(LLFloaterPreference::show, nullptr));
registerFloater("quit", boost::bind(&LLAppViewer::userQuit, LLAppViewer::instance()));
registerFloater("RegionDebugConsole", boost::bind(handle_singleton_toggle<LLFloaterRegionDebugConsole>, (void*)NULL), boost::bind(LLFloaterRegionDebugConsole::instanceExists));
registerFloater("RegionDebugConsole", boost::bind(handle_singleton_toggle<LLFloaterRegionDebugConsole>, nullptr), boost::bind(LLFloaterRegionDebugConsole::instanceExists));
registerFloater("script errors", boost::bind(LLFloaterScriptDebug::show, LLUUID::null));
registerFloater("search", boost::bind(toggle_search_floater));
registerFloater("show inspect", boost::bind(LLFloaterInspect::showInstance, LLSD()));
registerFloater("sit", boost::bind(toggle_sit));
registerFloater("snapshot", boost::bind(LLFloaterSnapshot::show, (void*)NULL));
registerFloater("snapshot", boost::bind(LLFloaterSnapshot::show, nullptr));
registerFloater("sound_explorer", boost::bind(LLFloaterExploreSounds::toggle), boost::bind(LLFloaterExploreSounds::visible));
registerFloater("test", boost::bind(LLFloaterTest::show, (void*)NULL));
registerFloater("test", boost::bind(LLFloaterTest::show, nullptr));
// Phoenix: Wolfspirit: Enabled Show Floater out of viewer menu
registerFloater("WaterSettings", boost::bind(LLFloaterWater::show), boost::bind(LLFloaterWater::isOpen));
registerFloater("Windlight", boost::bind(LLFloaterWindLight::show), boost::bind(LLFloaterWindLight::isOpen));
@@ -220,6 +223,7 @@ struct MenuFloaterDict : public LLSingleton<MenuFloaterDict>
registerFloater<LLFloaterChatterBox> ("communicate");
registerFloater<LLFloaterDestinations> ("destinations");
registerFloater<LLFloaterDisplayName> ("displayname");
registerFloater<LLFloaterExperiences> ("experiences");
registerFloater<LLFloaterMyFriends> ("friends", 0);
registerFloater<LLFloaterGesture> ("gestures");
registerFloater<LLFloaterMyFriends> ("groups", 1);
@@ -248,12 +252,13 @@ struct MenuFloaterDict : public LLSingleton<MenuFloaterDict>
registerFloater<RlvFloaterStrings>("rlv strings");
// [/RLVa:LF]
}
public:
template <typename T>
void registerConsole(const std::string& name, T* console)
{
registerFloater(name, boost::bind(&T::setVisible, console, !boost::bind(&T::getVisible, console)), boost::bind(&T::getVisible, console));
}
void registerFloater(const std::string& name, boost::function<void ()> show, boost::function<bool ()> visible = NULL)
void registerFloater(const std::string& name, std::function<void ()> show, std::function<bool ()> visible = nullptr)
{
mEntries.insert( std::make_pair( name, std::make_pair( show, visible ) ) );
}

View File

@@ -569,6 +569,8 @@ LLMeshRepoThread::LLMeshRepoThread()
mMutex = new LLMutex();
mHeaderMutex = new LLMutex();
mSignal = new LLCondition();
mSkinInfoQMutex = new LLMutex();
mDecompositionQMutex = new LLMutex();
}
LLMeshRepoThread::~LLMeshRepoThread()
@@ -579,6 +581,10 @@ LLMeshRepoThread::~LLMeshRepoThread()
mHeaderMutex = NULL;
delete mSignal;
mSignal = NULL;
delete mSkinInfoQMutex;
mSkinInfoQMutex = NULL;
delete mDecompositionQMutex;
mDecompositionQMutex = NULL;
}
bool LLMeshRepoThread::HeaderRequest::fetch(U32& count)
@@ -1167,7 +1173,9 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
info.mMeshID = mesh_id;
//LL_INFOS() <<"info pelvis offset"<<info.mPelvisOffset<<LL_ENDL;
mSkinInfoQMutex->lock();
mSkinInfoQ.push(info);
mSkinInfoQMutex->unlock();
}
return true;
@@ -1193,7 +1201,9 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
{
LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
d->mMeshID = mesh_id;
mDecompositionQMutex->lock();
mDecompositionQ.push(d);
mDecompositionQMutex->unlock();
}
return true;
@@ -1252,7 +1262,9 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
}
}
mDecompositionQMutex->lock();
mDecompositionQ.push(d);
mDecompositionQMutex->unlock();
return true;
}
@@ -1862,14 +1874,22 @@ void LLMeshRepoThread::notifyLoadedMeshes()
while (!mSkinInfoQ.empty())
{
gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front());
mSkinInfoQMutex->lock();
auto req = mSkinInfoQ.front();
mSkinInfoQ.pop();
mSkinInfoQMutex->unlock();
gMeshRepo.notifySkinInfoReceived(req);
}
while (!mDecompositionQ.empty())
{
gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front());
mDecompositionQMutex->lock();
auto req = mDecompositionQ.front();
mDecompositionQ.pop();
mDecompositionQMutex->unlock();
gMeshRepo.notifyDecompositionReceived(req);
}
}

View File

@@ -265,6 +265,7 @@ public:
//queue of completed skin info requests
std::queue<LLMeshSkinInfo> mSkinInfoQ;
LLMutex* mSkinInfoQMutex;
//set of requested decompositions
uuid_set_t mDecompositionRequests;
@@ -274,6 +275,7 @@ public:
//queue of completed Decomposition info requests
std::queue<LLModel::Decomposition*> mDecompositionQ;
LLMutex* mDecompositionQMutex;
//queue of requested headers
std::deque<std::pair<std::shared_ptr<MeshRequest>, F32> > mHeaderReqQ;

View File

@@ -42,8 +42,9 @@ LLNameBox::LLNameBox(const std::string& name,
const Type& type,
const std::string& loading,
bool rlv_sensitive,
const std::string& name_system)
: LLNameUI(loading, rlv_sensitive, name_id, type, name_system)
const std::string& name_system,
bool click_for_profile)
: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile)
, LLTextBox(name, LLRect(), LLStringUtil::null, nullptr, TRUE)
{
setClickedCallback(boost::bind(&LLNameUI::showProfile, this));
@@ -80,7 +81,7 @@ BOOL LLNameBox::handleRightMouseDown(S32 x, S32 y, MASK mask)
BOOL LLNameBox::handleHover(S32 x, S32 y, MASK mask)
{
auto handled = LLTextBox::handleHover(x, y, mask);
if (mAllowInteract)
if (mClickForProfile && mAllowInteract)
{
getWindow()->setCursor(UI_CURSOR_HAND);
handled = true;
@@ -96,6 +97,7 @@ LLXMLNodePtr LLNameBox::getXML(bool save_children) const
node->setName("name_box");
node->createChild("initial_value", TRUE)->setStringValue(mInitialValue);
node->createChild("rlv_sensitive", TRUE)->setBoolValue(mRLVSensitive);
node->createChild("click_for_profile", TRUE)->setBoolValue(mClickForProfile);
node->createChild("name_system", TRUE)->setStringValue(mNameSystem);
return node;
@@ -114,7 +116,9 @@ LLView* LLNameBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
node->getAttribute_bool("rlv_sensitive", rlv_sensitive);
std::string name_system;
node->getAttributeString("name_system", name_system);
LLNameBox* name_box = new LLNameBox("name_box", id, (Type)type, loading, rlv_sensitive, name_system);
bool click_for_profile = true;
node->getAttribute_bool("click_for_profile", click_for_profile);
LLNameBox* name_box = new LLNameBox("name_box", id, (Type)type, loading, rlv_sensitive, name_system, click_for_profile);
name_box->initFromXML(node,parent);
return name_box;

View File

@@ -49,6 +49,8 @@ public:
void setValue(const LLSD& value) override final { LLNameUI::setValue(value); }
LLSD getValue() const override final { return LLNameUI::getValue(); }
BOOL handleMouseDown(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseDown(x, y, mask); }
BOOL handleMouseUp(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseUp(x, y, mask); }
BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override final;
BOOL handleHover(S32 x, S32 y, MASK mask) override final;
@@ -57,7 +59,8 @@ public:
const Type& type = AVATAR,
const std::string& loading = LLStringUtil::null,
bool rlv_sensitive = false,
const std::string& name_system = LLStringUtil::null);
const std::string& name_system = LLStringUtil::null,
bool click_for_profile = false);
};
#endif

View File

@@ -49,9 +49,8 @@ LLNameEditor::LLNameEditor(const std::string& name, const LLRect& rect,
bool click_for_profile,
const LLFontGL* glfont,
S32 max_text_length)
: LLNameUI(loading, rlv_sensitive, name_id, type, name_system)
: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile)
, LLLineEditor(name, rect, LLStringUtil::null, glfont, max_text_length)
, mClickForProfile(click_for_profile)
{
if (!name_id.isNull())
{

View File

@@ -40,7 +40,6 @@ class LLNameEditor final
: public LLLineEditor
, public LLNameUI
{
bool mClickForProfile;
public:
LLNameEditor(const std::string& name, const LLRect& rect,
const LLUUID& name_id = LLUUID::null,

View File

@@ -34,9 +34,11 @@
#include "llcachename.h"
#include "llagent.h"
#include "llavataractions.h"
#include "llfloaterexperienceprofile.h"
#include "llgroupactions.h"
#include "llinventory.h"
#include "llscrolllistitem.h"
#include "llscrolllistcell.h"
#include "llscrolllistcolumn.h"
#include "llsdparam.h"
#include "lltrans.h"
@@ -49,6 +51,7 @@ void LLNameListItem::NameTypeNames::declareValues()
declare("INDIVIDUAL", INDIVIDUAL);
declare("GROUP", GROUP);
declare("SPECIAL", SPECIAL);
declare("EXPERIENCE", EXPERIENCE);
}
LLNameListCtrl::LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border, bool draw_heading, S32 name_column_index, const std::string& name_system, const std::string& tooltip)
@@ -134,6 +137,7 @@ BOOL LLNameListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
{
case LLNameListItem::INDIVIDUAL: LLAvatarActions::showProfile(item->getValue()); break;
case LLNameListItem::GROUP: LLGroupActions::show(item->getValue()); break;
case LLNameListItem::EXPERIENCE: LLFloaterExperienceProfile::showInstance(item->getValue()); break;
default: return false;
}
handled = true;
@@ -159,8 +163,9 @@ LFIDBearer::Type LLNameListCtrl::getSelectedType() const
{
switch (static_cast<LLNameListItem*>(item)->getNameType())
{
CONVERT_TO_RETTYPE(case LLNameListItem::INDIVIDUAL, AVATAR);
CONVERT_TO_RETTYPE(case LLNameListItem::INDIVIDUAL, AVATAR)
CONVERT_TO_RETTYPE(case LLNameListItem::GROUP, GROUP)
CONVERT_TO_RETTYPE(case LLNameListItem::EXPERIENCE, EXPERIENCE)
CONVERT_TO_RETTYPE(default, COUNT) // Invalid, but just use count instead
}
}
@@ -212,7 +217,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
LLUUID id = name_item.value().asUUID();
LLNameListItem* item = new LLNameListItem(name_item);
if (!item) return NULL;
if (!item) return nullptr;
LLScrollListCtrl::addRow(item, name_item, pos);
@@ -277,6 +282,8 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(
}
break;
}
case LLNameListItem::EXPERIENCE:
// just use supplied name
default:
break;
}
@@ -461,13 +468,13 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto
LLRect rect;
createRect(node, rect, parent, LLRect());
BOOL multi_select = FALSE;
BOOL multi_select = false;
node->getAttributeBOOL("multi_select", multi_select);
BOOL draw_border = TRUE;
BOOL draw_border = true;
node->getAttributeBOOL("draw_border", draw_border);
BOOL draw_heading = FALSE;
BOOL draw_heading = false;
node->getAttributeBOOL("draw_heading", draw_heading);
S32 name_column_index = 0;
@@ -494,108 +501,5 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto
name_list->initFromXML(node, parent);
LLSD columns;
S32 index = 0;
LLXMLNodePtr child;
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
if (child->hasName("column"))
{
std::string labelname("");
child->getAttributeString("label", labelname);
std::string columnname(labelname);
child->getAttributeString("name", columnname);
std::string sortname(columnname);
child->getAttributeString("sort", sortname);
if (child->hasAttribute("relative_width"))
{
F32 columnrelwidth = 0.f;
child->getAttributeF32("relative_width", columnrelwidth);
columns[index]["relative_width"] = columnrelwidth;
}
else if (child->hasAttribute("relwidth"))
{
F32 columnrelwidth = 0.f;
child->getAttributeF32("relwidth", columnrelwidth);
columns[index]["relative_width"] = columnrelwidth;
}
else if (child->hasAttribute("dynamic_width"))
{
BOOL columndynamicwidth = FALSE;
child->getAttributeBOOL("dynamic_width", columndynamicwidth);
columns[index]["dynamic_width"] = columndynamicwidth;
}
else if (child->hasAttribute("dynamicwidth"))
{
BOOL columndynamicwidth = FALSE;
child->getAttributeBOOL("dynamicwidth", columndynamicwidth);
columns[index]["dynamic_width"] = columndynamicwidth;
}
else
{
S32 columnwidth = -1;
child->getAttributeS32("width", columnwidth);
columns[index]["width"] = columnwidth;
}
LLFontGL::HAlign h_align = LLFontGL::LEFT;
h_align = LLView::selectFontHAlign(child);
columns[index]["name"] = columnname;
columns[index]["label"] = labelname;
columns[index]["halign"] = (S32)h_align;
columns[index]["sort"] = sortname;
index++;
}
}
name_list->setColumnHeadings(columns);
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
{
if (child->hasName("row"))
{
LLUUID id;
child->getAttributeUUID("id", id);
LLSD row;
row["id"] = id;
S32 column_idx = 0;
LLXMLNodePtr row_child;
for (row_child = node->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling())
{
if (row_child->hasName("column"))
{
std::string value = row_child->getTextContents();
std::string columnname("");
row_child->getAttributeString("name", columnname);
std::string font("");
row_child->getAttributeString("font", font);
std::string font_style("");
row_child->getAttributeString("font-style", font_style);
row["columns"][column_idx]["column"] = columnname;
row["columns"][column_idx]["value"] = value;
row["columns"][column_idx]["font"] = font;
row["columns"][column_idx]["font-style"] = font_style;
column_idx++;
}
}
name_list->addElement(row);
}
}
std::string contents = node->getTextContents();
name_list->setCommentText(contents);
return name_list;
}

View File

@@ -46,7 +46,8 @@ public:
{
INDIVIDUAL,
GROUP,
SPECIAL
SPECIAL,
EXPERIENCE
};
// provide names for enums
@@ -98,8 +99,8 @@ public:
Alternative<S32> column_index;
Alternative<std::string> column_name;
NameColumn()
: column_name("name_column"),
column_index("name_column_index", 0)
: column_index("name_column_index", 0),
column_name("name_column")
{}
};
@@ -118,7 +119,7 @@ protected:
}
friend class LLUICtrlFactory;
public:
virtual LLXMLNodePtr getXML(bool save_children = true) const;
virtual LLXMLNodePtr getXML(bool save_children = true) const override;
static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
// Add a user to the list by name. It will be added, the name
@@ -127,7 +128,7 @@ public:
BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null, const std::string& prefix = LLStringUtil::null);
LLScrollListItem* addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM);
/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL);
/*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) override;
LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null,
const std::string& prefix = LLStringUtil::null);
@@ -146,7 +147,7 @@ public:
/*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask,
BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
EAcceptance *accept,
std::string& tooltip_msg);
std::string& tooltip_msg) override;
BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override;
Type getSelectedType() const override final;
@@ -160,8 +161,9 @@ private:
private:
S32 mNameColumnIndex;
//std::string mNameColumn;
BOOL mAllowCallingCardDrop;
const LLCachedControl<S32> mNameSystem;
const LLCachedControl<S32> mNameSystem; // Singu Note: Instead of mShortNames
typedef std::map<LLUUID, boost::signals2::connection> avatar_name_cache_connection_map_t;
avatar_name_cache_connection_map_t mAvatarNameCacheConnections;
@@ -169,7 +171,7 @@ private:
namelist_complete_signal_t mNameListCompleteSignal;
public:
boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback)
boost::signals2::connection setOnNameListCompleteCallback(std::function<void(bool)> onNameListCompleteCallback)
{
return mNameListCompleteSignal.connect(onNameListCompleteCallback);
}

View File

@@ -37,6 +37,8 @@
#include "llagentdata.h"
#include "llavataractions.h"
#include "llavatarnamecache.h"
#include "llexperiencecache.h"
#include "llfloaterexperienceprofile.h"
#include "llgroupactions.h"
#include "lltrans.h"
@@ -46,9 +48,10 @@
// statics
std::set<LLNameUI*> LLNameUI::sInstances;
LLNameUI::LLNameUI(const std::string& loading, bool rlv_sensitive, const LLUUID& id, const Type& type, const std::string& name_system)
LLNameUI::LLNameUI(const std::string& loading, bool rlv_sensitive, const LLUUID& id, const Type& type, const std::string& name_system, bool click_for_profile)
: mNameID(id), mRLVSensitive(rlv_sensitive), mType(NONE), mAllowInteract(false)
, mNameSystem(name_system.empty() ? "PhoenixNameSystem" : name_system), mInitialValue(!loading.empty() ? loading : LLTrans::getString("LoadingData"))
, mClickForProfile(click_for_profile)
{
setType(type);
}
@@ -66,7 +69,8 @@ void LLNameUI::setType(const Type& type)
else
{
sInstances.erase(this);
mConnections[1] = gSavedSettings.getControl(mNameSystem)->getCommitSignal()->connect(boost::bind(&LLNameUI::setNameText, this));
if (type == AVATAR)
mConnections[1] = gSavedSettings.getControl(mNameSystem)->getCommitSignal()->connect(boost::bind(&LLNameUI::setNameText, this));
}
mType = type;
}
@@ -83,7 +87,8 @@ void LLNameUI::setNameID(const LLUUID& name_id, const Type& type)
}
else
{
setText(LLTrans::getString(mType == GROUP ? "GroupNameNone" : "AvatarNameNobody"));
setText(LLTrans::getString(mType == GROUP ? "GroupNameNone" :
mType == AVATAR ? "AvatarNameNobody" : "ExperienceNameNull"));
displayAsLink(false);
}
}
@@ -97,6 +102,15 @@ void LLNameUI::setNameText()
{
got_name = gCacheName->getGroupName(mNameID, name);
}
else if (mType == EXPERIENCE)
{
auto& cache = LLExperienceCache::instance();
const auto& exp = cache.get(mNameID);
if (got_name = exp.isMap())
name = exp.has(LLExperienceCache::MISSING) && exp[LLExperienceCache::MISSING] ? LLTrans::getString("ExperienceNameNull") : exp[LLExperienceCache::NAME].asString();
else
cache.get(mNameID, boost::bind(&LLNameUI::setNameText, this));
}
else
{
LLAvatarName av_name;
@@ -144,10 +158,11 @@ void LLNameUI::showProfile()
{
if (!mAllowInteract) return;
switch (LFIDBearer::getActiveType())
switch (mType)
{
case LFIDBearer::GROUP: LLGroupActions::show(mNameID); break;
case LFIDBearer::AVATAR: LLAvatarActions::showProfile(mNameID); break;
case LFIDBearer::EXPERIENCE: LLFloaterExperienceProfile::showInstance(mNameID); break;
default: break;
}
}

View File

@@ -38,7 +38,7 @@
struct LLNameUI : public LFIDBearer
{
LLNameUI(const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, const LLUUID& id = LLUUID::null, const Type& type = AVATAR, const std::string& name_system = LLStringUtil::null);
LLNameUI(const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, const LLUUID& id = LLUUID::null, const Type& type = AVATAR, const std::string& name_system = LLStringUtil::null, bool click_for_profile = true);
virtual ~LLNameUI()
{
if (mType == GROUP) sInstances.erase(this);
@@ -47,7 +47,6 @@ struct LLNameUI : public LFIDBearer
}
LLUUID getStringUUIDSelectedItem() const override final { return mNameID; }
S32 getNumSelected() const override final { return 1; }
Type getSelectedType() const override final { return mType; }
void setType(const Type& type);
@@ -83,4 +82,5 @@ protected:
bool mAllowInteract;
std::string mInitialValue;
std::string mNameSystem;
bool mClickForProfile;
};

View File

@@ -70,7 +70,6 @@ public:
LLUUID getStringUUIDSelectedItem() const override final { return mClosestAgentAtLastRightClick; }
uuid_vec_t getSelectedIDs() const override final { return mClosestAgentsAtLastClick; }
S32 getNumSelected() const override final { return mClosestAgentsAtLastClick.size(); }
// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0)
void refreshParcelOverlay() { mUpdateParcelImage = true; }

View File

@@ -0,0 +1,280 @@
/**
* @file llpanelexperiencelisteditor.cpp
* @brief Editor for building a list of experiences
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llpanelexperiencelisteditor.h"
#include "llbutton.h"
#include "llexperiencecache.h"
#include "llfloaterexperiencepicker.h"
#include "llfloaterexperienceprofile.h"
//#include "llfloaterreg.h"
#include "llhandle.h"
#include "llnamelistctrl.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "lltextbox.h"
#include "lltrans.h"
/* Singu Note: We do not have injectors, so we'll have to call this function instead
static LLPanelInjector<LLPanelExperienceListEditor> t_panel_experience_list_editor("panel_experience_list_editor");
*/
void* create_xp_list_editor(void* data)
{
return *reinterpret_cast<LLPanelExperienceListEditor**>(data) = new LLPanelExperienceListEditor;
}
LLPanelExperienceListEditor::LLPanelExperienceListEditor()
:mItems(nullptr)
,mAdd(nullptr)
,mRemove(nullptr)
,mProfile(nullptr)
,mAddedCallback()
,mRemovedCallback()
,mReadonly(false)
,mMaxExperienceIDs(0)
{
}
BOOL LLPanelExperienceListEditor::postBuild()
{
mItems = getChild<LLScrollListCtrl>("experience_list");
mAdd = getChild<LLButton>("btn_add");
mRemove = getChild<LLButton>("btn_remove");
mProfile = getChild<LLButton>("btn_profile");
childSetAction("btn_add", boost::bind(&LLPanelExperienceListEditor::onAdd, this));
childSetAction("btn_remove", boost::bind(&LLPanelExperienceListEditor::onRemove, this));
childSetAction("btn_profile", boost::bind(&LLPanelExperienceListEditor::onProfile, this));
mItems->setCommitCallback(boost::bind(&LLPanelExperienceListEditor::checkButtonsEnabled, this));
checkButtonsEnabled();
return TRUE;
}
const uuid_list_t& LLPanelExperienceListEditor::getExperienceIds() const
{
return mExperienceIds;
}
void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience_ids )
{
// the commented out code in this function is handled by the callback and no longer necessary!
//mExperienceIds.insert(experience_ids.begin(), experience_ids.end());
//onItems();
if(!mAddedCallback.empty())
{
for(uuid_vec_t::const_iterator it = experience_ids.begin(); it != experience_ids.end(); ++it)
{
mAddedCallback(*it);
}
}
}
void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids )
{
mExperienceIds.clear();
for_each(experience_ids.beginArray(), experience_ids.endArray(), [this] (const LLUUID& id)
{
// Using insert(range) doesn't work here because the conversion from
// LLSD to LLUUID is ambiguous: have to specify asUUID() for each entry.
mExperienceIds.insert(id);
});
onItems();
}
void LLPanelExperienceListEditor::addExperience( const LLUUID& id )
{
mExperienceIds.insert(id);
onItems();
}
void LLPanelExperienceListEditor::onAdd()
{
if(!mPicker.isDead())
{
mPicker.markDead();
}
mKey.generateNewID();
LLFloaterExperiencePicker* picker = LLFloaterExperiencePicker::show(boost::bind(&LLPanelExperienceListEditor::addExperienceIds, this, _1), mKey, FALSE, TRUE, mFilters, mAdd);
mPicker = picker->getDerivedHandle<LLFloaterExperiencePicker>();
}
void LLPanelExperienceListEditor::onRemove()
{
// the commented out code in this function is handled by the callback and no longer necessary!
std::vector<LLScrollListItem*> items= mItems->getAllSelected();
std::vector<LLScrollListItem*>::iterator it = items.begin();
for(/**/; it != items.end(); ++it)
{
if((*it) != nullptr)
{
//mExperienceIds.erase((*it)->getValue());
mRemovedCallback((*it)->getValue());
}
}
mItems->selectFirstItem();
checkButtonsEnabled();
//onItems();
}
void LLPanelExperienceListEditor::onProfile()
{
LLScrollListItem* item = mItems->getFirstSelected();
if(item)
{
LLFloaterExperienceProfile::showInstance(item->getUUID());
}
}
void LLPanelExperienceListEditor::checkButtonsEnabled()
{
mAdd->setEnabled(!mReadonly);
int selected = mItems->getNumSelected();
bool remove_enabled = !mReadonly && selected>0;
if(remove_enabled && mSticky)
{
std::vector<LLScrollListItem*> items= mItems->getAllSelected();
std::vector<LLScrollListItem*>::iterator it = items.begin();
for(/**/; it != items.end() && remove_enabled; ++it)
{
if((*it) != nullptr)
{
remove_enabled = !mSticky((*it)->getValue());
}
}
}
mRemove->setEnabled(remove_enabled);
mProfile->setEnabled(selected==1);
}
void LLPanelExperienceListEditor::onItems()
{
mItems->deleteAllItems();
LLSD item;
uuid_list_t::iterator it = mExperienceIds.begin();
for(/**/; it != mExperienceIds.end(); ++it)
{
const LLUUID& experience = *it;
item["id"]=experience;
item["target"] = LLNameListItem::EXPERIENCE;
LLSD& columns = item["columns"];
columns[0]["column"] = "experience_name";
columns[0]["value"] = getString("loading");
mItems->addElement(item);
LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback,
getDerivedHandle<LLPanelExperienceListEditor>(), _1));
}
if(mItems->getItemCount() == 0)
{
mItems->setCommentText(getString("no_results"));
}
checkButtonsEnabled();
}
void LLPanelExperienceListEditor::experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience )
{
if(!panel.isDead())
{
panel.get()->onExperienceDetails(experience);
}
}
void LLPanelExperienceListEditor::onExperienceDetails( const LLSD& experience )
{
LLScrollListItem* item = mItems->getItem(experience[LLExperienceCache::EXPERIENCE_ID]);
if(!item)
return;
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
item->getColumn(0)->setValue(experience_name_string);
}
LLPanelExperienceListEditor::~LLPanelExperienceListEditor()
{
if(!mPicker.isDead())
{
mPicker.get()->close();
}
}
void LLPanelExperienceListEditor::loading()
{
mItems->clear();
mItems->setCommentText( getString("loading"));
}
void LLPanelExperienceListEditor::setReadonly( bool val )
{
mReadonly = val;
checkButtonsEnabled();
}
void LLPanelExperienceListEditor::refreshExperienceCounter()
{
if(mMaxExperienceIDs > 0)
{
LLStringUtil::format_map_t args;
args["[EXPERIENCES]"] = llformat("%d", mItems->getItemCount());
args["[MAXEXPERIENCES]"] = llformat("%d", mMaxExperienceIDs);
getChild<LLTextBox>("text_count")->setText(LLTrans::getString("ExperiencesCounter", args));
}
}
boost::signals2::connection LLPanelExperienceListEditor::setAddedCallback( list_changed_signal_t::slot_type cb )
{
return mAddedCallback.connect(cb);
}
boost::signals2::connection LLPanelExperienceListEditor::setRemovedCallback( list_changed_signal_t::slot_type cb )
{
return mRemovedCallback.connect(cb);
}

View File

@@ -0,0 +1,102 @@
/**
* @file llpanelexperiencelisteditor.cpp
* @brief Editor for building a list of experiences
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#ifndef LL_LLPANELEXPERIENCELISTEDITOR_H
#define LL_LLPANELEXPERIENCELISTEDITOR_H
#include "llpanel.h"
#include "lluuid.h"
#include <set>
class LLNameListCtrl;
class LLScrollListCtrl;
class LLButton;
class LLFloaterExperiencePicker;
void* create_xp_list_editor(void* data); // <singu/>
class LLPanelExperienceListEditor final : public LLPanel
{
public:
typedef boost::signals2::signal<void (const LLUUID&) > list_changed_signal_t;
// filter function for experiences, return true if the experience should be hidden.
typedef std::function<bool (const LLSD&)> experience_function;
typedef std::vector<experience_function> filter_list;
typedef LLHandle<LLFloaterExperiencePicker> PickerHandle;
LLPanelExperienceListEditor();
~LLPanelExperienceListEditor();
BOOL postBuild() override;
void loading();
const uuid_list_t& getExperienceIds()const;
void setExperienceIds(const LLSD& experience_ids);
void addExperienceIds(const uuid_vec_t& experience_ids);
void addExperience(const LLUUID& id);
boost::signals2::connection setAddedCallback(list_changed_signal_t::slot_type cb );
boost::signals2::connection setRemovedCallback(list_changed_signal_t::slot_type cb );
bool getReadonly() const { return mReadonly; }
void setReadonly(bool val);
void refreshExperienceCounter();
void addFilter(experience_function func){mFilters.push_back(func);}
void setStickyFunction(experience_function func){mSticky = func;}
U32 getMaxExperienceIDs() const { return mMaxExperienceIDs; }
void setMaxExperienceIDs(U32 val) { mMaxExperienceIDs = val; }
private:
void onItems();
void onRemove();
void onAdd();
void onProfile();
void checkButtonsEnabled();
static void experienceDetailsCallback( LLHandle<LLPanelExperienceListEditor> panel, const LLSD& experience );
void onExperienceDetails( const LLSD& experience );
void processResponse( const LLSD& content );
uuid_list_t mExperienceIds;
LLScrollListCtrl* mItems;
filter_list mFilters;
LLButton* mAdd;
LLButton* mRemove;
LLButton* mProfile;
PickerHandle mPicker;
list_changed_signal_t mAddedCallback;
list_changed_signal_t mRemovedCallback;
LLUUID mKey;
bool mReadonly;
experience_function mSticky;
U32 mMaxExperienceIDs;
};
#endif //LL_LLPANELEXPERIENCELISTEDITOR_H

View File

@@ -0,0 +1,270 @@
/**
* @file llpanelexperiencelog.cpp
* @brief llpanelexperiencelog
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llpanelexperiencelog.h"
#include "llexperiencelog.h"
#include "llexperiencecache.h"
#include "llbutton.h"
#include "llscrolllistctrl.h"
#include "llcombobox.h"
#include "llspinctrl.h"
#include "llcheckboxctrl.h"
#include "llfloaterexperienceprofile.h"
//#include "llfloaterreg.h"
#include "lluictrlfactory.h"
#include "llfloaterreporter.h"
#include "llinventoryfunctions.h"
#define BTN_PROFILE_XP "btn_profile_xp"
#define BTN_REPORT_XP "btn_report_xp"
/* Singu Note: We do not have injectors, so we'll have to call this function instead
static LLPanelInjector<LLPanelExperienceLog> register_experiences_panel("experience_log");
*/
void* create_xp_log(void* data) { return new LLPanelExperienceLog(false); }
LLPanelExperienceLog::LLPanelExperienceLog(bool build)
: mEventList(nullptr)
, mPageSize(25)
, mCurrentPage(0)
{
//buildFromFile("panel_experience_log.xml");
if (build) LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_log.xml"); // Singu Note: Use filename in xml
}
BOOL LLPanelExperienceLog::postBuild( void )
{
LLExperienceLog* log = LLExperienceLog::getInstance();
mEventList = getChild<LLScrollListCtrl>("experience_log_list");
mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this));
mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log));
getChild<LLButton>("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this));
getChild<LLButton>(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this));
getChild<LLButton>(BTN_REPORT_XP )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this));
getChild<LLButton>("btn_notify" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this));
getChild<LLButton>("btn_next" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this));
getChild<LLButton>("btn_prev" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this));
LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("notify_all");
check->set(log->getNotifyNewEvent());
check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this));
LLSpinCtrl* spin = getChild<LLSpinCtrl>("logsizespinner");
spin->set(log->getMaxDays());
spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this));
mPageSize = log->getPageSize();
refresh();
mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this));
return TRUE;
}
LLPanelExperienceLog* LLPanelExperienceLog::create()
{
return new LLPanelExperienceLog();
}
void LLPanelExperienceLog::refresh()
{
S32 selected = mEventList->getFirstSelectedIndex();
mEventList->deleteAllItems();
const LLSD events = LLExperienceLog::instance().getEvents();
if(events.size() == 0)
{
mEventList->setCommentText(getString("no_events"));
return;
}
setAllChildrenEnabled(FALSE);
LLSD item;
bool waiting = false;
LLUUID waiting_id;
U32 itemsToSkip = mPageSize*mCurrentPage;
U32 items = 0;
bool moreItems = false;
if (!events.emptyMap())
{
LLSD::map_const_iterator day = events.endMap();
do
{
--day;
const std::string& date = day->first;
if (LLExperienceLog::instance().isExpired(date))
{
continue;
}
const LLSD& dayArray = day->second;
U32 size = dayArray.size();
if(itemsToSkip > size)
{
itemsToSkip -= size;
continue;
}
if(items >= mPageSize && size > 0)
{
moreItems = true;
break;
}
for(int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--)
{
if (items >= mPageSize)
{
moreItems = true;
break;
}
const LLSD event = dayArray[i];
LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID();
const LLSD& experience = LLExperienceCache::instance().get(id);
if(experience.isUndefined()){
waiting = true;
waiting_id = id;
}
if(!waiting)
{
item["id"] = event;
LLSD& columns = item["columns"];
columns[0]["column"] = "time";
columns[0]["value"] = day->first+event["Time"].asString();
columns[1]["column"] = "event";
columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort");
columns[2]["column"] = "experience_name";
columns[2]["value"] = experience[LLExperienceCache::NAME].asString();
columns[3]["column"] = "object_name";
columns[3]["value"] = event["ObjectName"].asString();
mEventList->addElement(item);
}
++items;
}
} while (day != events.beginMap());
}
if (waiting)
{
mEventList->deleteAllItems();
mEventList->setCommentText(getString("loading"));
LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this));
}
else
{
setAllChildrenEnabled(TRUE);
mEventList->setEnabled(TRUE);
getChild<LLButton>("btn_next")->setEnabled(moreItems);
getChild<LLButton>("btn_prev")->setEnabled(mCurrentPage>0);
getChild<LLButton>("btn_clear")->setEnabled(mEventList->getItemCount()>0);
if (selected < 0)
{
selected = 0;
}
mEventList->selectNthItem(selected);
onSelectionChanged();
}
}
void LLPanelExperienceLog::onProfileExperience()
{
LLSD event = getSelectedEvent();
if (event.isDefined())
{
LLFloaterExperienceProfile::showInstance(event[LLExperienceCache::EXPERIENCE_ID].asUUID());
}
}
void LLPanelExperienceLog::onReportExperience()
{
LLSD event = getSelectedEvent();
if (event.isDefined())
{
LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID());
}
}
void LLPanelExperienceLog::onNotify()
{
LLSD event = getSelectedEvent();
if (event.isDefined())
{
LLExperienceLog::instance().notify(event);
}
}
void LLPanelExperienceLog::onNext()
{
mCurrentPage++;
refresh();
}
void LLPanelExperienceLog::onPrev()
{
if(mCurrentPage>0)
{
mCurrentPage--;
refresh();
}
}
void LLPanelExperienceLog::notifyChanged()
{
LLExperienceLog::instance().setNotifyNewEvent(getChild<LLCheckBoxCtrl>("notify_all")->get());
}
void LLPanelExperienceLog::logSizeChanged()
{
int value = (int)(getChild<LLSpinCtrl>("logsizespinner")->get());
LLExperienceLog::instance().setMaxDays(value);
refresh();
}
void LLPanelExperienceLog::onSelectionChanged()
{
bool enabled = (1 == mEventList->getNumSelected());
getChild<LLButton>(BTN_REPORT_XP)->setEnabled(enabled);
getChild<LLButton>(BTN_PROFILE_XP)->setEnabled(enabled);
getChild<LLButton>("btn_notify")->setEnabled(enabled);
}
LLSD LLPanelExperienceLog::getSelectedEvent()
{
LLScrollListItem* item = mEventList->getFirstSelected();
if(item)
{
return item->getValue();
}
return LLSD();
}

View File

@@ -0,0 +1,65 @@
/**
* @file llpanelexperiencelog.h
* @brief llpanelexperiencelog and related class definitions
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#ifndef LL_LLPANELEXPERIENCELOG_H
#define LL_LLPANELEXPERIENCELOG_H
#include "llpanel.h"
class LLScrollListCtrl;
void* create_xp_log(void* data);
class LLPanelExperienceLog final
: public LLPanel
{
public:
LLPanelExperienceLog(bool build = true);
static LLPanelExperienceLog* create();
/*virtual*/ BOOL postBuild(void) override;
void refresh() override;
protected:
void logSizeChanged();
void notifyChanged();
void onNext();
void onNotify();
void onPrev();
void onProfileExperience();
void onReportExperience();
void onSelectionChanged();
LLSD getSelectedEvent();
private:
LLScrollListCtrl* mEventList;
U32 mPageSize;
U32 mCurrentPage;
boost::signals2::scoped_connection mNewEvent;
};
#endif // LL_LLPANELEXPERIENCELOG_H

View File

@@ -0,0 +1,456 @@
/**
* @file llpanelexperiencepicker.cpp
* @brief Implementation of llpanelexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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 "llpanelexperiencepicker.h"
#include "lllineeditor.h"
#include "llfloaterexperienceprofile.h"
//#include "llfloaterreg.h"
#include "lluictrlfactory.h"
#include "llscrolllistctrl.h"
#include "llviewerregion.h"
#include "llagent.h"
#include "llexperiencecache.h"
#include "llslurl.h"
#include "llavatarnamecache.h"
#include "llcombobox.h"
#include "llviewercontrol.h"
#include "llfloater.h"
#include "lltrans.h"
#include <boost/regex.hpp>
#define BTN_FIND "find"
#define BTN_OK "ok_btn"
#define BTN_CANCEL "cancel_btn"
#define BTN_PROFILE "profile_btn"
#define BTN_LEFT "left_btn"
#define BTN_RIGHT "right_btn"
#define TEXT_EDIT "edit"
#define TEXT_MATURITY "maturity"
#define LIST_RESULTS "search_results"
#define PANEL_SEARCH "search_panel"
const static std::string columnSpace = " ";
/* Singu Note: We do not have injectors, so we'll have to call this function instead
static LLPanelInjector<LLPanelExperiencePicker> t_panel_status("llpanelexperiencepicker");
*/
void* create_xp_picker(void* data) { return new LLPanelExperiencePicker(false); }
LLPanelExperiencePicker::LLPanelExperiencePicker(bool build)
:LLPanel()
{
//buildFromFile("panel_experience_search.xml");
if (build) LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_search.xml"); // Singu Note: Use filename in xml
setDefaultFilters();
}
LLPanelExperiencePicker::~LLPanelExperiencePicker()
{
}
BOOL LLPanelExperiencePicker::postBuild()
{
getChild<LLLineEditor>(TEXT_EDIT)->setKeystrokeCallback(boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1));
childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
getChildView(BTN_FIND)->setEnabled(TRUE);
LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>(LIST_RESULTS);
searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this));
getChildView(LIST_RESULTS)->setEnabled(FALSE);
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
childSetAction(BTN_OK, boost::bind(&LLPanelExperiencePicker::onBtnSelect, this));
getChildView(BTN_OK)->setEnabled(FALSE);
childSetAction(BTN_CANCEL, boost::bind(&LLPanelExperiencePicker::onBtnClose, this));
childSetAction(BTN_PROFILE, boost::bind(&LLPanelExperiencePicker::onBtnProfile, this));
getChildView(BTN_PROFILE)->setEnabled(FALSE);
getChild<LLComboBox>(TEXT_MATURITY)->setCurrentByIndex(2);
getChild<LLComboBox>(TEXT_MATURITY)->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onMaturity, this));
getChild<LLUICtrl>(TEXT_EDIT)->setFocus(TRUE);
childSetAction(BTN_LEFT, boost::bind(&LLPanelExperiencePicker::onPage, this, -1));
childSetAction(BTN_RIGHT, boost::bind(&LLPanelExperiencePicker::onPage, this, 1));
LLPanel* search_panel = getChild<LLPanel>(PANEL_SEARCH);
if (search_panel)
{
// Start searching when Return is pressed in the line editor.
search_panel->setDefaultBtn(BTN_FIND);
}
return TRUE;
}
void LLPanelExperiencePicker::editKeystroke(class LLLineEditor* caller)
{
getChildView(BTN_FIND)->setEnabled(!caller->getText().empty());
}
void LLPanelExperiencePicker::onBtnFind()
{
mCurrentPage=1;
boost::cmatch what;
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
// *TODO: this should be part of LLUrlEntry
static const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile");
if (boost::regex_match(text.c_str(), what, expression))
{
LLURI uri(text);
LLSD path_array = uri.pathArray();
if (path_array.size() == 4)
{
std::string exp_id = path_array.get(2).asString();
LLUUID experience_id(exp_id);
if (!experience_id.isNull())
{
const LLSD& experience_details = LLExperienceCache::instance().get(experience_id);
if(!experience_details.isUndefined())
{
std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString();
if(!experience_name_string.empty())
{
getChild<LLUICtrl>(TEXT_EDIT)->setValue(experience_name_string);
}
}
else
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
getChildView(BTN_OK)->setEnabled(FALSE);
getChildView(BTN_PROFILE)->setEnabled(FALSE);
getChildView(BTN_RIGHT)->setEnabled(FALSE);
getChildView(BTN_LEFT)->setEnabled(FALSE);
LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this));
return;
}
}
}
}
find();
}
void LLPanelExperiencePicker::onList()
{
bool enabled = isSelectButtonEnabled();
getChildView(BTN_OK)->setEnabled(enabled);
enabled = enabled && getChild<LLScrollListCtrl>(LIST_RESULTS)->getNumSelected() == 1;
getChildView(BTN_PROFILE)->setEnabled(enabled);
}
void LLPanelExperiencePicker::find()
{
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
mQueryID.generate();
LLExperienceCache::instance().findExperienceByName(text, mCurrentPage,
boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle<LLPanelExperiencePicker>(), mQueryID, _1));
getChild<LLScrollListCtrl>(LIST_RESULTS)->deleteAllItems();
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("searching"));
getChildView(BTN_OK)->setEnabled(FALSE);
getChildView(BTN_PROFILE)->setEnabled(FALSE);
getChildView(BTN_RIGHT)->setEnabled(FALSE);
getChildView(BTN_LEFT)->setEnabled(FALSE);
}
/*static*/
void LLPanelExperiencePicker::findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult)
{
if (hparent.isDead())
return;
LLPanelExperiencePicker* panel = hparent.get();
if (panel)
{
panel->processResponse(queryId, foundResult);
}
}
bool LLPanelExperiencePicker::isSelectButtonEnabled()
{
LLScrollListCtrl* list=getChild<LLScrollListCtrl>(LIST_RESULTS);
return list->getFirstSelectedIndex() >=0;
}
void LLPanelExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids )
{
std::vector<LLScrollListItem*> items = results->getAllSelected();
for(std::vector<LLScrollListItem*>::iterator it = items.begin(); it != items.end(); ++it)
{
LLScrollListItem* item = *it;
if (item->getUUID().notNull())
{
experience_ids.push_back(item->getUUID());
}
}
}
void LLPanelExperiencePicker::setAllowMultiple( bool allow_multiple )
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setAllowMultipleSelection(allow_multiple);
}
void name_callback(const LLHandle<LLPanelExperiencePicker>& floater, const LLUUID& experience_id, const LLUUID& agent_id, const LLAvatarName& av_name)
{
if (floater.isDead())
return;
LLPanelExperiencePicker* picker = floater.get();
LLScrollListCtrl* search_results = picker->getChild<LLScrollListCtrl>(LIST_RESULTS);
LLScrollListItem* item = search_results->getItem(experience_id);
if (!item)
return;
item->getColumn(2)->setValue(columnSpace+av_name.getNSName());
}
void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content )
{
if (query_id != mQueryID)
{
return;
}
mResponse = content;
getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url"));
getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url"));
filterContent();
}
void LLPanelExperiencePicker::onBtnSelect()
{
if (!isSelectButtonEnabled())
{
return;
}
if(mSelectionCallback != nullptr)
{
const LLScrollListCtrl* results = getChild<LLScrollListCtrl>(LIST_RESULTS);
uuid_vec_t experience_ids;
getSelectedExperienceIds(results, experience_ids);
mSelectionCallback(experience_ids);
getChild<LLScrollListCtrl>(LIST_RESULTS)->deselectAllItems(TRUE);
if (mCloseOnSelect)
{
mCloseOnSelect = FALSE;
onBtnClose();
}
}
else
{
onBtnProfile();
}
}
void LLPanelExperiencePicker::onBtnClose()
{
LLFloater* floater = static_cast<LLFloater*>(getParent());
if (floater)
{
floater->close();
}
}
void LLPanelExperiencePicker::onBtnProfile()
{
LLScrollListItem* item = getChild<LLScrollListCtrl>(LIST_RESULTS)->getFirstSelected();
if (item)
{
LLFloaterExperienceProfile::showInstance(item->getUUID());
}
}
std::string LLPanelExperiencePicker::getMaturityString(int maturity)
{
if (maturity <= SIM_ACCESS_PG)
{
return getString("maturity_icon_general");
}
else if (maturity <= SIM_ACCESS_MATURE)
{
return getString("maturity_icon_moderate");
}
return getString("maturity_icon_adult");
}
void LLPanelExperiencePicker::filterContent()
{
LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>(LIST_RESULTS);
const LLSD& experiences=mResponse["experience_keys"];
search_results->deleteAllItems();
LLSD item;
LLSD::array_const_iterator it = experiences.beginArray();
for ( ; it != experiences.endArray(); ++it)
{
const LLSD& experience = *it;
if (isExperienceHidden(experience))
continue;
std::string experience_name_string = experience[LLExperienceCache::NAME].asString();
if (experience_name_string.empty())
{
experience_name_string = LLTrans::getString("ExperienceNameUntitled");
}
item["id"]=experience[LLExperienceCache::EXPERIENCE_ID];
LLSD& columns = item["columns"];
columns[0]["column"] = "maturity";
columns[0]["value"] = getMaturityString(experience[LLExperienceCache::MATURITY].asInteger());
columns[0]["type"]="icon";
columns[0]["halign"]="right";
columns[1]["column"] = "experience_name";
columns[1]["value"] = columnSpace+experience_name_string;
columns[2]["column"] = "owner";
columns[2]["value"] = columnSpace+getString("loading");
search_results->addElement(item);
LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID], boost::bind(name_callback, getDerivedHandle<LLPanelExperiencePicker>(), experience[LLExperienceCache::EXPERIENCE_ID], _1, _2));
}
if (search_results->isEmpty())
{
LLStringUtil::format_map_t map;
std::string search_text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
map["[TEXT]"] = search_text;
if (search_text.empty())
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("no_results"));
}
else
{
getChild<LLScrollListCtrl>(LIST_RESULTS)->setCommentText(getString("not_found", map));
}
search_results->setEnabled(false);
getChildView(BTN_OK)->setEnabled(false);
getChildView(BTN_PROFILE)->setEnabled(false);
}
else
{
getChildView(BTN_OK)->setEnabled(true);
search_results->setEnabled(true);
search_results->sortByColumnIndex(1, TRUE);
std::string text = getChild<LLUICtrl>(TEXT_EDIT)->getValue().asString();
if (!search_results->selectItemByLabel(text, TRUE))
{
search_results->selectFirstItem();
}
onList();
search_results->setFocus(TRUE);
}
}
void LLPanelExperiencePicker::onMaturity()
{
if (mResponse.has("experience_keys") && mResponse["experience_keys"].beginArray() != mResponse["experience_keys"].endArray())
{
filterContent();
}
}
bool LLPanelExperiencePicker::isExperienceHidden( const LLSD& experience) const
{
bool hide=false;
filter_list::const_iterator it = mFilters.begin();
for(/**/;it != mFilters.end(); ++it)
{
if ((*it)(experience)){
return true;
}
}
return hide;
}
bool LLPanelExperiencePicker::FilterOverRating( const LLSD& experience )
{
int maturity = getChild<LLComboBox>(TEXT_MATURITY)->getSelectedValue().asInteger();
return experience[LLExperienceCache::MATURITY].asInteger() > maturity;
}
bool LLPanelExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop)
{
return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0;
}
bool LLPanelExperiencePicker::FilterWithoutProperties( const LLSD& experience, S32 prop)
{
return ((experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == prop);
}
bool LLPanelExperiencePicker::FilterWithoutProperty( const LLSD& experience, S32 prop )
{
return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == 0;
}
void LLPanelExperiencePicker::setDefaultFilters()
{
mFilters.clear();
addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating, this, _1));
}
bool LLPanelExperiencePicker::FilterMatching( const LLSD& experience, const LLUUID& id )
{
if (experience.isUUID())
{
return experience.asUUID() == id;
}
return experience[LLExperienceCache::EXPERIENCE_ID].asUUID() == id;
}
void LLPanelExperiencePicker::onPage( S32 direction )
{
mCurrentPage += direction;
if (mCurrentPage < 1)
{
mCurrentPage = 1;
}
find();
}

View File

@@ -0,0 +1,96 @@
/**
* @file llpanelexperiencepicker.h
* @brief Header file for llpanelexperiencepicker
* @author dolphin@lindenlab.com
*
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2014, 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$
*/
#ifndef LL_LLPANELEXPERIENCEPICKER_H
#define LL_LLPANELEXPERIENCEPICKER_H
#include "llpanel.h"
class LLScrollListCtrl;
class LLLineEditor;
void* create_xp_picker(void* data);
class LLPanelExperiencePicker final : public LLPanel
{
public:
friend class LLExperienceSearchResponder;
friend class LLFloaterExperiencePicker;
typedef std::function<void (const uuid_vec_t&)> select_callback_t;
// filter function for experiences, return true if the experience should be hidden.
typedef std::function<bool (const LLSD&)> filter_function;
typedef std::vector<filter_function> filter_list;
LLPanelExperiencePicker(bool build = true);
virtual ~LLPanelExperiencePicker();
BOOL postBuild() override;
void addFilter(filter_function func){mFilters.push_back(func);}
template <class IT>
void addFilters(IT begin, IT end){mFilters.insert(mFilters.end(), begin, end);}
void setDefaultFilters();
static bool FilterWithProperty(const LLSD& experience, S32 prop);
static bool FilterWithoutProperties(const LLSD& experience, S32 prop);
static bool FilterWithoutProperty(const LLSD& experience, S32 prop);
static bool FilterMatching(const LLSD& experience, const LLUUID& id);
bool FilterOverRating(const LLSD& experience);
private:
void editKeystroke(LLLineEditor* caller);
void onBtnFind();
void onBtnSelect();
void onBtnClose();
void onBtnProfile();
void onList();
void onMaturity();
void onPage(S32 direction);
void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids );
void setAllowMultiple(bool allow_multiple);
void find();
static void findResults(LLHandle<LLPanelExperiencePicker> hparent, LLUUID queryId, LLSD foundResult);
bool isSelectButtonEnabled();
void processResponse( const LLUUID& query_id, const LLSD& content );
void filterContent();
bool isExperienceHidden(const LLSD& experience) const ;
std::string getMaturityString(int maturity);
select_callback_t mSelectionCallback;
filter_list mFilters;
LLUUID mQueryID;
LLSD mResponse;
bool mCloseOnSelect;
S32 mCurrentPage;
};
#endif // LL_LLPANELEXPERIENCEPICKER_H

View File

@@ -0,0 +1,154 @@
/**
* @file llpanelexperiences.cpp
* @brief LLPanelExperiences class implementation
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2013, 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 "lluictrlfactory.h"
#include "llexperiencecache.h"
#include "llagent.h"
#include "llfloaterexperienceprofile.h"
#include "llpanelexperiences.h"
#include "lllayoutstack.h"
#include "llnamelistctrl.h"
//static LLPanelInjector<LLPanelExperiences> register_experiences_panel("experiences_panel");
LLPanelExperiences::LLPanelExperiences()
: mExperiencesList(nullptr)
{
//buildFromFile("panel_experiences.xml");
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experiences.xml");
}
BOOL LLPanelExperiences::postBuild( void )
{
mExperiencesList = getChild<LLNameListCtrl>("experiences_list");
if (hasString("loading_experiences"))
{
mExperiencesList->setCommentText(getString("loading_experiences"));
}
else if (hasString("no_experiences"))
{
mExperiencesList->setCommentText(getString("no_experiences"));
}
return TRUE;
}
void addExperienceToList(const LLSD& experience, LLNameListCtrl* list)
{
// Don't add missing experiences, that seems wrong
if (experience.has(LLExperienceCache::MISSING) && experience[LLExperienceCache::MISSING].asBoolean())
return;
const auto& id = experience[LLExperienceCache::EXPERIENCE_ID];
list->removeNameItem(id); // Don't add the same item twice, this can happen
auto item = LLNameListCtrl::NameItem()
.name(experience[LLExperienceCache::NAME].asString())
.target(LLNameListItem::EXPERIENCE);
item.value(id)
.columns.add(LLScrollListCell::Params()); // Dummy column for names
list->addNameItemRow(item);
}
void LLPanelExperiences::setExperienceList( const LLSD& experiences )
{
mExperiencesList->setSortEnabled(false);
if (hasString("no_experiences"))
{
mExperiencesList->setCommentText(getString("no_experiences"));
}
mExperiencesList->clear();
auto& cache = LLExperienceCache::instance();
LLSD::array_const_iterator it = experiences.beginArray();
for( /**/ ; it != experiences.endArray(); ++it)
{
LLUUID public_key = it->asUUID();
if (public_key.notNull())
cache.get(public_key, boost::bind(addExperienceToList, _1, mExperiencesList));
}
mExperiencesList->setSortEnabled(true);
}
void LLPanelExperiences::getExperienceIdsList(uuid_vec_t& result)
{
result = mExperiencesList->getAllIDs();
}
LLPanelExperiences* LLPanelExperiences::create(const std::string& name)
{
LLPanelExperiences* panel= new LLPanelExperiences();
panel->setName(name);
return panel;
}
void LLPanelExperiences::removeExperiences( const LLSD& ids )
{
LLSD::array_const_iterator it = ids.beginArray();
for( /**/ ; it != ids.endArray(); ++it)
{
removeExperience(it->asUUID());
}
}
void LLPanelExperiences::removeExperience( const LLUUID& id )
{
mExperiencesList->removeNameItem(id);
}
void LLPanelExperiences::addExperience( const LLUUID& id )
{
if (!mExperiencesList->getItem(id))
{
LLExperienceCache::instance().get(id, boost::bind(addExperienceToList, _1, mExperiencesList));
}
}
void LLPanelExperiences::setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb )
{
if(label.empty())
{
getChild<LLLayoutPanel>("button_panel")->setVisible(false);
}
else
{
getChild<LLLayoutPanel>("button_panel")->setVisible(true);
LLButton* child = getChild<LLButton>("btn_action");
child->setCommitCallback(cb);
child->setLabel(getString(label));
}
}
void LLPanelExperiences::enableButton( bool enable )
{
getChild<LLButton>("btn_action")->setEnabled(enable);
}

Some files were not shown because too many files have changed in this diff Show More