From 699eac4ee37b31da78af2323ed15a47e6b386930 Mon Sep 17 00:00:00 2001 From: Bryan O'Sullivan Date: Wed, 18 Nov 2009 17:52:03 -0800 Subject: Switch some files to Unix line endings --- indra/cmake/run_build_test.py | 222 +- indra/llcommon/llallocator.h | 126 +- indra/llcommon/llcoros.h | 298 +- indra/llcommon/llfasttimer.h | 634 +- indra/llcommon/llmemory.h | 130 +- indra/llcommon/llmemtype.h | 496 +- indra/llcommon/llpreprocessor.h | 338 +- indra/llcommon/llstacktrace.cpp | 284 +- indra/llcommon/llstacktrace.h | 88 +- indra/llcommon/llstring.h | 2600 ++--- indra/llui/lltabcontainer.cpp | 2 +- .../quicktime/media_plugin_quicktime.cpp | 14 +- indra/newview/app_settings/ignorable_dialogs.xml | 582 +- indra/newview/llimview.cpp | 5112 ++++----- indra/newview/llinventorybridge.cpp | 10292 +++++++++---------- indra/newview/llinventoryfunctions.h | 272 +- indra/newview/llinventorypanel.cpp | 1780 ++-- indra/newview/llpanelimcontrolpanel.cpp | 2 +- indra/newview/llpanelmaininventory.cpp | 2044 ++-- indra/newview/llpanelmaininventory.h | 298 +- indra/newview/llpanelmediasettingssecurity.cpp | 690 +- indra/newview/llpanelobjectinventory.h | 204 +- indra/newview/llsidepanelinventory.cpp | 558 +- indra/newview/llsidepanelinventory.h | 182 +- indra/newview/llsidepanelinventorysubpanel.cpp | 310 +- indra/newview/llsidepanelinventorysubpanel.h | 164 +- indra/newview/llsidepaneliteminfo.cpp | 1766 ++-- indra/newview/llsidepaneliteminfo.h | 182 +- .../skins/default/xui/da/panel_edit_profile.xml | 90 +- .../newview/skins/default/xui/de/floater_about.xml | 80 +- .../skins/default/xui/de/floater_about_land.xml | 950 +- .../default/xui/de/floater_animation_preview.xml | 368 +- .../skins/default/xui/de/floater_avatar_picker.xml | 86 +- .../skins/default/xui/de/floater_beacons.xml | 42 +- .../skins/default/xui/de/floater_build_options.xml | 22 +- .../skins/default/xui/de/floater_bulk_perms.xml | 106 +- .../skins/default/xui/de/floater_buy_object.xml | 52 +- .../skins/default/xui/de/floater_camera.xml | 46 +- .../skins/default/xui/de/floater_color_picker.xml | 64 +- .../skins/default/xui/de/floater_god_tools.xml | 204 +- .../default/xui/de/floater_hardware_settings.xml | 56 +- .../skins/default/xui/de/floater_image_preview.xml | 64 +- .../xui/de/floater_inventory_item_properties.xml | 134 +- .../skins/default/xui/de/floater_land_holdings.xml | 80 +- .../default/xui/de/floater_live_lsleditor.xml | 30 +- indra/newview/skins/default/xui/de/floater_map.xml | 108 +- .../skins/default/xui/de/floater_media_browser.xml | 60 +- .../skins/default/xui/de/floater_mem_leaking.xml | 36 +- .../skins/default/xui/de/floater_moveview.xml | 70 +- indra/newview/skins/default/xui/de/floater_pay.xml | 38 +- .../skins/default/xui/de/floater_pay_object.xml | 58 +- .../default/xui/de/floater_preview_animation.xml | 24 +- .../default/xui/de/floater_preview_classified.xml | 12 +- .../skins/default/xui/de/floater_preview_event.xml | 12 +- .../xui/de/floater_preview_gesture_info.xml | 4 +- .../xui/de/floater_preview_gesture_steps.xml | 4 +- .../default/xui/de/floater_preview_notecard.xml | 44 +- .../skins/default/xui/de/floater_preview_sound.xml | 22 +- .../default/xui/de/floater_preview_texture.xml | 34 +- .../skins/default/xui/de/floater_report_abuse.xml | 208 +- .../default/xui/de/floater_script_debug_panel.xml | 4 +- .../default/xui/de/floater_script_preview.xml | 18 +- .../skins/default/xui/de/floater_script_queue.xml | 38 +- .../skins/default/xui/de/floater_sell_land.xml | 134 +- .../default/xui/de/floater_settings_debug.xml | 26 +- .../newview/skins/default/xui/de/floater_stats.xml | 142 +- .../newview/skins/default/xui/de/floater_tools.xml | 960 +- .../skins/default/xui/de/inspect_avatar.xml | 32 +- .../skins/default/xui/de/menu_avatar_icon.xml | 14 +- .../skins/default/xui/de/menu_favorites.xml | 20 +- .../skins/default/xui/de/menu_group_plus.xml | 10 +- .../skins/default/xui/de/menu_inventory.xml | 152 +- .../newview/skins/default/xui/de/menu_landmark.xml | 12 +- .../newview/skins/default/xui/de/menu_mini_map.xml | 16 +- indra/newview/skins/default/xui/de/menu_navbar.xml | 20 +- indra/newview/skins/default/xui/de/menu_picks.xml | 16 +- indra/newview/skins/default/xui/de/menu_place.xml | 14 +- indra/newview/skins/default/xui/de/menu_slurl.xml | 12 +- .../skins/default/xui/de/menu_url_agent.xml | 12 +- .../skins/default/xui/de/menu_url_group.xml | 12 +- .../newview/skins/default/xui/de/menu_url_http.xml | 14 +- .../skins/default/xui/de/menu_url_objectim.xml | 14 +- .../skins/default/xui/de/menu_url_parcel.xml | 10 +- .../skins/default/xui/de/menu_url_slurl.xml | 12 +- .../skins/default/xui/de/menu_url_teleport.xml | 10 +- .../newview/skins/default/xui/de/notifications.xml | 5126 ++++----- .../skins/default/xui/de/panel_edit_profile.xml | 76 +- .../skins/default/xui/de/panel_group_invite.xml | 58 +- .../default/xui/de/panel_group_land_money.xml | 340 +- .../skins/default/xui/de/panel_group_notices.xml | 294 +- .../skins/default/xui/de/panel_group_roles.xml | 236 +- .../default/xui/de/panel_im_control_panel.xml | 18 +- indra/newview/skins/default/xui/de/panel_login.xml | 38 +- .../skins/default/xui/de/panel_nearby_chat_bar.xml | 8 +- .../skins/default/xui/de/panel_pick_info.xml | 32 +- indra/newview/skins/default/xui/de/panel_picks.xml | 18 +- .../default/xui/de/panel_preferences_chat.xml | 84 +- .../default/xui/de/panel_preferences_graphics1.xml | 232 +- .../default/xui/de/panel_preferences_privacy.xml | 40 +- .../default/xui/de/panel_preferences_setup.xml | 92 +- .../newview/skins/default/xui/de/panel_profile.xml | 82 +- .../skins/default/xui/de/panel_profile_view.xml | 30 +- .../skins/default/xui/de/panel_script_ed.xml | 86 +- .../default/xui/de/panel_stand_stop_flying.xml | 12 +- .../skins/default/xui/de/panel_status_bar.xml | 44 +- .../skins/default/xui/de/panel_world_map.xml | 114 +- indra/newview/skins/default/xui/de/strings.xml | 6298 ++++++------ .../skins/default/xui/de/teleport_strings.xml | 156 +- .../default/xui/en/menu_inspect_avatar_gear.xml | 210 +- .../skins/default/xui/en/panel_group_notify.xml | 210 +- .../skins/default/xui/en/panel_main_inventory.xml | 934 +- .../skins/default/xui/en/sidepanel_inventory.xml | 254 +- .../skins/default/xui/en/sidepanel_item_info.xml | 1022 +- .../skins/default/xui/es/panel_edit_profile.xml | 90 +- .../newview/skins/default/xui/fr/floater_about.xml | 80 +- .../skins/default/xui/fr/floater_about_land.xml | 960 +- .../default/xui/fr/floater_animation_preview.xml | 372 +- .../skins/default/xui/fr/floater_avatar_picker.xml | 82 +- .../skins/default/xui/fr/floater_beacons.xml | 42 +- .../skins/default/xui/fr/floater_build_options.xml | 22 +- .../skins/default/xui/fr/floater_bulk_perms.xml | 106 +- .../skins/default/xui/fr/floater_buy_object.xml | 52 +- .../skins/default/xui/fr/floater_camera.xml | 46 +- .../skins/default/xui/fr/floater_color_picker.xml | 64 +- .../skins/default/xui/fr/floater_god_tools.xml | 212 +- .../default/xui/fr/floater_hardware_settings.xml | 56 +- .../skins/default/xui/fr/floater_image_preview.xml | 64 +- .../xui/fr/floater_inventory_item_properties.xml | 134 +- .../skins/default/xui/fr/floater_land_holdings.xml | 80 +- .../default/xui/fr/floater_live_lsleditor.xml | 30 +- indra/newview/skins/default/xui/fr/floater_map.xml | 108 +- .../skins/default/xui/fr/floater_media_browser.xml | 62 +- .../skins/default/xui/fr/floater_mem_leaking.xml | 36 +- .../skins/default/xui/fr/floater_moveview.xml | 70 +- indra/newview/skins/default/xui/fr/floater_pay.xml | 40 +- .../skins/default/xui/fr/floater_pay_object.xml | 60 +- .../default/xui/fr/floater_preview_animation.xml | 22 +- .../default/xui/fr/floater_preview_classified.xml | 12 +- .../skins/default/xui/fr/floater_preview_event.xml | 12 +- .../xui/fr/floater_preview_gesture_info.xml | 4 +- .../xui/fr/floater_preview_gesture_steps.xml | 4 +- .../default/xui/fr/floater_preview_notecard.xml | 44 +- .../skins/default/xui/fr/floater_preview_sound.xml | 22 +- .../default/xui/fr/floater_preview_texture.xml | 34 +- .../skins/default/xui/fr/floater_report_abuse.xml | 208 +- .../default/xui/fr/floater_script_debug_panel.xml | 4 +- .../default/xui/fr/floater_script_preview.xml | 18 +- .../skins/default/xui/fr/floater_script_queue.xml | 38 +- .../skins/default/xui/fr/floater_sell_land.xml | 132 +- .../default/xui/fr/floater_settings_debug.xml | 26 +- .../newview/skins/default/xui/fr/floater_stats.xml | 142 +- .../newview/skins/default/xui/fr/floater_tools.xml | 958 +- .../skins/default/xui/fr/inspect_avatar.xml | 32 +- .../skins/default/xui/fr/menu_avatar_icon.xml | 14 +- .../skins/default/xui/fr/menu_favorites.xml | 20 +- .../skins/default/xui/fr/menu_group_plus.xml | 10 +- .../skins/default/xui/fr/menu_inventory.xml | 152 +- .../newview/skins/default/xui/fr/menu_landmark.xml | 12 +- .../newview/skins/default/xui/fr/menu_mini_map.xml | 16 +- indra/newview/skins/default/xui/fr/menu_navbar.xml | 20 +- indra/newview/skins/default/xui/fr/menu_picks.xml | 16 +- indra/newview/skins/default/xui/fr/menu_place.xml | 14 +- indra/newview/skins/default/xui/fr/menu_slurl.xml | 12 +- .../skins/default/xui/fr/menu_url_agent.xml | 12 +- .../skins/default/xui/fr/menu_url_group.xml | 12 +- .../newview/skins/default/xui/fr/menu_url_http.xml | 14 +- .../skins/default/xui/fr/menu_url_objectim.xml | 14 +- .../skins/default/xui/fr/menu_url_parcel.xml | 10 +- .../skins/default/xui/fr/menu_url_slurl.xml | 12 +- .../skins/default/xui/fr/menu_url_teleport.xml | 10 +- .../newview/skins/default/xui/fr/notifications.xml | 5094 ++++----- .../skins/default/xui/fr/panel_edit_profile.xml | 76 +- .../skins/default/xui/fr/panel_group_invite.xml | 58 +- .../default/xui/fr/panel_group_land_money.xml | 172 +- .../skins/default/xui/fr/panel_group_list_item.xml | 8 +- .../skins/default/xui/fr/panel_group_notices.xml | 134 +- .../skins/default/xui/fr/panel_group_roles.xml | 226 +- .../default/xui/fr/panel_im_control_panel.xml | 18 +- indra/newview/skins/default/xui/fr/panel_login.xml | 38 +- .../skins/default/xui/fr/panel_nearby_chat_bar.xml | 8 +- indra/newview/skins/default/xui/fr/panel_picks.xml | 18 +- .../default/xui/fr/panel_preferences_chat.xml | 84 +- .../default/xui/fr/panel_preferences_graphics1.xml | 232 +- .../default/xui/fr/panel_preferences_privacy.xml | 42 +- .../default/xui/fr/panel_preferences_setup.xml | 92 +- .../default/xui/fr/panel_preferences_sound.xml | 80 +- .../newview/skins/default/xui/fr/panel_profile.xml | 82 +- .../skins/default/xui/fr/panel_profile_view.xml | 30 +- .../skins/default/xui/fr/panel_script_ed.xml | 86 +- .../default/xui/fr/panel_stand_stop_flying.xml | 12 +- .../skins/default/xui/fr/panel_status_bar.xml | 44 +- .../skins/default/xui/fr/panel_world_map.xml | 114 +- indra/newview/skins/default/xui/fr/strings.xml | 6298 ++++++------ .../skins/default/xui/fr/teleport_strings.xml | 154 +- .../skins/default/xui/it/panel_edit_profile.xml | 90 +- .../newview/skins/default/xui/ja/floater_about.xml | 80 +- .../skins/default/xui/ja/floater_about_land.xml | 950 +- .../default/xui/ja/floater_animation_preview.xml | 366 +- .../skins/default/xui/ja/floater_avatar_picker.xml | 80 +- .../skins/default/xui/ja/floater_beacons.xml | 42 +- .../skins/default/xui/ja/floater_build_options.xml | 22 +- .../skins/default/xui/ja/floater_bulk_perms.xml | 106 +- .../skins/default/xui/ja/floater_buy_object.xml | 52 +- .../skins/default/xui/ja/floater_camera.xml | 46 +- .../skins/default/xui/ja/floater_color_picker.xml | 62 +- .../skins/default/xui/ja/floater_god_tools.xml | 194 +- .../default/xui/ja/floater_hardware_settings.xml | 56 +- .../skins/default/xui/ja/floater_image_preview.xml | 64 +- .../xui/ja/floater_inventory_item_properties.xml | 134 +- .../skins/default/xui/ja/floater_land_holdings.xml | 80 +- .../default/xui/ja/floater_live_lsleditor.xml | 30 +- indra/newview/skins/default/xui/ja/floater_map.xml | 108 +- .../skins/default/xui/ja/floater_media_browser.xml | 60 +- .../skins/default/xui/ja/floater_mem_leaking.xml | 36 +- .../skins/default/xui/ja/floater_moveview.xml | 70 +- indra/newview/skins/default/xui/ja/floater_pay.xml | 38 +- .../skins/default/xui/ja/floater_pay_object.xml | 58 +- .../default/xui/ja/floater_preview_animation.xml | 22 +- .../default/xui/ja/floater_preview_classified.xml | 12 +- .../skins/default/xui/ja/floater_preview_event.xml | 12 +- .../xui/ja/floater_preview_gesture_info.xml | 4 +- .../xui/ja/floater_preview_gesture_steps.xml | 4 +- .../default/xui/ja/floater_preview_notecard.xml | 44 +- .../skins/default/xui/ja/floater_preview_sound.xml | 22 +- .../default/xui/ja/floater_preview_texture.xml | 34 +- .../skins/default/xui/ja/floater_report_abuse.xml | 206 +- .../default/xui/ja/floater_script_debug_panel.xml | 4 +- .../default/xui/ja/floater_script_preview.xml | 18 +- .../skins/default/xui/ja/floater_script_queue.xml | 38 +- .../skins/default/xui/ja/floater_sell_land.xml | 140 +- .../default/xui/ja/floater_settings_debug.xml | 26 +- .../newview/skins/default/xui/ja/floater_stats.xml | 142 +- .../newview/skins/default/xui/ja/floater_tools.xml | 954 +- .../skins/default/xui/ja/inspect_avatar.xml | 32 +- .../skins/default/xui/ja/menu_avatar_icon.xml | 14 +- .../skins/default/xui/ja/menu_favorites.xml | 20 +- .../skins/default/xui/ja/menu_group_plus.xml | 10 +- .../skins/default/xui/ja/menu_inventory.xml | 152 +- .../newview/skins/default/xui/ja/menu_landmark.xml | 12 +- .../newview/skins/default/xui/ja/menu_mini_map.xml | 16 +- indra/newview/skins/default/xui/ja/menu_navbar.xml | 20 +- indra/newview/skins/default/xui/ja/menu_picks.xml | 16 +- indra/newview/skins/default/xui/ja/menu_place.xml | 14 +- indra/newview/skins/default/xui/ja/menu_slurl.xml | 12 +- .../skins/default/xui/ja/menu_url_agent.xml | 12 +- .../skins/default/xui/ja/menu_url_group.xml | 12 +- .../newview/skins/default/xui/ja/menu_url_http.xml | 14 +- .../skins/default/xui/ja/menu_url_objectim.xml | 14 +- .../skins/default/xui/ja/menu_url_parcel.xml | 10 +- .../skins/default/xui/ja/menu_url_slurl.xml | 12 +- .../skins/default/xui/ja/menu_url_teleport.xml | 10 +- .../newview/skins/default/xui/ja/notifications.xml | 5370 +++++----- .../skins/default/xui/ja/panel_edit_profile.xml | 76 +- .../skins/default/xui/ja/panel_group_invite.xml | 60 +- .../default/xui/ja/panel_group_land_money.xml | 170 +- .../skins/default/xui/ja/panel_group_list_item.xml | 8 +- .../skins/default/xui/ja/panel_group_notices.xml | 132 +- .../skins/default/xui/ja/panel_group_roles.xml | 236 +- .../default/xui/ja/panel_im_control_panel.xml | 18 +- indra/newview/skins/default/xui/ja/panel_login.xml | 38 +- .../skins/default/xui/ja/panel_nearby_chat_bar.xml | 8 +- .../skins/default/xui/ja/panel_pick_info.xml | 32 +- indra/newview/skins/default/xui/ja/panel_picks.xml | 18 +- .../default/xui/ja/panel_preferences_chat.xml | 84 +- .../default/xui/ja/panel_preferences_graphics1.xml | 232 +- .../default/xui/ja/panel_preferences_privacy.xml | 40 +- .../default/xui/ja/panel_preferences_setup.xml | 92 +- .../default/xui/ja/panel_preferences_sound.xml | 144 +- .../newview/skins/default/xui/ja/panel_profile.xml | 82 +- .../skins/default/xui/ja/panel_profile_view.xml | 30 +- .../skins/default/xui/ja/panel_script_ed.xml | 86 +- .../default/xui/ja/panel_stand_stop_flying.xml | 12 +- .../skins/default/xui/ja/panel_status_bar.xml | 44 +- .../skins/default/xui/ja/panel_world_map.xml | 114 +- indra/newview/skins/default/xui/ja/strings.xml | 6298 ++++++------ .../skins/default/xui/ja/teleport_strings.xml | 158 +- .../skins/default/xui/nl/panel_edit_profile.xml | 90 +- .../skins/default/xui/pl/panel_edit_profile.xml | 90 +- .../skins/default/xui/pt/panel_edit_profile.xml | 90 +- 279 files changed, 43828 insertions(+), 43828 deletions(-) (limited to 'indra') diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py index 17bce6f434..fff78ecbe3 100644 --- a/indra/cmake/run_build_test.py +++ b/indra/cmake/run_build_test.py @@ -1,111 +1,111 @@ -#!/usr/bin/python -"""\ -@file run_build_test.py -@author Nat Goodspeed -@date 2009-09-03 -@brief Helper script to allow CMake to run some command after setting - environment variables. - -CMake has commands to run an external program. But remember that each CMake -command must be backed by multiple build-system implementations. Unfortunately -it seems CMake can't promise that every target build system can set specified -environment variables before running the external program of interest. - -This helper script is a workaround. It simply sets the requested environment -variables and then executes the program specified on the rest of its command -line. - -Example: - -python run_build_test.py -DFOO=bar myprog somearg otherarg - -sets environment variable FOO=bar, then runs: -myprog somearg otherarg - -$LicenseInfo:firstyear=2009&license=internal$ -Copyright (c) 2009, Linden Research, Inc. -$/LicenseInfo$ -""" - -import os -import sys -import subprocess - -def main(command, libpath=[], vars={}): - """Pass: - command is a sequence (e.g. a list) of strings. The first item in the list - must be the command name, the rest are its arguments. - - libpath is a sequence of directory pathnames. These will be appended to - the platform-specific dynamic library search path environment variable. - - vars is a dict of arbitrary (var, value) pairs to be added to the - environment before running 'command'. - - This function runs the specified command, waits for it to terminate and - returns its return code. This will be negative if the command terminated - with a signal, else it will be the process's specified exit code. - """ - # Handle platform-dependent libpath first. - if sys.platform == "win32": - lpvars = ["PATH"] - elif sys.platform == "darwin": - lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"] - elif sys.platform.startswith("linux"): - lpvars = ["LD_LIBRARY_PATH"] - else: - # No idea what the right pathname might be! But only crump if this - # feature is requested. - if libpath: - raise NotImplemented("run_build_test: unknown platform %s" % sys.platform) - lpvars = [] - for var in lpvars: - # Split the existing path. Bear in mind that the variable in question - # might not exist; instead of KeyError, just use an empty string. - dirs = os.environ.get(var, "").split(os.pathsep) - # Append the sequence in libpath -## print "%s += %r" % (var, libpath) - dirs.extend(libpath) - # Now rebuild the path string. This way we use a minimum of separators - # -- and we avoid adding a pointless separator when libpath is empty. - os.environ[var] = os.pathsep.join(dirs) - # Now handle arbitrary environment variables. The tricky part is ensuring - # that all the keys and values we try to pass are actually strings. -## if vars: -## print "Setting:" -## for key, value in vars.iteritems(): -## print "%s=%s" % (key, value) - os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()])) - # Run the child process. -## print "Running: %s" % " ".join(command) - return subprocess.call(command) - -if __name__ == "__main__": - from optparse import OptionParser - parser = OptionParser(usage="usage: %prog [options] command args...") - # We want optparse support for the options we ourselves handle -- but we - # DO NOT want it looking at options for the executable we intend to run, - # rejecting them as invalid because we don't define them. So configure the - # parser to stop looking for options as soon as it sees the first - # positional argument (traditional Unix syntax). - parser.disable_interspersed_args() - parser.add_option("-D", "--define", dest="vars", default=[], action="append", - metavar="VAR=value", - help="Add VAR=value to the env variables defined") - parser.add_option("-l", "--libpath", dest="libpath", default=[], action="append", - metavar="DIR", - help="Add DIR to the platform-dependent DLL search path") - opts, args = parser.parse_args() - # What we have in opts.vars is a list of strings of the form "VAR=value" - # or possibly just "VAR". What we want is a dict. We can build that dict by - # constructing a list of ["VAR", "value"] pairs -- so split each - # "VAR=value" string on the '=' sign (but only once, in case we have - # "VAR=some=user=string"). To handle the case of just "VAR", append "" to - # the list returned by split(), then slice off anything after the pair we - # want. - rc = main(command=args, libpath=opts.libpath, - vars=dict([(pair.split('=', 1) + [""])[:2] for pair in opts.vars])) - if rc not in (None, 0): - print >>sys.stderr, "Failure running: %s" % " ".join(args) - print >>sys.stderr, "Error: %s" % rc - sys.exit((rc < 0) and 255 or rc) +#!/usr/bin/python +"""\ +@file run_build_test.py +@author Nat Goodspeed +@date 2009-09-03 +@brief Helper script to allow CMake to run some command after setting + environment variables. + +CMake has commands to run an external program. But remember that each CMake +command must be backed by multiple build-system implementations. Unfortunately +it seems CMake can't promise that every target build system can set specified +environment variables before running the external program of interest. + +This helper script is a workaround. It simply sets the requested environment +variables and then executes the program specified on the rest of its command +line. + +Example: + +python run_build_test.py -DFOO=bar myprog somearg otherarg + +sets environment variable FOO=bar, then runs: +myprog somearg otherarg + +$LicenseInfo:firstyear=2009&license=internal$ +Copyright (c) 2009, Linden Research, Inc. +$/LicenseInfo$ +""" + +import os +import sys +import subprocess + +def main(command, libpath=[], vars={}): + """Pass: + command is a sequence (e.g. a list) of strings. The first item in the list + must be the command name, the rest are its arguments. + + libpath is a sequence of directory pathnames. These will be appended to + the platform-specific dynamic library search path environment variable. + + vars is a dict of arbitrary (var, value) pairs to be added to the + environment before running 'command'. + + This function runs the specified command, waits for it to terminate and + returns its return code. This will be negative if the command terminated + with a signal, else it will be the process's specified exit code. + """ + # Handle platform-dependent libpath first. + if sys.platform == "win32": + lpvars = ["PATH"] + elif sys.platform == "darwin": + lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"] + elif sys.platform.startswith("linux"): + lpvars = ["LD_LIBRARY_PATH"] + else: + # No idea what the right pathname might be! But only crump if this + # feature is requested. + if libpath: + raise NotImplemented("run_build_test: unknown platform %s" % sys.platform) + lpvars = [] + for var in lpvars: + # Split the existing path. Bear in mind that the variable in question + # might not exist; instead of KeyError, just use an empty string. + dirs = os.environ.get(var, "").split(os.pathsep) + # Append the sequence in libpath +## print "%s += %r" % (var, libpath) + dirs.extend(libpath) + # Now rebuild the path string. This way we use a minimum of separators + # -- and we avoid adding a pointless separator when libpath is empty. + os.environ[var] = os.pathsep.join(dirs) + # Now handle arbitrary environment variables. The tricky part is ensuring + # that all the keys and values we try to pass are actually strings. +## if vars: +## print "Setting:" +## for key, value in vars.iteritems(): +## print "%s=%s" % (key, value) + os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()])) + # Run the child process. +## print "Running: %s" % " ".join(command) + return subprocess.call(command) + +if __name__ == "__main__": + from optparse import OptionParser + parser = OptionParser(usage="usage: %prog [options] command args...") + # We want optparse support for the options we ourselves handle -- but we + # DO NOT want it looking at options for the executable we intend to run, + # rejecting them as invalid because we don't define them. So configure the + # parser to stop looking for options as soon as it sees the first + # positional argument (traditional Unix syntax). + parser.disable_interspersed_args() + parser.add_option("-D", "--define", dest="vars", default=[], action="append", + metavar="VAR=value", + help="Add VAR=value to the env variables defined") + parser.add_option("-l", "--libpath", dest="libpath", default=[], action="append", + metavar="DIR", + help="Add DIR to the platform-dependent DLL search path") + opts, args = parser.parse_args() + # What we have in opts.vars is a list of strings of the form "VAR=value" + # or possibly just "VAR". What we want is a dict. We can build that dict by + # constructing a list of ["VAR", "value"] pairs -- so split each + # "VAR=value" string on the '=' sign (but only once, in case we have + # "VAR=some=user=string"). To handle the case of just "VAR", append "" to + # the list returned by split(), then slice off anything after the pair we + # want. + rc = main(command=args, libpath=opts.libpath, + vars=dict([(pair.split('=', 1) + [""])[:2] for pair in opts.vars])) + if rc not in (None, 0): + print >>sys.stderr, "Failure running: %s" % " ".join(args) + print >>sys.stderr, "Error: %s" % rc + sys.exit((rc < 0) and 255 or rc) diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index 0d6f18c5d4..50129b4526 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -1,63 +1,63 @@ -/** - * @file llallocator.h - * @brief Declaration of the LLAllocator class. - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLALLOCATOR_H -#define LL_LLALLOCATOR_H - -#include - -#include "llmemtype.h" -#include "llallocator_heap_profile.h" - -class LL_COMMON_API LLAllocator { - friend class LLMemoryView; - friend class LLMemType; - -private: - static void pushMemType(S32 type); - static S32 popMemType(); - -public: - void setProfilingEnabled(bool should_enable); - - static bool isProfiling(); - - LLAllocatorHeapProfile const & getProfile(); - -private: - std::string getRawProfile(); - -private: - LLAllocatorHeapProfile mProf; -}; - -#endif // LL_LLALLOCATOR_H +/** + * @file llallocator.h + * @brief Declaration of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_H +#define LL_LLALLOCATOR_H + +#include + +#include "llmemtype.h" +#include "llallocator_heap_profile.h" + +class LL_COMMON_API LLAllocator { + friend class LLMemoryView; + friend class LLMemType; + +private: + static void pushMemType(S32 type); + static S32 popMemType(); + +public: + void setProfilingEnabled(bool should_enable); + + static bool isProfiling(); + + LLAllocatorHeapProfile const & getProfile(); + +private: + std::string getRawProfile(); + +private: + LLAllocatorHeapProfile mProf; +}; + +#endif // LL_LLALLOCATOR_H diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 6c5fa5af6d..141b0df43c 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -1,149 +1,149 @@ -/** - * @file llcoros.h - * @author Nat Goodspeed - * @date 2009-06-02 - * @brief Manage running boost::coroutine instances - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * Copyright (c) 2009, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLCOROS_H) -#define LL_LLCOROS_H - -#include -#include "llsingleton.h" -#include -#include -#include -#include -#include -#include - -/** - * Registry of named Boost.Coroutine instances - * - * The Boost.Coroutine library supports the general case of a coroutine - * accepting arbitrary parameters and yielding multiple (sets of) results. For - * such use cases, it's natural for the invoking code to retain the coroutine - * instance: the consumer repeatedly calls into the coroutine, perhaps passing - * new parameter values, prompting it to yield its next result. - * - * Our typical coroutine usage is different, though. For us, coroutines - * provide an alternative to the @c Responder pattern. Our typical coroutine - * has @c void return, invoked in fire-and-forget mode: the handler for some - * user gesture launches the coroutine and promptly returns to the main loop. - * The coroutine initiates some action that will take multiple frames (e.g. a - * capability request), waits for its result, processes it and silently steals - * away. - * - * This usage poses two (related) problems: - * - * # Who should own the coroutine instance? If it's simply local to the - * handler code that launches it, return from the handler will destroy the - * coroutine object, terminating the coroutine. - * # Once the coroutine terminates, in whatever way, who's responsible for - * cleaning up the coroutine object? - * - * LLCoros is a Singleton collection of currently-active coroutine instances. - * Each has a name. You ask LLCoros to launch a new coroutine with a suggested - * name prefix; from your prefix it generates a distinct name, registers the - * new coroutine and returns the actual name. - * - * The name can be used to kill off the coroutine prematurely, if needed. It - * can also provide diagnostic info: we can look up the name of the - * currently-running coroutine. - * - * Finally, the next frame ("mainloop" event) after the coroutine terminates, - * LLCoros will notice its demise and destroy it. - */ -class LL_COMMON_API LLCoros: public LLSingleton -{ -public: - /// Canonical boost::coroutines::coroutine signature we use - typedef boost::coroutines::coroutine coro; - /// Canonical 'self' type - typedef coro::self self; - - /** - * Create and start running a new coroutine with specified name. The name - * string you pass is a suggestion; it will be tweaked for uniqueness. The - * actual name is returned to you. - * - * Usage looks like this, for (e.g.) two coroutine parameters: - * @code - * class MyClass - * { - * public: - * ... - * // Do NOT NOT NOT accept reference params other than 'self'! - * // Pass by value only! - * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); - * ... - * }; - * ... - * std::string name = LLCoros::instance().launch( - * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, - * "somestring", LLSD(17)); - * @endcode - * - * Your function/method must accept LLCoros::self& as its first parameter. - * It can accept any other parameters you want -- but ONLY BY VALUE! - * Other reference parameters are a BAD IDEA! You Have Been Warned. See - * DEV-32777 comments for an explanation. - * - * Pass a callable that accepts the single LLCoros::self& parameter. It - * may work to pass a free function whose only parameter is 'self'; for - * all other cases use boost::bind(). Of course, for a non-static class - * method, the first parameter must be the class instance. Use the - * placeholder _1 for the 'self' parameter. Any other parameters should be - * passed via the bind() expression. - * - * launch() tweaks the suggested name so it won't collide with any - * existing coroutine instance, creates the coroutine instance, registers - * it with the tweaked name and runs it until its first wait. At that - * point it returns the tweaked name. - */ - template - std::string launch(const std::string& prefix, const CALLABLE& callable) - { - return launchImpl(prefix, new coro(callable)); - } - - /** - * Abort a running coroutine by name. Normally, when a coroutine either - * runs to completion or terminates with an exception, LLCoros quietly - * cleans it up. This is for use only when you must explicitly interrupt - * one prematurely. Returns @c true if the specified name was found and - * still running at the time. - */ - bool kill(const std::string& name); - - /** - * From within a coroutine, pass its @c self object to look up the - * (tweaked) name string by which this coroutine is registered. Returns - * the empty string if not found (e.g. if the coroutine was launched by - * hand rather than using LLCoros::launch()). - */ - template - std::string getName(const COROUTINE_SELF& self) const - { - return getNameByID(self.get_id()); - } - - /// getName() by self.get_id() - std::string getNameByID(const void* self_id) const; - -private: - friend class LLSingleton; - LLCoros(); - std::string launchImpl(const std::string& prefix, coro* newCoro); - std::string generateDistinctName(const std::string& prefix) const; - bool cleanup(const LLSD&); - - typedef boost::ptr_map CoroMap; - CoroMap mCoros; -}; - -#endif /* ! defined(LL_LLCOROS_H) */ +/** + * @file llcoros.h + * @author Nat Goodspeed + * @date 2009-06-02 + * @brief Manage running boost::coroutine instances + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLCOROS_H) +#define LL_LLCOROS_H + +#include +#include "llsingleton.h" +#include +#include +#include +#include +#include +#include + +/** + * Registry of named Boost.Coroutine instances + * + * The Boost.Coroutine library supports the general case of a coroutine + * accepting arbitrary parameters and yielding multiple (sets of) results. For + * such use cases, it's natural for the invoking code to retain the coroutine + * instance: the consumer repeatedly calls into the coroutine, perhaps passing + * new parameter values, prompting it to yield its next result. + * + * Our typical coroutine usage is different, though. For us, coroutines + * provide an alternative to the @c Responder pattern. Our typical coroutine + * has @c void return, invoked in fire-and-forget mode: the handler for some + * user gesture launches the coroutine and promptly returns to the main loop. + * The coroutine initiates some action that will take multiple frames (e.g. a + * capability request), waits for its result, processes it and silently steals + * away. + * + * This usage poses two (related) problems: + * + * # Who should own the coroutine instance? If it's simply local to the + * handler code that launches it, return from the handler will destroy the + * coroutine object, terminating the coroutine. + * # Once the coroutine terminates, in whatever way, who's responsible for + * cleaning up the coroutine object? + * + * LLCoros is a Singleton collection of currently-active coroutine instances. + * Each has a name. You ask LLCoros to launch a new coroutine with a suggested + * name prefix; from your prefix it generates a distinct name, registers the + * new coroutine and returns the actual name. + * + * The name can be used to kill off the coroutine prematurely, if needed. It + * can also provide diagnostic info: we can look up the name of the + * currently-running coroutine. + * + * Finally, the next frame ("mainloop" event) after the coroutine terminates, + * LLCoros will notice its demise and destroy it. + */ +class LL_COMMON_API LLCoros: public LLSingleton +{ +public: + /// Canonical boost::coroutines::coroutine signature we use + typedef boost::coroutines::coroutine coro; + /// Canonical 'self' type + typedef coro::self self; + + /** + * Create and start running a new coroutine with specified name. The name + * string you pass is a suggestion; it will be tweaked for uniqueness. The + * actual name is returned to you. + * + * Usage looks like this, for (e.g.) two coroutine parameters: + * @code + * class MyClass + * { + * public: + * ... + * // Do NOT NOT NOT accept reference params other than 'self'! + * // Pass by value only! + * void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); + * ... + * }; + * ... + * std::string name = LLCoros::instance().launch( + * "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, + * "somestring", LLSD(17)); + * @endcode + * + * Your function/method must accept LLCoros::self& as its first parameter. + * It can accept any other parameters you want -- but ONLY BY VALUE! + * Other reference parameters are a BAD IDEA! You Have Been Warned. See + * DEV-32777 comments for an explanation. + * + * Pass a callable that accepts the single LLCoros::self& parameter. It + * may work to pass a free function whose only parameter is 'self'; for + * all other cases use boost::bind(). Of course, for a non-static class + * method, the first parameter must be the class instance. Use the + * placeholder _1 for the 'self' parameter. Any other parameters should be + * passed via the bind() expression. + * + * launch() tweaks the suggested name so it won't collide with any + * existing coroutine instance, creates the coroutine instance, registers + * it with the tweaked name and runs it until its first wait. At that + * point it returns the tweaked name. + */ + template + std::string launch(const std::string& prefix, const CALLABLE& callable) + { + return launchImpl(prefix, new coro(callable)); + } + + /** + * Abort a running coroutine by name. Normally, when a coroutine either + * runs to completion or terminates with an exception, LLCoros quietly + * cleans it up. This is for use only when you must explicitly interrupt + * one prematurely. Returns @c true if the specified name was found and + * still running at the time. + */ + bool kill(const std::string& name); + + /** + * From within a coroutine, pass its @c self object to look up the + * (tweaked) name string by which this coroutine is registered. Returns + * the empty string if not found (e.g. if the coroutine was launched by + * hand rather than using LLCoros::launch()). + */ + template + std::string getName(const COROUTINE_SELF& self) const + { + return getNameByID(self.get_id()); + } + + /// getName() by self.get_id() + std::string getNameByID(const void* self_id) const; + +private: + friend class LLSingleton; + LLCoros(); + std::string launchImpl(const std::string& prefix, coro* newCoro); + std::string generateDistinctName(const std::string& prefix) const; + bool cleanup(const LLSD&); + + typedef boost::ptr_map CoroMap; + CoroMap mCoros; +}; + +#endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 905d736d62..45b84ea3ea 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,317 +1,317 @@ -/** - * @file llfasttimer.h - * @brief Declaration of a fast timer. - * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_FASTTIMER_H -#define LL_FASTTIMER_H - -#include "llinstancetracker.h" - -#define FAST_TIMER_ON 1 - -#if LL_WINDOWS - -// shift off lower 8 bits for lower resolution but longer term timing -// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing -inline U32 get_cpu_clock_count_32() -{ - U32 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - shr eax,8 - shl edx,24 - or eax, edx - mov dword ptr [ret_val], eax - } - return ret_val; -} - -// return full timer value, still shifted by 8 bits -inline U64 get_cpu_clock_count_64() -{ - U64 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - mov eax,eax - mov edx,edx - mov dword ptr [ret_val+4], edx - mov dword ptr [ret_val], eax - } - return ret_val >> 8; -} - -#endif // LL_WINDOWS - -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) -inline U32 get_cpu_clock_count_32() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return (U32)x >> 8; -} - -inline U32 get_cpu_clock_count_64() -{ - U64 x; - __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); - return x >> 8; -} -#endif - -#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) -// -// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock -// -// Just use gettimeofday implementation for now - -inline U32 get_cpu_clock_count_32() -{ - return (U32)get_clock_count(); -} - -inline U32 get_cpu_clock_count_64() -{ - return get_clock_count(); -} -#endif - -class LLMutex; - -#include -#include "llsd.h" - - -class LL_COMMON_API LLFastTimer -{ -public: - // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances - class LL_COMMON_API NamedTimer - : public LLInstanceTracker - { - friend class DeclareTimer; - public: - ~NamedTimer(); - - enum { HISTORY_NUM = 60 }; - - const std::string& getName() const { return mName; } - NamedTimer* getParent() const { return mParent; } - void setParent(NamedTimer* parent); - S32 getDepth(); - std::string getToolTip(S32 history_index = -1); - - typedef std::vector::const_iterator child_const_iter; - child_const_iter beginChildren(); - child_const_iter endChildren(); - std::vector& getChildren(); - - void setCollapsed(bool collapsed) { mCollapsed = collapsed; } - bool getCollapsed() const { return mCollapsed; } - - U32 getCountAverage() const { return mCountAverage; } - U32 getCallAverage() const { return mCallAverage; } - - U32 getHistoricalCount(S32 history_index = 0) const; - U32 getHistoricalCalls(S32 history_index = 0) const; - - static NamedTimer& getRootNamedTimer(); - - struct FrameState - { - FrameState(NamedTimer* timerp); - - U32 mSelfTimeCounter; - U32 mCalls; - FrameState* mParent; // info for caller timer - FrameState* mLastCaller; // used to bootstrap tree construction - NamedTimer* mTimer; - U16 mActiveCount; // number of timers with this ID active on stack - bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame - }; - - S32 getFrameStateIndex() const { return mFrameStateIndex; } - - FrameState& getFrameState() const; - - - private: - friend class LLFastTimer; - friend class NamedTimerFactory; - - // - // methods - // - NamedTimer(const std::string& name); - // recursive call to gather total time from children - static void accumulateTimings(); - - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); - - static void buildHierarchy(); - static void resetFrame(); - static void reset(); - - - // - // members - // - S32 mFrameStateIndex; - - std::string mName; - - U32 mTotalTimeCounter; - - U32 mCountAverage; - U32 mCallAverage; - - U32* mCountHistory; - U32* mCallHistory; - - // tree structure - NamedTimer* mParent; // NamedTimer of caller(parent) - std::vector mChildren; - bool mCollapsed; // don't show children - bool mNeedsSorting; // sort children whenever child added - - }; - - // used to statically declare a new named timer - class LL_COMMON_API DeclareTimer - : public LLInstanceTracker - { - public: - DeclareTimer(const std::string& name, bool open); - DeclareTimer(const std::string& name); - - static void updateCachedPointers(); - - // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) - operator NamedTimer::FrameState&() { return *mFrameState; } - private: - NamedTimer& mTimer; - NamedTimer::FrameState* mFrameState; - }; - - -public: - static LLMutex* sLogLock; - static std::queue sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - - typedef std::vector info_list_t; - static info_list_t& getFrameStateList(); - - enum RootTimerMarker { ROOT }; - LLFastTimer(RootTimerMarker); - - LLFastTimer(NamedTimer::FrameState& timer) - : mFrameState(&timer) - { -#if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = &timer; - U32 cur_time = get_cpu_clock_count_32(); - mStartSelfTime = cur_time; - mStartTotalTime = cur_time; - - frame_state->mActiveCount++; - frame_state->mCalls++; - // keep current parent as long as it is active when we are - frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - - mLastTimer = sCurTimer; - sCurTimer = this; -#endif - } - - ~LLFastTimer() - { -#if FAST_TIMER_ON - NamedTimer::FrameState* frame_state = mFrameState; - U32 cur_time = get_cpu_clock_count_32(); - frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; - - frame_state->mActiveCount--; - LLFastTimer* last_timer = mLastTimer; - sCurTimer = last_timer; - - // store last caller to bootstrap tree creation - frame_state->mLastCaller = last_timer->mFrameState; - - // we are only tracking self time, so subtract our total time delta from parents - U32 total_time = cur_time - mStartTotalTime; - last_timer->mStartSelfTime += total_time; -#endif - } - - - // call this once a frame to reset timers - static void nextFrame(); - - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); - - // call this to reset timer hierarchy, averages, etc. - static void reset(); - - static U64 countsPerSecond(); - static S32 getLastFrameIndex() { return sLastFrameIndex; } - static S32 getCurFrameIndex() { return sCurFrameIndex; } - - static void writeLog(std::ostream& os); - static const NamedTimer* getTimerByName(const std::string& name); - -public: - static bool sPauseHistory; - static bool sResetHistory; - -private: - typedef std::vector timer_stack_t; - static LLFastTimer* sCurTimer; - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static U64 sLastFrameTime; - static info_list_t* sTimerInfos; - - U32 mStartSelfTime; // start time + time of all child timers - U32 mStartTotalTime; // start time + time of all child timers - NamedTimer::FrameState* mFrameState; - LLFastTimer* mLastTimer; -}; - -#endif // LL_LLFASTTIMER_H +/** + * @file llfasttimer.h + * @brief Declaration of a fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 + +#if LL_WINDOWS + +// shift off lower 8 bits for lower resolution but longer term timing +// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing +inline U32 get_cpu_clock_count_32() +{ + U32 ret_val; + __asm + { + _emit 0x0f + _emit 0x31 + shr eax,8 + shl edx,24 + or eax, edx + mov dword ptr [ret_val], eax + } + return ret_val; +} + +// return full timer value, still shifted by 8 bits +inline U64 get_cpu_clock_count_64() +{ + U64 ret_val; + __asm + { + _emit 0x0f + _emit 0x31 + mov eax,eax + mov edx,edx + mov dword ptr [ret_val+4], edx + mov dword ptr [ret_val], eax + } + return ret_val >> 8; +} + +#endif // LL_WINDOWS + +#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +inline U32 get_cpu_clock_count_32() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return (U32)x >> 8; +} + +inline U32 get_cpu_clock_count_64() +{ + U64 x; + __asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); + return x >> 8; +} +#endif + +#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) +// +// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock +// +// Just use gettimeofday implementation for now + +inline U32 get_cpu_clock_count_32() +{ + return (U32)get_clock_count(); +} + +inline U32 get_cpu_clock_count_64() +{ + return get_clock_count(); +} +#endif + +class LLMutex; + +#include +#include "llsd.h" + + +class LL_COMMON_API LLFastTimer +{ +public: + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances + class LL_COMMON_API NamedTimer + : public LLInstanceTracker + { + friend class DeclareTimer; + public: + ~NamedTimer(); + + enum { HISTORY_NUM = 60 }; + + const std::string& getName() const { return mName; } + NamedTimer* getParent() const { return mParent; } + void setParent(NamedTimer* parent); + S32 getDepth(); + std::string getToolTip(S32 history_index = -1); + + typedef std::vector::const_iterator child_const_iter; + child_const_iter beginChildren(); + child_const_iter endChildren(); + std::vector& getChildren(); + + void setCollapsed(bool collapsed) { mCollapsed = collapsed; } + bool getCollapsed() const { return mCollapsed; } + + U32 getCountAverage() const { return mCountAverage; } + U32 getCallAverage() const { return mCallAverage; } + + U32 getHistoricalCount(S32 history_index = 0) const; + U32 getHistoricalCalls(S32 history_index = 0) const; + + static NamedTimer& getRootNamedTimer(); + + struct FrameState + { + FrameState(NamedTimer* timerp); + + U32 mSelfTimeCounter; + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* mLastCaller; // used to bootstrap tree construction + NamedTimer* mTimer; + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + }; + + S32 getFrameStateIndex() const { return mFrameStateIndex; } + + FrameState& getFrameState() const; + + + private: + friend class LLFastTimer; + friend class NamedTimerFactory; + + // + // methods + // + NamedTimer(const std::string& name); + // recursive call to gather total time from children + static void accumulateTimings(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); + + static void buildHierarchy(); + static void resetFrame(); + static void reset(); + + + // + // members + // + S32 mFrameStateIndex; + + std::string mName; + + U32 mTotalTimeCounter; + + U32 mCountAverage; + U32 mCallAverage; + + U32* mCountHistory; + U32* mCallHistory; + + // tree structure + NamedTimer* mParent; // NamedTimer of caller(parent) + std::vector mChildren; + bool mCollapsed; // don't show children + bool mNeedsSorting; // sort children whenever child added + + }; + + // used to statically declare a new named timer + class LL_COMMON_API DeclareTimer + : public LLInstanceTracker + { + public: + DeclareTimer(const std::string& name, bool open); + DeclareTimer(const std::string& name); + + static void updateCachedPointers(); + + // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) + operator NamedTimer::FrameState&() { return *mFrameState; } + private: + NamedTimer& mTimer; + NamedTimer::FrameState* mFrameState; + }; + + +public: + static LLMutex* sLogLock; + static std::queue sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; + + typedef std::vector info_list_t; + static info_list_t& getFrameStateList(); + + enum RootTimerMarker { ROOT }; + LLFastTimer(RootTimerMarker); + + LLFastTimer(NamedTimer::FrameState& timer) + : mFrameState(&timer) + { +#if FAST_TIMER_ON + NamedTimer::FrameState* frame_state = &timer; + U32 cur_time = get_cpu_clock_count_32(); + mStartSelfTime = cur_time; + mStartTotalTime = cur_time; + + frame_state->mActiveCount++; + frame_state->mCalls++; + // keep current parent as long as it is active when we are + frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); + + mLastTimer = sCurTimer; + sCurTimer = this; +#endif + } + + ~LLFastTimer() + { +#if FAST_TIMER_ON + NamedTimer::FrameState* frame_state = mFrameState; + U32 cur_time = get_cpu_clock_count_32(); + frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + + frame_state->mActiveCount--; + LLFastTimer* last_timer = mLastTimer; + sCurTimer = last_timer; + + // store last caller to bootstrap tree creation + frame_state->mLastCaller = last_timer->mFrameState; + + // we are only tracking self time, so subtract our total time delta from parents + U32 total_time = cur_time - mStartTotalTime; + last_timer->mStartSelfTime += total_time; +#endif + } + + + // call this once a frame to reset timers + static void nextFrame(); + + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); + + // call this to reset timer hierarchy, averages, etc. + static void reset(); + + static U64 countsPerSecond(); + static S32 getLastFrameIndex() { return sLastFrameIndex; } + static S32 getCurFrameIndex() { return sCurFrameIndex; } + + static void writeLog(std::ostream& os); + static const NamedTimer* getTimerByName(const std::string& name); + +public: + static bool sPauseHistory; + static bool sResetHistory; + +private: + typedef std::vector timer_stack_t; + static LLFastTimer* sCurTimer; + static S32 sCurFrameIndex; + static S32 sLastFrameIndex; + static U64 sLastFrameTime; + static info_list_t* sTimerInfos; + + U32 mStartSelfTime; // start time + time of all child timers + U32 mStartTotalTime; // start time + time of all child timers + NamedTimer::FrameState* mFrameState; + LLFastTimer* mLastTimer; +}; + +#endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 09f19532b7..1c6f64dd8b 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -1,65 +1,65 @@ -/** - * @file llmemory.h - * @brief Memory allocation/deallocation header-stuff goes here. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LLMEMORY_H -#define LLMEMORY_H - - - -extern S32 gTotalDAlloc; -extern S32 gTotalDAUse; -extern S32 gDACount; - -extern void* ll_allocate (size_t size); -extern void ll_release (void *p); - -class LL_COMMON_API LLMemory -{ -public: - static void initClass(); - static void cleanupClass(); - static void freeReserve(); - // Return the resident set size of the current process, in bytes. - // Return value is zero if not known. - static U64 getCurrentRSS(); -private: - static char* reserveMem; -}; - -// LLRefCount moved to llrefcount.h - -// LLPointer moved to llpointer.h - -// LLSafeHandle moved to llsafehandle.h - -// LLSingleton moved to llsingleton.h - -#endif +/** + * @file llmemory.h + * @brief Memory allocation/deallocation header-stuff goes here. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLMEMORY_H +#define LLMEMORY_H + + + +extern S32 gTotalDAlloc; +extern S32 gTotalDAUse; +extern S32 gDACount; + +extern void* ll_allocate (size_t size); +extern void ll_release (void *p); + +class LL_COMMON_API LLMemory +{ +public: + static void initClass(); + static void cleanupClass(); + static void freeReserve(); + // Return the resident set size of the current process, in bytes. + // Return value is zero if not known. + static U64 getCurrentRSS(); +private: + static char* reserveMem; +}; + +// LLRefCount moved to llrefcount.h + +// LLPointer moved to llpointer.h + +// LLSafeHandle moved to llsafehandle.h + +// LLSingleton moved to llsingleton.h + +#endif diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index 5952a3a7c5..677fad3034 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -1,248 +1,248 @@ -/** - * @file llmemtype.h - * @brief Runtime memory usage debugging utilities. - * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_MEMTYPE_H -#define LL_MEMTYPE_H - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- - -//---------------------------------------------------------------------------- - -#include "linden_common.h" -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// WARNING: Never commit with MEM_TRACK_MEM == 1 -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -#define MEM_TRACK_MEM (0 && LL_WINDOWS) - -#include - -#define MEM_TYPE_NEW(T) - -class LL_COMMON_API LLMemType -{ -public: - - // class we'll initialize all instances of as - // static members of MemType. Then use - // to construct any new mem type. - class LL_COMMON_API DeclareMemType - { - public: - DeclareMemType(char const * st); - ~DeclareMemType(); - - S32 mID; - char const * mName; - - // array so we can map an index ID to Name - static std::vector mNameList; - }; - - LLMemType(DeclareMemType& dt); - ~LLMemType(); - - static char const * getNameFromID(S32 id); - - static DeclareMemType MTYPE_INIT; - static DeclareMemType MTYPE_STARTUP; - static DeclareMemType MTYPE_MAIN; - static DeclareMemType MTYPE_FRAME; - - static DeclareMemType MTYPE_GATHER_INPUT; - static DeclareMemType MTYPE_JOY_KEY; - - static DeclareMemType MTYPE_IDLE; - static DeclareMemType MTYPE_IDLE_PUMP; - static DeclareMemType MTYPE_IDLE_NETWORK; - static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; - static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; - static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; - static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; - static DeclareMemType MTYPE_IDLE_AUDIO; - - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; - static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; - - static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; - static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; - - static DeclareMemType MTYPE_RENDER; - static DeclareMemType MTYPE_SLEEP; - - static DeclareMemType MTYPE_NETWORK; - static DeclareMemType MTYPE_PHYSICS; - static DeclareMemType MTYPE_INTERESTLIST; - - static DeclareMemType MTYPE_IMAGEBASE; - static DeclareMemType MTYPE_IMAGERAW; - static DeclareMemType MTYPE_IMAGEFORMATTED; - - static DeclareMemType MTYPE_APPFMTIMAGE; - static DeclareMemType MTYPE_APPRAWIMAGE; - static DeclareMemType MTYPE_APPAUXRAWIMAGE; - - static DeclareMemType MTYPE_DRAWABLE; - - static DeclareMemType MTYPE_OBJECT; - static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; - static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; - - static DeclareMemType MTYPE_DISPLAY; - static DeclareMemType MTYPE_DISPLAY_UPDATE; - static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; - static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; - static DeclareMemType MTYPE_DISPLAY_SWAP; - static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; - static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; - static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; - static DeclareMemType MTYPE_DISPLAY_STATE_SORT; - static DeclareMemType MTYPE_DISPLAY_SKY; - static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; - static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; - static DeclareMemType MTYPE_DISPLAY_RENDER_UI; - static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; - - static DeclareMemType MTYPE_VERTEX_DATA; - static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; - static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; - static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; - static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; - static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER; - static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; - static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; - static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; - static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; - static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; - static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; - static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; - static DeclareMemType MTYPE_VERTEX_SET_STRIDE; - static DeclareMemType MTYPE_VERTEX_SET_BUFFER; - static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; - static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; - - static DeclareMemType MTYPE_SPACE_PARTITION; - - static DeclareMemType MTYPE_PIPELINE; - static DeclareMemType MTYPE_PIPELINE_INIT; - static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; - static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; - static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; - static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; - static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; - static DeclareMemType MTYPE_PIPELINE_ADD_POOL; - static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; - static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; - static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; - static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; - static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; - static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; - static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; - static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; - static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; - static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; - static DeclareMemType MTYPE_PIPELINE_STATE_SORT; - static DeclareMemType MTYPE_PIPELINE_POST_SORT; - - static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; - static DeclareMemType MTYPE_PIPELINE_RENDER_HL; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; - static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; - static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; - static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; - static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; - static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; - static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; - static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; - - static DeclareMemType MTYPE_UPKEEP_POOLS; - - static DeclareMemType MTYPE_AVATAR; - static DeclareMemType MTYPE_AVATAR_MESH; - static DeclareMemType MTYPE_PARTICLES; - static DeclareMemType MTYPE_REGIONS; - - static DeclareMemType MTYPE_INVENTORY; - static DeclareMemType MTYPE_INVENTORY_DRAW; - static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; - static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; - static DeclareMemType MTYPE_INVENTORY_POST_BUILD; - static DeclareMemType MTYPE_INVENTORY_FROM_XML; - static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; - static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; - static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; - static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; - - static DeclareMemType MTYPE_ANIMATION; - static DeclareMemType MTYPE_VOLUME; - static DeclareMemType MTYPE_PRIMITIVE; - - static DeclareMemType MTYPE_SCRIPT; - static DeclareMemType MTYPE_SCRIPT_RUN; - static DeclareMemType MTYPE_SCRIPT_BYTECODE; - - static DeclareMemType MTYPE_IO_PUMP; - static DeclareMemType MTYPE_IO_TCP; - static DeclareMemType MTYPE_IO_BUFFER; - static DeclareMemType MTYPE_IO_HTTP_SERVER; - static DeclareMemType MTYPE_IO_SD_SERVER; - static DeclareMemType MTYPE_IO_SD_CLIENT; - static DeclareMemType MTYPE_IO_URL_REQUEST; - - static DeclareMemType MTYPE_DIRECTX_INIT; - - static DeclareMemType MTYPE_TEMP1; - static DeclareMemType MTYPE_TEMP2; - static DeclareMemType MTYPE_TEMP3; - static DeclareMemType MTYPE_TEMP4; - static DeclareMemType MTYPE_TEMP5; - static DeclareMemType MTYPE_TEMP6; - static DeclareMemType MTYPE_TEMP7; - static DeclareMemType MTYPE_TEMP8; - static DeclareMemType MTYPE_TEMP9; - - static DeclareMemType MTYPE_OTHER; // Special; used by display code - - S32 mTypeIndex; -}; - -//---------------------------------------------------------------------------- - -#endif - +/** + * @file llmemtype.h + * @brief Runtime memory usage debugging utilities. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + * + * Copyright (c) 2005-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_MEMTYPE_H +#define LL_MEMTYPE_H + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- + +#include "linden_common.h" +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// WARNING: Never commit with MEM_TRACK_MEM == 1 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define MEM_TRACK_MEM (0 && LL_WINDOWS) + +#include + +#define MEM_TYPE_NEW(T) + +class LL_COMMON_API LLMemType +{ +public: + + // class we'll initialize all instances of as + // static members of MemType. Then use + // to construct any new mem type. + class LL_COMMON_API DeclareMemType + { + public: + DeclareMemType(char const * st); + ~DeclareMemType(); + + S32 mID; + char const * mName; + + // array so we can map an index ID to Name + static std::vector mNameList; + }; + + LLMemType(DeclareMemType& dt); + ~LLMemType(); + + static char const * getNameFromID(S32 id); + + static DeclareMemType MTYPE_INIT; + static DeclareMemType MTYPE_STARTUP; + static DeclareMemType MTYPE_MAIN; + static DeclareMemType MTYPE_FRAME; + + static DeclareMemType MTYPE_GATHER_INPUT; + static DeclareMemType MTYPE_JOY_KEY; + + static DeclareMemType MTYPE_IDLE; + static DeclareMemType MTYPE_IDLE_PUMP; + static DeclareMemType MTYPE_IDLE_NETWORK; + static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; + static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; + static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; + static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; + static DeclareMemType MTYPE_IDLE_AUDIO; + + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; + + static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; + static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; + + static DeclareMemType MTYPE_RENDER; + static DeclareMemType MTYPE_SLEEP; + + static DeclareMemType MTYPE_NETWORK; + static DeclareMemType MTYPE_PHYSICS; + static DeclareMemType MTYPE_INTERESTLIST; + + static DeclareMemType MTYPE_IMAGEBASE; + static DeclareMemType MTYPE_IMAGERAW; + static DeclareMemType MTYPE_IMAGEFORMATTED; + + static DeclareMemType MTYPE_APPFMTIMAGE; + static DeclareMemType MTYPE_APPRAWIMAGE; + static DeclareMemType MTYPE_APPAUXRAWIMAGE; + + static DeclareMemType MTYPE_DRAWABLE; + + static DeclareMemType MTYPE_OBJECT; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; + + static DeclareMemType MTYPE_DISPLAY; + static DeclareMemType MTYPE_DISPLAY_UPDATE; + static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; + static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; + static DeclareMemType MTYPE_DISPLAY_SWAP; + static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; + static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; + static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; + static DeclareMemType MTYPE_DISPLAY_STATE_SORT; + static DeclareMemType MTYPE_DISPLAY_SKY; + static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; + static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; + static DeclareMemType MTYPE_DISPLAY_RENDER_UI; + static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; + + static DeclareMemType MTYPE_VERTEX_DATA; + static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; + static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; + static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; + static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; + static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER; + static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; + static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; + static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; + static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; + static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; + static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_SET_STRIDE; + static DeclareMemType MTYPE_VERTEX_SET_BUFFER; + static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; + static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; + + static DeclareMemType MTYPE_SPACE_PARTITION; + + static DeclareMemType MTYPE_PIPELINE; + static DeclareMemType MTYPE_PIPELINE_INIT; + static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; + static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; + static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; + static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; + static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; + static DeclareMemType MTYPE_PIPELINE_ADD_POOL; + static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; + static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; + static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; + static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; + static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; + static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; + static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; + static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; + static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; + static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; + static DeclareMemType MTYPE_PIPELINE_STATE_SORT; + static DeclareMemType MTYPE_PIPELINE_POST_SORT; + + static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; + static DeclareMemType MTYPE_PIPELINE_RENDER_HL; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; + static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; + static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; + static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; + static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; + static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; + + static DeclareMemType MTYPE_UPKEEP_POOLS; + + static DeclareMemType MTYPE_AVATAR; + static DeclareMemType MTYPE_AVATAR_MESH; + static DeclareMemType MTYPE_PARTICLES; + static DeclareMemType MTYPE_REGIONS; + + static DeclareMemType MTYPE_INVENTORY; + static DeclareMemType MTYPE_INVENTORY_DRAW; + static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; + static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; + static DeclareMemType MTYPE_INVENTORY_POST_BUILD; + static DeclareMemType MTYPE_INVENTORY_FROM_XML; + static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; + static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; + static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; + static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; + + static DeclareMemType MTYPE_ANIMATION; + static DeclareMemType MTYPE_VOLUME; + static DeclareMemType MTYPE_PRIMITIVE; + + static DeclareMemType MTYPE_SCRIPT; + static DeclareMemType MTYPE_SCRIPT_RUN; + static DeclareMemType MTYPE_SCRIPT_BYTECODE; + + static DeclareMemType MTYPE_IO_PUMP; + static DeclareMemType MTYPE_IO_TCP; + static DeclareMemType MTYPE_IO_BUFFER; + static DeclareMemType MTYPE_IO_HTTP_SERVER; + static DeclareMemType MTYPE_IO_SD_SERVER; + static DeclareMemType MTYPE_IO_SD_CLIENT; + static DeclareMemType MTYPE_IO_URL_REQUEST; + + static DeclareMemType MTYPE_DIRECTX_INIT; + + static DeclareMemType MTYPE_TEMP1; + static DeclareMemType MTYPE_TEMP2; + static DeclareMemType MTYPE_TEMP3; + static DeclareMemType MTYPE_TEMP4; + static DeclareMemType MTYPE_TEMP5; + static DeclareMemType MTYPE_TEMP6; + static DeclareMemType MTYPE_TEMP7; + static DeclareMemType MTYPE_TEMP8; + static DeclareMemType MTYPE_TEMP9; + + static DeclareMemType MTYPE_OTHER; // Special; used by display code + + S32 mTypeIndex; +}; + +//---------------------------------------------------------------------------- + +#endif + diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index dda9a95597..bb3301df9f 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -1,169 +1,169 @@ -/** - * @file llpreprocessor.h - * @brief This file should be included in all Linden Lab files and - * should only contain special preprocessor directives - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLPREPROCESSOR_H -#define LLPREPROCESSOR_H - -// Figure out endianness of platform -#ifdef LL_LINUX -#define __ENABLE_WSTRING -#include -#endif // LL_LINUX - -#if LL_SOLARIS -# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported. -# define LL_BIG_ENDIAN 1 -# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed -# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API -# endif -# include // ensure we know which end is up -#endif // LL_SOLARIS - -#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) -#define LL_LITTLE_ENDIAN 1 -#else -#define LL_BIG_ENDIAN 1 -#endif - -// Per-compiler switches -#ifdef __GNUC__ -#define LL_FORCE_INLINE inline __attribute__((always_inline)) -#else -#define LL_FORCE_INLINE __forceinline -#endif - -// Figure out differences between compilers -#if defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - #ifndef LL_GNUC - #define LL_GNUC 1 - #endif -#elif defined(__MSVC_VER__) || defined(_MSC_VER) - #ifndef LL_MSVC - #define LL_MSVC 1 - #endif - #if _MSC_VER < 1400 - #define LL_MSVC7 //Visual C++ 2003 or earlier - #endif -#endif - -// Deal with minor differences on Unixy OSes. -#if LL_DARWIN || LL_LINUX - // Different name, same functionality. - #define stricmp strcasecmp - #define strnicmp strncasecmp - - // Not sure why this is different, but... - #ifndef MAX_PATH - #define MAX_PATH PATH_MAX - #endif // not MAX_PATH - -#endif - - -// Static linking with apr on windows needs to be declared. -#if LL_WINDOWS && !LL_COMMON_LINK_SHARED -#ifndef APR_DECLARE_STATIC -#define APR_DECLARE_STATIC // For APR on Windows -#endif -#ifndef APU_DECLARE_STATIC -#define APU_DECLARE_STATIC // For APR util on Windows -#endif -#endif - -#if defined(LL_WINDOWS) -#define BOOST_REGEX_NO_LIB 1 -#define CURL_STATICLIB 1 -#ifndef XML_STATIC -#define XML_STATIC -#endif -#endif // LL_WINDOWS - - -// Deal with VC6 problems -#if LL_MSVC -#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. -#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. -#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. -//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. -#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function -#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" -#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden -#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored -#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file -#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. -#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( disable : 4996 ) // warning: deprecated - -// level 4 warnings that we need to disable: -#pragma warning (disable : 4100) // unreferenced formal parameter -#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) -#pragma warning (disable : 4244) // possible loss of data on conversions -#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template -#pragma warning (disable : 4512) // assignment operator could not be generated -#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) - -#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class -#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class -#endif // LL_MSVC - -#if LL_WINDOWS -#define LL_DLLEXPORT __declspec(dllexport) -#define LL_DLLIMPORT __declspec(dllimport) -#elif LL_LINUX -#define LL_DLLEXPORT __attribute__ ((visibility("default"))) -#define LL_DLLIMPORT -#else -#define LL_DLLEXPORT -#define LL_DLLIMPORT -#endif // LL_WINDOWS - -#if LL_COMMON_LINK_SHARED -// CMake automagically defines llcommon_EXPORTS only when building llcommon -// sources, and only when llcommon is a shared library (i.e. when -// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because -// otherwise we can't distinguish between (non-llcommon source) and (llcommon -// not shared). -# if defined(llcommon_EXPORTS) -# define LL_COMMON_API LL_DLLEXPORT -# else //llcommon_EXPORTS -# define LL_COMMON_API LL_DLLIMPORT -# endif //llcommon_EXPORTS -#else // LL_COMMON_LINK_SHARED -# define LL_COMMON_API -#endif // LL_COMMON_LINK_SHARED - -#endif // not LL_LINDEN_PREPROCESSOR_H +/** + * @file llpreprocessor.h + * @brief This file should be included in all Linden Lab files and + * should only contain special preprocessor directives + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLPREPROCESSOR_H +#define LLPREPROCESSOR_H + +// Figure out endianness of platform +#ifdef LL_LINUX +#define __ENABLE_WSTRING +#include +#endif // LL_LINUX + +#if LL_SOLARIS +# ifdef __sparc // Since we're talking Solaris 10 and up, only 64 bit is supported. +# define LL_BIG_ENDIAN 1 +# define LL_SOLARIS_ALIGNED_CPU 1 // used to designate issues where SPARC alignment is addressed +# define LL_SOLARIS_NON_MESA_GL 1 // The SPARC GL does not provide a MESA-based GL API +# endif +# include // ensure we know which end is up +#endif // LL_SOLARIS + +#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) +#define LL_LITTLE_ENDIAN 1 +#else +#define LL_BIG_ENDIAN 1 +#endif + +// Per-compiler switches +#ifdef __GNUC__ +#define LL_FORCE_INLINE inline __attribute__((always_inline)) +#else +#define LL_FORCE_INLINE __forceinline +#endif + +// Figure out differences between compilers +#if defined(__GNUC__) + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + #ifndef LL_GNUC + #define LL_GNUC 1 + #endif +#elif defined(__MSVC_VER__) || defined(_MSC_VER) + #ifndef LL_MSVC + #define LL_MSVC 1 + #endif + #if _MSC_VER < 1400 + #define LL_MSVC7 //Visual C++ 2003 or earlier + #endif +#endif + +// Deal with minor differences on Unixy OSes. +#if LL_DARWIN || LL_LINUX + // Different name, same functionality. + #define stricmp strcasecmp + #define strnicmp strncasecmp + + // Not sure why this is different, but... + #ifndef MAX_PATH + #define MAX_PATH PATH_MAX + #endif // not MAX_PATH + +#endif + + +// Static linking with apr on windows needs to be declared. +#if LL_WINDOWS && !LL_COMMON_LINK_SHARED +#ifndef APR_DECLARE_STATIC +#define APR_DECLARE_STATIC // For APR on Windows +#endif +#ifndef APU_DECLARE_STATIC +#define APU_DECLARE_STATIC // For APR util on Windows +#endif +#endif + +#if defined(LL_WINDOWS) +#define BOOST_REGEX_NO_LIB 1 +#define CURL_STATICLIB 1 +#ifndef XML_STATIC +#define XML_STATIC +#endif +#endif // LL_WINDOWS + + +// Deal with VC6 problems +#if LL_MSVC +#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. +#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. +#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. +//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" +#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored +#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file +#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. +#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 ) // warning: deprecated + +// level 4 warnings that we need to disable: +#pragma warning (disable : 4100) // unreferenced formal parameter +#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) +#pragma warning (disable : 4244) // possible loss of data on conversions +#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template +#pragma warning (disable : 4512) // assignment operator could not be generated +#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) + +#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class +#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class +#endif // LL_MSVC + +#if LL_WINDOWS +#define LL_DLLEXPORT __declspec(dllexport) +#define LL_DLLIMPORT __declspec(dllimport) +#elif LL_LINUX +#define LL_DLLEXPORT __attribute__ ((visibility("default"))) +#define LL_DLLIMPORT +#else +#define LL_DLLEXPORT +#define LL_DLLIMPORT +#endif // LL_WINDOWS + +#if LL_COMMON_LINK_SHARED +// CMake automagically defines llcommon_EXPORTS only when building llcommon +// sources, and only when llcommon is a shared library (i.e. when +// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because +// otherwise we can't distinguish between (non-llcommon source) and (llcommon +// not shared). +# if defined(llcommon_EXPORTS) +# define LL_COMMON_API LL_DLLEXPORT +# else //llcommon_EXPORTS +# define LL_COMMON_API LL_DLLIMPORT +# endif //llcommon_EXPORTS +#else // LL_COMMON_LINK_SHARED +# define LL_COMMON_API +#endif // LL_COMMON_LINK_SHARED + +#endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index 3cb074257b..6558df70a4 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -1,142 +1,142 @@ -/** - * @file llstacktrace.cpp - * @brief stack tracing functionality - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llstacktrace.h" - -#ifdef LL_WINDOWS - -#include -#include - -#include "windows.h" -#include "Dbghelp.h" - -typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( - IN ULONG frames_to_skip, - IN ULONG frames_to_capture, - OUT PVOID *backtrace, - OUT PULONG backtrace_hash); - -static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = - (RtlCaptureStackBackTrace_Function*) - GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); - -bool ll_get_stack_trace(std::vector& lines) -{ - const S32 MAX_STACK_DEPTH = 32; - const S32 STRING_NAME_LENGTH = 200; - const S32 FRAME_SKIP = 2; - static BOOL symbolsLoaded = false; - static BOOL firstCall = true; - - HANDLE hProc = GetCurrentProcess(); - - // load the symbols if they're not loaded - if(!symbolsLoaded && firstCall) - { - symbolsLoaded = SymInitialize(hProc, NULL, true); - firstCall = false; - } - - // if loaded, get the call stack - if(symbolsLoaded) - { - // create the frames to hold the addresses - void* frames[MAX_STACK_DEPTH]; - memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); - S32 depth = 0; - - // get the addresses - depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); - - IMAGEHLP_LINE64 line; - memset(&line, 0, sizeof(IMAGEHLP_LINE64)); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - // create something to hold address info - PIMAGEHLP_SYMBOL64 pSym; - pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - pSym->MaxNameLength = STRING_NAME_LENGTH; - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - // get address info for each address frame - // and store - for(S32 i=0; i < depth; i++) - { - std::stringstream stack_line; - BOOL ret; - - DWORD64 addr = (DWORD64)frames[i]; - ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); - if(ret) - { - stack_line << pSym->Name << " "; - } - - DWORD dummy; - ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); - if(ret) - { - std::string file_name = line.FileName; - std::string::size_type index = file_name.rfind("\\"); - stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; - } - - lines.push_back(stack_line.str()); - } - - free(pSym); - - // TODO: figure out a way to cleanup symbol loading - // Not hugely necessary, however. - //SymCleanup(hProc); - return true; - } - else - { - lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); - } - - return false; -} - -#else - -bool ll_get_stack_trace(std::vector& lines) -{ - return false; -} - -#endif - +/** + * @file llstacktrace.cpp + * @brief stack tracing functionality + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llstacktrace.h" + +#ifdef LL_WINDOWS + +#include +#include + +#include "windows.h" +#include "Dbghelp.h" + +typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( + IN ULONG frames_to_skip, + IN ULONG frames_to_capture, + OUT PVOID *backtrace, + OUT PULONG backtrace_hash); + +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = + (RtlCaptureStackBackTrace_Function*) + GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + +bool ll_get_stack_trace(std::vector& lines) +{ + const S32 MAX_STACK_DEPTH = 32; + const S32 STRING_NAME_LENGTH = 200; + const S32 FRAME_SKIP = 2; + static BOOL symbolsLoaded = false; + static BOOL firstCall = true; + + HANDLE hProc = GetCurrentProcess(); + + // load the symbols if they're not loaded + if(!symbolsLoaded && firstCall) + { + symbolsLoaded = SymInitialize(hProc, NULL, true); + firstCall = false; + } + + // if loaded, get the call stack + if(symbolsLoaded) + { + // create the frames to hold the addresses + void* frames[MAX_STACK_DEPTH]; + memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + S32 depth = 0; + + // get the addresses + depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + + IMAGEHLP_LINE64 line; + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + // create something to hold address info + PIMAGEHLP_SYMBOL64 pSym; + pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + pSym->MaxNameLength = STRING_NAME_LENGTH; + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + + // get address info for each address frame + // and store + for(S32 i=0; i < depth; i++) + { + std::stringstream stack_line; + BOOL ret; + + DWORD64 addr = (DWORD64)frames[i]; + ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); + if(ret) + { + stack_line << pSym->Name << " "; + } + + DWORD dummy; + ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); + if(ret) + { + std::string file_name = line.FileName; + std::string::size_type index = file_name.rfind("\\"); + stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; + } + + lines.push_back(stack_line.str()); + } + + free(pSym); + + // TODO: figure out a way to cleanup symbol loading + // Not hugely necessary, however. + //SymCleanup(hProc); + return true; + } + else + { + lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); + } + + return false; +} + +#else + +bool ll_get_stack_trace(std::vector& lines) +{ + return false; +} + +#endif + diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h index b84b1aa6ad..9f857f0fd3 100644 --- a/indra/llcommon/llstacktrace.h +++ b/indra/llcommon/llstacktrace.h @@ -1,44 +1,44 @@ -/** - * @file llstacktrace.h - * @brief stack trace functions - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - - -#ifndef LL_LLSTACKTRACE_H -#define LL_LLSTACKTRACE_H - -#include "stdtypes.h" -#include -#include - -LL_COMMON_API bool ll_get_stack_trace(std::vector& lines); - -#endif - +/** + * @file llstacktrace.h + * @brief stack trace functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_LLSTACKTRACE_H +#define LL_LLSTACKTRACE_H + +#include "stdtypes.h" +#include +#include + +LL_COMMON_API bool ll_get_stack_trace(std::vector& lines); + +#endif + diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index edbb007f61..31e70e0fe4 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,1300 +1,1300 @@ -/** - * @file llstring.h - * @brief String utility functions and std::string class. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTRING_H -#define LL_LLSTRING_H - -#include -#include -#include -#include -#include "llsd.h" -#include "llfasttimer.h" - -#if LL_LINUX || LL_SOLARIS -#include -#include -#endif - -#include - -#if LL_SOLARIS -// stricmp and strnicmp do not exist on Solaris: -#define stricmp strcasecmp -#define strnicmp strncasecmp -#endif - -const char LL_UNKNOWN_CHAR = '?'; - -#if LL_DARWIN || LL_LINUX || LL_SOLARIS -// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) -#include - -namespace std -{ -template<> -struct char_traits -{ - typedef U16 char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - typedef mbstate_t state_type; - - static void - assign(char_type& __c1, const char_type& __c2) - { __c1 = __c2; } - - static bool - eq(const char_type& __c1, const char_type& __c2) - { return __c1 == __c2; } - - static bool - lt(const char_type& __c1, const char_type& __c2) - { return __c1 < __c2; } - - static int - compare(const char_type* __s1, const char_type* __s2, size_t __n) - { return memcmp(__s1, __s2, __n * sizeof(char_type)); } - - static size_t - length(const char_type* __s) - { - const char_type *cur_char = __s; - while (*cur_char != 0) - { - ++cur_char; - } - return cur_char - __s; - } - - static const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) - { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ - - static char_type* - assign(char_type* __s, size_t __n, char_type __a) - { - // This isn't right. - //return static_cast(memset(__s, __a, __n * sizeof(char_type))); - - // I don't think there's a standard 'memset' for 16-bit values. - // Do this the old-fashioned way. - - size_t __i; - for(__i = 0; __i < __n; __i++) - { - __s[__i] = __a; - } - return __s; - } - - static char_type - to_char_type(const int_type& __c) - { return static_cast(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast(EOF); } - - static int_type - not_eof(const int_type& __c) - { return (__c == eof()) ? 0 : __c; } - }; -}; -#endif - -class LL_COMMON_API LLStringOps -{ -private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; - static std::map datetimeToCodes; - -public: - static char toUpper(char elem) { return toupper((unsigned char)elem); } - static llwchar toUpper(llwchar elem) { return towupper(elem); } - - static char toLower(char elem) { return tolower((unsigned char)elem); } - static llwchar toLower(llwchar elem) { return towlower(elem); } - - static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - - static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } - static bool isPunct(llwchar a) { return iswpunct(a) != 0; } - - static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } - static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - - static S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); - - static void setupDatetimeInfo(bool pacific_daylight_time); - static long getPacificTimeOffset(void) { return sPacificTimeOffset;} - static long getLocalTimeOffset(void) { return sLocalTimeOffset;} - // Is the Pacific time zone (aka server time zone) - // currently in daylight savings time? - static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - - static std::string getDatetimeCode (std::string key); -}; - -/** - * @brief Return a string constructed from in without crashing if the - * pointer is NULL. - */ -LL_COMMON_API std::string ll_safe_string(const char* in); -LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); - - -// Allowing assignments from non-strings into format_map_t is apparently -// *really* error-prone, so subclass std::string with just basic c'tors. -class LLFormatMapString -{ -public: - LLFormatMapString() {}; - LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; - LLFormatMapString(const std::string& s) : mString(s) {}; - operator std::string() const { return mString; } - bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } - std::size_t length() const { return mString.length(); } - -private: - std::string mString; -}; - -template -class LLStringUtilBase -{ -private: - static std::string sLocale; - -public: - typedef typename std::basic_string::size_type size_type; - -public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static std::basic_string null; - - typedef std::map format_map_t; - LL_COMMON_API static void getTokens(const std::basic_string& instr, std::vector >& tokens, const std::basic_string& delims); - LL_COMMON_API static void formatNumber(std::basic_string& numStr, std::basic_string decimals); - LL_COMMON_API static bool formatDatetime(std::basic_string& replacement, std::basic_string token, std::basic_string param, S32 secFromEpoch); - LL_COMMON_API static S32 format(std::basic_string& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(std::basic_string& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const LLSD& substitutions); - static void setLocale (std::string inLocale) {sLocale = inLocale;}; - static std::string getLocale (void) {return sLocale;}; - - static bool isValidIndex(const std::basic_string& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static void trimHead(std::basic_string& string); - static void trimTail(std::basic_string& string); - static void trim(std::basic_string& string) { trimHead(string); trimTail(string); } - static void truncate(std::basic_string& string, size_type count); - - static void toUpper(std::basic_string& string); - static void toLower(std::basic_string& string); - - // True if this is the head of s. - static BOOL isHead( const std::basic_string& string, const T* s ); - - /** - * @brief Returns true if string starts with substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool startsWith( - const std::basic_string& string, - const std::basic_string& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const std::basic_string& string, - const std::basic_string& substr); - - static void addCRLF(std::basic_string& string); - static void removeCRLF(std::basic_string& string); - - static void replaceTabsWithSpaces( std::basic_string& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( std::basic_string& string, T replacement ); - static void replaceChar( std::basic_string& string, T target, T replacement ); - static void replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ); - - static BOOL containsNonprintable(const std::basic_string& string); - static void stripNonprintable(std::basic_string& string); - - /** - * @brief Unsafe way to make ascii characters. You should probably - * only call this when interacting with the host operating system. - * The 1 byte std::string does not work correctly. - * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII - * should work. - */ - static void _makeASCII(std::basic_string& string); - - // Conversion to other data types - static BOOL convertToBOOL(const std::basic_string& string, BOOL& value); - static BOOL convertToU8(const std::basic_string& string, U8& value); - static BOOL convertToS8(const std::basic_string& string, S8& value); - static BOOL convertToS16(const std::basic_string& string, S16& value); - static BOOL convertToU16(const std::basic_string& string, U16& value); - static BOOL convertToU32(const std::basic_string& string, U32& value); - static BOOL convertToS32(const std::basic_string& string, S32& value); - static BOOL convertToF32(const std::basic_string& string, F32& value); - static BOOL convertToF64(const std::basic_string& string, F64& value); - - ///////////////////////////////////////////////////////////////////////////////////////// - // Utility functions for working with char*'s and strings - - // Like strcmp but also handles empty strings. Uses - // current locale. - static S32 compareStrings(const T* lhs, const T* rhs); - static S32 compareStrings(const std::basic_string& lhs, const std::basic_string& rhs); - - // case insensitive version of above. Uses current locale on - // Win32, and falls back to a non-locale aware comparison on - // Linux. - static S32 compareInsensitive(const T* lhs, const T* rhs); - static S32 compareInsensitive(const std::basic_string& lhs, const std::basic_string& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const std::basic_string& a, const std::basic_string& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const std::basic_string& a, const std::basic_string& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const std::basic_string& a, const std::basic_string& b ); - - // A replacement for strncpy. - // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds - // up to dst_size-1 characters of src. - static void copy(T* dst, const T* src, size_type dst_size); - - // Copies src into dst at a given offset. - static void copyInto(std::basic_string& dst, const std::basic_string& src, size_type offset); - - static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } - - -#ifdef _DEBUG - LL_COMMON_API static void testHarness(); -#endif - -private: - LL_COMMON_API static size_type getSubstitution(const std::basic_string& instr, size_type& start, std::vector >& tokens); -}; - -template std::basic_string LLStringUtilBase::null; -template std::string LLStringUtilBase::sLocale; - -typedef LLStringUtilBase LLStringUtil; -typedef LLStringUtilBase LLWStringUtil; -typedef std::basic_string LLWString; - -//@ Use this where we want to disallow input in the form of "foo" -// This is used to catch places where english text is embedded in the code -// instead of in a translatable XUI file. -class LLStringExplicit : public std::string -{ -public: - explicit LLStringExplicit(const char* s) : std::string(s) {} - LLStringExplicit(const std::string& s) : std::string(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} -}; - -struct LLDictionaryLess -{ -public: - bool operator()(const std::string& a, const std::string& b) - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } -}; - - -/** - * Simple support functions - */ - -/** - * @brief chop off the trailing characters in a string. - * - * This function works on bytes rather than glyphs, so this will - * incorrectly truncate non-single byte strings. - * Use utf8str_truncate() for utf8 strings - * @return a copy of in string minus the trailing count bytes. - */ -inline std::string chop_tail_copy( - const std::string& in, - std::string::size_type count) -{ - return std::string(in, 0, in.length() - count); -} - -/** - * @brief This translates a nybble stored as a hex value from 0-f back - * to a nybble in the low order bits of the return byte. - */ -LL_COMMON_API U8 hex_as_nybble(char hex); - -/** - * @brief read the contents of a file into a string. - * - * Since this function has no concept of character encoding, most - * anything you do with this method ill-advised. Please avoid. - * @param str [out] The string which will have. - * @param filename The full name of the file to read. - * @return Returns true on success. If false, str is unmodified. - */ -LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); -LL_COMMON_API bool iswindividual(llwchar elem); - -/** - * Unicode support - */ - -// Make the incoming string a utf8 string. Replaces any unknown glyph -// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest -// of the data may not be recovered. -LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); - -// -// We should never use UTF16 except when communicating with Win32! -// -typedef std::basic_string llutf16string; - -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); - -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); - -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); - -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); -// Same function, better name. JC -inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } - -// -LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); - -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); - -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); - -// Length of this UTF32 string in bytes when transformed to UTF8 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); - -// Length in bytes of this wide char in a UTF8 string -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); - -LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str); - -// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. -LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); - -// Length in utf16string (UTF-16) of wlen wchars beginning at woffset. -LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); - -// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) -LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); - -/** - * @brief Properly truncate a utf8 string to a maximum byte count. - * - * The returned string may be less than max_len if the truncation - * happens in the middle of a glyph. If max_len is longer than the - * string passed in, the return value == utf8str. - * @param utf8str A valid utf8 string to truncate. - * @param max_len The maximum number of bytes in the return value. - * @return Returns a valid utf8 string with byte count <= max_len. - */ -LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); - -LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); - -LL_COMMON_API S32 utf8str_compare_insensitive( - const std::string& lhs, - const std::string& rhs); - -/** - * @brief Replace all occurences of target_char with replace_char - * - * @param utf8str A utf8 string to process. - * @param target_char The wchar to be replaced - * @param replace_char The wchar which is written on replace - */ -LL_COMMON_API std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char); - -LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); - -// Hack - used for evil notecards. -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); - -LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); - - -#if LL_WINDOWS -/* @name Windows string helpers - */ -//@{ - -/** - * @brief Implementation the expected snprintf interface. - * - * If the size of the passed in buffer is not large enough to hold the string, - * two bad things happen: - * 1. resulting formatted string is NOT null terminated - * 2. Depending on the platform, the return value could be a) the required - * size of the buffer to copy the entire formatted string or b) -1. - * On Windows with VS.Net 2003, it returns -1 e.g. - * - * safe_snprintf always adds a NULL terminator so that the caller does not - * need to check for return value or need to add the NULL terminator. - * It does not, however change the return value - to let the caller know - * that the passed in buffer size was not large enough to hold the - * formatted string. - * - */ - -// Deal with the differeneces on Windows -namespace snprintf_hack -{ - LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); -} - -using snprintf_hack::snprintf; - -/** - * @brief Convert a wide string to std::string - * - * This replaces the unsafe W2A macro from ATL. - */ -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); - -//@} -#endif // LL_WINDOWS - -/** - * Many of the 'strip' and 'replace' methods of LLStringUtilBase need - * specialization to work with the signed char type. - * Sadly, it is not possible (AFAIK) to specialize a single method of - * a template class. - * That stuff should go here. - */ -namespace LLStringFn -{ - /** - * @brief Replace all non-printable characters with replacement in - * string. - * NOTE - this will zap non-ascii - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_in_ascii( - std::basic_string& string, - char replacement); - - - /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a string. - * NOTE - this will zap non-ascii - * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, - char replacement); - - - /** - * @brief Remove all characters that are not allowed in XML 1.0. - * Returns a copy of the string with those characters removed. - * Works with US ASCII and UTF-8 encoded strings. JC - */ - LL_COMMON_API std::string strip_invalid_xml(const std::string& input); - - - /** - * @brief Replace all control characters (0 <= c < 0x20) with replacement in - * string. This is safe for utf-8 - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_ascii_controlchars( - std::basic_string& string, - char replacement); -} - -//////////////////////////////////////////////////////////// -// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. -// There is no LLWStringUtil::format implementation currently. -// Calling thse for anything other than LLStringUtil will produce link errors. - -//////////////////////////////////////////////////////////// - - -// static -template -S32 LLStringUtilBase::compareStrings(const T* lhs, const T* rhs) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0]) - { - result = -1; - } - else - { - result = LLStringOps::collate(lhs, rhs); - } - return result; -} - -//static -template -S32 LLStringUtilBase::compareStrings(const std::basic_string& lhs, const std::basic_string& rhs) -{ - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); -} - -// static -template -S32 LLStringUtilBase::compareInsensitive(const T* lhs, const T* rhs ) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0] ) - { - result = -1; - } - else - { - std::basic_string lhs_string(lhs); - std::basic_string rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; -} - -//static -template -S32 LLStringUtilBase::compareInsensitive(const std::basic_string& lhs, const std::basic_string& rhs) -{ - std::basic_string lhs_string(lhs); - std::basic_string rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); -} - -// Case sensitive comparison with good handling of numbers. Does not use current locale. -// a.k.a. strdictcmp() - -//static -template -S32 LLStringUtilBase::compareDict(const std::basic_string& astr, const std::basic_string& bstr) -{ - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - S32 bias = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( bias==0 ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } - }else{ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai -S32 LLStringUtilBase::compareDictInsensitive(const std::basic_string& astr, const std::basic_string& bstr) -{ - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai -BOOL LLStringUtilBase::precedesDict( const std::basic_string& a, const std::basic_string& b ) -{ - if( a.size() && b.size() ) - { - return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } -} - -//static -template -void LLStringUtilBase::toUpper(std::basic_string& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } -} - -//static -template -void LLStringUtilBase::toLower(std::basic_string& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } -} - -//static -template -void LLStringUtilBase::trimHead(std::basic_string& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } -} - -//static -template -void LLStringUtilBase::trimTail(std::basic_string& string) -{ - if( string.size() ) - { - size_type len = string.length(); - size_type i = len; - while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) - { - i--; - } - - string.erase( i, len - i ); - } -} - - -// Replace line feeds with carriage return-line feed pairs. -//static -template -void LLStringUtilBase::addCRLF(std::basic_string& string) -{ - const T LF = 10; - const T CR = 13; - - // Count the number of line feeds - size_type count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len; i++ ) - { - if( string[i] == LF ) - { - count++; - } - } - - // Insert a carriage return before each line feed - if( count ) - { - size_type size = len + count; - T *t = new T[size]; - size_type j = 0; - for( i = 0; i < len; ++i ) - { - if( string[i] == LF ) - { - t[j] = CR; - ++j; - } - t[j] = string[i]; - ++j; - } - - string.assign(t, size); - } -} - -// Remove all carriage returns -//static -template -void LLStringUtilBase::removeCRLF(std::basic_string& string) -{ - const T CR = 13; - - size_type cr_count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len - cr_count; i++ ) - { - if( string[i+cr_count] == CR ) - { - cr_count++; - } - - string[i] = string[i+cr_count]; - } - string.erase(i, cr_count); -} - -//static -template -void LLStringUtilBase::replaceChar( std::basic_string& string, T target, T replacement ) -{ - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } -} - -//static -template -void LLStringUtilBase::replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ) -{ - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } -} - -//static -template -void LLStringUtilBase::replaceNonstandardASCII( std::basic_string& string, T replacement ) -{ - const char LF = 10; - const S8 MIN = 32; -// const S8 MAX = 127; - - size_type len = string.size(); - for( size_type i = 0; i < len; i++ ) - { - // No need to test MAX < mText[i] because we treat mText[i] as a signed char, - // which has a max value of 127. - if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) - { - string[i] = replacement; - } - } -} - -//static -template -void LLStringUtilBase::replaceTabsWithSpaces( std::basic_string& str, size_type spaces_per_tab ) -{ - const T TAB = '\t'; - const T SPACE = ' '; - - std::basic_string out_str; - // Replace tabs with spaces - for (size_type i = 0; i < str.length(); i++) - { - if (str[i] == TAB) - { - for (size_type j = 0; j < spaces_per_tab; j++) - out_str += SPACE; - } - else - { - out_str += str[i]; - } - } - str = out_str; -} - -//static -template -BOOL LLStringUtilBase::containsNonprintable(const std::basic_string& string) -{ - const char MIN = 32; - BOOL rv = FALSE; - for (size_type i = 0; i < string.size(); i++) - { - if(string[i] < MIN) - { - rv = TRUE; - break; - } - } - return rv; -} - -//static -template -void LLStringUtilBase::stripNonprintable(std::basic_string& string) -{ - const char MIN = 32; - size_type j = 0; - if (string.empty()) - { - return; - } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; - for (size_type i = 0; i < src_size; i++) - { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) - { - *write_head = *read_head; - ++j; - } - } - c_string[j]= '\0'; - string = c_string; - delete []c_string; -} - -template -void LLStringUtilBase::_makeASCII(std::basic_string& string) -{ - // Replace non-ASCII chars with LL_UNKNOWN_CHAR - for (size_type i = 0; i < string.length(); i++) - { - if (string[i] > 0x7f) - { - string[i] = LL_UNKNOWN_CHAR; - } - } -} - -// static -template -void LLStringUtilBase::copy( T* dst, const T* src, size_type dst_size ) -{ - if( dst_size > 0 ) - { - size_type min_len = 0; - if( src ) - { - min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ - memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ - } - dst[min_len] = '\0'; - } -} - -// static -template -void LLStringUtilBase::copyInto(std::basic_string& dst, const std::basic_string& src, size_type offset) -{ - if ( offset == dst.length() ) - { - // special case - append to end of string and avoid expensive - // (when strings are large) string manipulations - dst += src; - } - else - { - std::basic_string tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; -} - -// True if this is the head of s. -//static -template -BOOL LLStringUtilBase::isHead( const std::basic_string& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } -} - -// static -template -bool LLStringUtilBase::startsWith( - const std::basic_string& string, - const std::basic_string& substr) -{ - if(string.empty() || (substr.empty())) return false; - if(0 == string.find(substr)) return true; - return false; -} - -// static -template -bool LLStringUtilBase::endsWith( - const std::basic_string& string, - const std::basic_string& substr) -{ - if(string.empty() || (substr.empty())) return false; - std::string::size_type idx = string.rfind(substr); - if(std::string::npos == idx) return false; - return (idx == (string.size() - substr.size())); -} - - -template -BOOL LLStringUtilBase::convertToBOOL(const std::basic_string& string, BOOL& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string temp( string ); - trim(temp); - if( - (temp == "1") || - (temp == "T") || - (temp == "t") || - (temp == "TRUE") || - (temp == "true") || - (temp == "True") ) - { - value = TRUE; - return TRUE; - } - else - if( - (temp == "0") || - (temp == "F") || - (temp == "f") || - (temp == "FALSE") || - (temp == "false") || - (temp == "False") ) - { - value = FALSE; - return TRUE; - } - - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToU8(const std::basic_string& string, U8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) - { - value = (U8) value32; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToS8(const std::basic_string& string, S8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) - { - value = (S8) value32; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToS16(const std::basic_string& string, S16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) - { - value = (S16) value32; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToU16(const std::basic_string& string, U16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) - { - value = (U16) value32; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToU32(const std::basic_string& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string temp( string ); - trim(temp); - U32 v; - std::basic_istringstream i_stream((std::basic_string)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToS32(const std::basic_string& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string temp( string ); - trim(temp); - S32 v; - std::basic_istringstream i_stream((std::basic_string)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if((LONG_MAX == v) || (LONG_MIN == v)) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToF32(const std::basic_string& string, F32& value) -{ - F64 value64 = 0.0; - BOOL success = convertToF64(string, value64); - if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) - { - value = (F32) value64; - return TRUE; - } - return FALSE; -} - -template -BOOL LLStringUtilBase::convertToF64(const std::basic_string& string, F64& value) -{ - if( string.empty() ) - { - return FALSE; - } - - std::basic_string temp( string ); - trim(temp); - F64 v; - std::basic_istringstream i_stream((std::basic_string)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; -} - -template -void LLStringUtilBase::truncate(std::basic_string& string, size_type count) -{ - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); -} - -#endif // LL_STRING_H +/** + * @file llstring.h + * @brief String utility functions and std::string class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSTRING_H +#define LL_LLSTRING_H + +#include +#include +#include +#include +#include "llsd.h" +#include "llfasttimer.h" + +#if LL_LINUX || LL_SOLARIS +#include +#include +#endif + +#include + +#if LL_SOLARIS +// stricmp and strnicmp do not exist on Solaris: +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif + +const char LL_UNKNOWN_CHAR = '?'; + +#if LL_DARWIN || LL_LINUX || LL_SOLARIS +// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) +#include + +namespace std +{ +template<> +struct char_traits +{ + typedef U16 char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef mbstate_t state_type; + + static void + assign(char_type& __c1, const char_type& __c2) + { __c1 = __c2; } + + static bool + eq(const char_type& __c1, const char_type& __c2) + { return __c1 == __c2; } + + static bool + lt(const char_type& __c1, const char_type& __c2) + { return __c1 < __c2; } + + static int + compare(const char_type* __s1, const char_type* __s2, size_t __n) + { return memcmp(__s1, __s2, __n * sizeof(char_type)); } + + static size_t + length(const char_type* __s) + { + const char_type *cur_char = __s; + while (*cur_char != 0) + { + ++cur_char; + } + return cur_char - __s; + } + + static const char_type* + find(const char_type* __s, size_t __n, const char_type& __a) + { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ + + static char_type* + assign(char_type* __s, size_t __n, char_type __a) + { + // This isn't right. + //return static_cast(memset(__s, __a, __n * sizeof(char_type))); + + // I don't think there's a standard 'memset' for 16-bit values. + // Do this the old-fashioned way. + + size_t __i; + for(__i = 0; __i < __n; __i++) + { + __s[__i] = __a; + } + return __s; + } + + static char_type + to_char_type(const int_type& __c) + { return static_cast(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast(EOF); } + + static int_type + not_eof(const int_type& __c) + { return (__c == eof()) ? 0 : __c; } + }; +}; +#endif + +class LL_COMMON_API LLStringOps +{ +private: + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; + static std::map datetimeToCodes; + +public: + static char toUpper(char elem) { return toupper((unsigned char)elem); } + static llwchar toUpper(llwchar elem) { return towupper(elem); } + + static char toLower(char elem) { return tolower((unsigned char)elem); } + static llwchar toLower(llwchar elem) { return towlower(elem); } + + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); + + static void setupDatetimeInfo(bool pacific_daylight_time); + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} + + static std::string getDatetimeCode (std::string key); +}; + +/** + * @brief Return a string constructed from in without crashing if the + * pointer is NULL. + */ +LL_COMMON_API std::string ll_safe_string(const char* in); +LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); + + +// Allowing assignments from non-strings into format_map_t is apparently +// *really* error-prone, so subclass std::string with just basic c'tors. +class LLFormatMapString +{ +public: + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } + +private: + std::string mString; +}; + +template +class LLStringUtilBase +{ +private: + static std::string sLocale; + +public: + typedef typename std::basic_string::size_type size_type; + +public: + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static std::basic_string null; + + typedef std::map format_map_t; + LL_COMMON_API static void getTokens(const std::basic_string& instr, std::vector >& tokens, const std::basic_string& delims); + LL_COMMON_API static void formatNumber(std::basic_string& numStr, std::basic_string decimals); + LL_COMMON_API static bool formatDatetime(std::basic_string& replacement, std::basic_string token, std::basic_string param, S32 secFromEpoch); + LL_COMMON_API static S32 format(std::basic_string& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(std::basic_string& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const LLSD& substitutions); + static void setLocale (std::string inLocale) {sLocale = inLocale;}; + static std::string getLocale (void) {return sLocale;}; + + static bool isValidIndex(const std::basic_string& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static void trimHead(std::basic_string& string); + static void trimTail(std::basic_string& string); + static void trim(std::basic_string& string) { trimHead(string); trimTail(string); } + static void truncate(std::basic_string& string, size_type count); + + static void toUpper(std::basic_string& string); + static void toLower(std::basic_string& string); + + // True if this is the head of s. + static BOOL isHead( const std::basic_string& string, const T* s ); + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const std::basic_string& string, + const std::basic_string& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const std::basic_string& string, + const std::basic_string& substr); + + static void addCRLF(std::basic_string& string); + static void removeCRLF(std::basic_string& string); + + static void replaceTabsWithSpaces( std::basic_string& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( std::basic_string& string, T replacement ); + static void replaceChar( std::basic_string& string, T target, T replacement ); + static void replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ); + + static BOOL containsNonprintable(const std::basic_string& string); + static void stripNonprintable(std::basic_string& string); + + /** + * @brief Unsafe way to make ascii characters. You should probably + * only call this when interacting with the host operating system. + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII + * should work. + */ + static void _makeASCII(std::basic_string& string); + + // Conversion to other data types + static BOOL convertToBOOL(const std::basic_string& string, BOOL& value); + static BOOL convertToU8(const std::basic_string& string, U8& value); + static BOOL convertToS8(const std::basic_string& string, S8& value); + static BOOL convertToS16(const std::basic_string& string, S16& value); + static BOOL convertToU16(const std::basic_string& string, U16& value); + static BOOL convertToU32(const std::basic_string& string, U32& value); + static BOOL convertToS32(const std::basic_string& string, S32& value); + static BOOL convertToF32(const std::basic_string& string, F32& value); + static BOOL convertToF64(const std::basic_string& string, F64& value); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Utility functions for working with char*'s and strings + + // Like strcmp but also handles empty strings. Uses + // current locale. + static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const std::basic_string& lhs, const std::basic_string& rhs); + + // case insensitive version of above. Uses current locale on + // Win32, and falls back to a non-locale aware comparison on + // Linux. + static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const std::basic_string& lhs, const std::basic_string& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const std::basic_string& a, const std::basic_string& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const std::basic_string& a, const std::basic_string& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const std::basic_string& a, const std::basic_string& b ); + + // A replacement for strncpy. + // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds + // up to dst_size-1 characters of src. + static void copy(T* dst, const T* src, size_type dst_size); + + // Copies src into dst at a given offset. + static void copyInto(std::basic_string& dst, const std::basic_string& src, size_type offset); + + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG + LL_COMMON_API static void testHarness(); +#endif + +private: + LL_COMMON_API static size_type getSubstitution(const std::basic_string& instr, size_type& start, std::vector >& tokens); +}; + +template std::basic_string LLStringUtilBase::null; +template std::string LLStringUtilBase::sLocale; + +typedef LLStringUtilBase LLStringUtil; +typedef LLStringUtilBase LLWStringUtil; +typedef std::basic_string LLWString; + +//@ Use this where we want to disallow input in the form of "foo" +// This is used to catch places where english text is embedded in the code +// instead of in a translatable XUI file. +class LLStringExplicit : public std::string +{ +public: + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} +}; + +struct LLDictionaryLess +{ +public: + bool operator()(const std::string& a, const std::string& b) + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } +}; + + +/** + * Simple support functions + */ + +/** + * @brief chop off the trailing characters in a string. + * + * This function works on bytes rather than glyphs, so this will + * incorrectly truncate non-single byte strings. + * Use utf8str_truncate() for utf8 strings + * @return a copy of in string minus the trailing count bytes. + */ +inline std::string chop_tail_copy( + const std::string& in, + std::string::size_type count) +{ + return std::string(in, 0, in.length() - count); +} + +/** + * @brief This translates a nybble stored as a hex value from 0-f back + * to a nybble in the low order bits of the return byte. + */ +LL_COMMON_API U8 hex_as_nybble(char hex); + +/** + * @brief read the contents of a file into a string. + * + * Since this function has no concept of character encoding, most + * anything you do with this method ill-advised. Please avoid. + * @param str [out] The string which will have. + * @param filename The full name of the file to read. + * @return Returns true on success. If false, str is unmodified. + */ +LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); +LL_COMMON_API bool iswindividual(llwchar elem); + +/** + * Unicode support + */ + +// Make the incoming string a utf8 string. Replaces any unknown glyph +// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest +// of the data may not be recovered. +LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); + +// +// We should never use UTF16 except when communicating with Win32! +// +typedef std::basic_string llutf16string; + +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); + +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); + +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); + +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); +// Same function, better name. JC +inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } + +// +LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); + +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); + +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); + +// Length of this UTF32 string in bytes when transformed to UTF8 +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); + +// Length in bytes of this wide char in a UTF8 string +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); + +LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str); + +// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. +LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); + +// Length in utf16string (UTF-16) of wlen wchars beginning at woffset. +LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); + +// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); + +/** + * @brief Properly truncate a utf8 string to a maximum byte count. + * + * The returned string may be less than max_len if the truncation + * happens in the middle of a glyph. If max_len is longer than the + * string passed in, the return value == utf8str. + * @param utf8str A valid utf8 string to truncate. + * @param max_len The maximum number of bytes in the return value. + * @return Returns a valid utf8 string with byte count <= max_len. + */ +LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); + +LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); + +LL_COMMON_API S32 utf8str_compare_insensitive( + const std::string& lhs, + const std::string& rhs); + +/** + * @brief Replace all occurences of target_char with replace_char + * + * @param utf8str A utf8 string to process. + * @param target_char The wchar to be replaced + * @param replace_char The wchar which is written on replace + */ +LL_COMMON_API std::string utf8str_substChar( + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char); + +LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); + +// Hack - used for evil notecards. +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); + +LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); + + +#if LL_WINDOWS +/* @name Windows string helpers + */ +//@{ + +/** + * @brief Implementation the expected snprintf interface. + * + * If the size of the passed in buffer is not large enough to hold the string, + * two bad things happen: + * 1. resulting formatted string is NOT null terminated + * 2. Depending on the platform, the return value could be a) the required + * size of the buffer to copy the entire formatted string or b) -1. + * On Windows with VS.Net 2003, it returns -1 e.g. + * + * safe_snprintf always adds a NULL terminator so that the caller does not + * need to check for return value or need to add the NULL terminator. + * It does not, however change the return value - to let the caller know + * that the passed in buffer size was not large enough to hold the + * formatted string. + * + */ + +// Deal with the differeneces on Windows +namespace snprintf_hack +{ + LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); +} + +using snprintf_hack::snprintf; + +/** + * @brief Convert a wide string to std::string + * + * This replaces the unsafe W2A macro from ATL. + */ +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); + +//@} +#endif // LL_WINDOWS + +/** + * Many of the 'strip' and 'replace' methods of LLStringUtilBase need + * specialization to work with the signed char type. + * Sadly, it is not possible (AFAIK) to specialize a single method of + * a template class. + * That stuff should go here. + */ +namespace LLStringFn +{ + /** + * @brief Replace all non-printable characters with replacement in + * string. + * NOTE - this will zap non-ascii + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_in_ascii( + std::basic_string& string, + char replacement); + + + /** + * @brief Replace all non-printable characters and pipe characters + * with replacement in a string. + * NOTE - this will zap non-ascii + * + * @param [in,out] the string to modify. out value is the string + * with zero non-printable characters and zero pipe characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, + char replacement); + + + /** + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string& string, + char replacement); +} + +//////////////////////////////////////////////////////////// +// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. +// There is no LLWStringUtil::format implementation currently. +// Calling thse for anything other than LLStringUtil will produce link errors. + +//////////////////////////////////////////////////////////// + + +// static +template +S32 LLStringUtilBase::compareStrings(const T* lhs, const T* rhs) +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0]) + { + result = -1; + } + else + { + result = LLStringOps::collate(lhs, rhs); + } + return result; +} + +//static +template +S32 LLStringUtilBase::compareStrings(const std::basic_string& lhs, const std::basic_string& rhs) +{ + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); +} + +// static +template +S32 LLStringUtilBase::compareInsensitive(const T* lhs, const T* rhs ) +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0] ) + { + result = -1; + } + else + { + std::basic_string lhs_string(lhs); + std::basic_string rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; +} + +//static +template +S32 LLStringUtilBase::compareInsensitive(const std::basic_string& lhs, const std::basic_string& rhs) +{ + std::basic_string lhs_string(lhs); + std::basic_string rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); +} + +// Case sensitive comparison with good handling of numbers. Does not use current locale. +// a.k.a. strdictcmp() + +//static +template +S32 LLStringUtilBase::compareDict(const std::basic_string& astr, const std::basic_string& bstr) +{ + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + S32 bias = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( bias==0 ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } + }else{ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai +S32 LLStringUtilBase::compareDictInsensitive(const std::basic_string& astr, const std::basic_string& bstr) +{ + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai +BOOL LLStringUtilBase::precedesDict( const std::basic_string& a, const std::basic_string& b ) +{ + if( a.size() && b.size() ) + { + return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } +} + +//static +template +void LLStringUtilBase::toUpper(std::basic_string& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } +} + +//static +template +void LLStringUtilBase::toLower(std::basic_string& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } +} + +//static +template +void LLStringUtilBase::trimHead(std::basic_string& string) +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } +} + +//static +template +void LLStringUtilBase::trimTail(std::basic_string& string) +{ + if( string.size() ) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) + { + i--; + } + + string.erase( i, len - i ); + } +} + + +// Replace line feeds with carriage return-line feed pairs. +//static +template +void LLStringUtilBase::addCRLF(std::basic_string& string) +{ + const T LF = 10; + const T CR = 13; + + // Count the number of line feeds + size_type count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len; i++ ) + { + if( string[i] == LF ) + { + count++; + } + } + + // Insert a carriage return before each line feed + if( count ) + { + size_type size = len + count; + T *t = new T[size]; + size_type j = 0; + for( i = 0; i < len; ++i ) + { + if( string[i] == LF ) + { + t[j] = CR; + ++j; + } + t[j] = string[i]; + ++j; + } + + string.assign(t, size); + } +} + +// Remove all carriage returns +//static +template +void LLStringUtilBase::removeCRLF(std::basic_string& string) +{ + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count; i++ ) + { + if( string[i+cr_count] == CR ) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); +} + +//static +template +void LLStringUtilBase::replaceChar( std::basic_string& string, T target, T replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } +} + +//static +template +void LLStringUtilBase::replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } +} + +//static +template +void LLStringUtilBase::replaceNonstandardASCII( std::basic_string& string, T replacement ) +{ + const char LF = 10; + const S8 MIN = 32; +// const S8 MAX = 127; + + size_type len = string.size(); + for( size_type i = 0; i < len; i++ ) + { + // No need to test MAX < mText[i] because we treat mText[i] as a signed char, + // which has a max value of 127. + if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) + { + string[i] = replacement; + } + } +} + +//static +template +void LLStringUtilBase::replaceTabsWithSpaces( std::basic_string& str, size_type spaces_per_tab ) +{ + const T TAB = '\t'; + const T SPACE = ' '; + + std::basic_string out_str; + // Replace tabs with spaces + for (size_type i = 0; i < str.length(); i++) + { + if (str[i] == TAB) + { + for (size_type j = 0; j < spaces_per_tab; j++) + out_str += SPACE; + } + else + { + out_str += str[i]; + } + } + str = out_str; +} + +//static +template +BOOL LLStringUtilBase::containsNonprintable(const std::basic_string& string) +{ + const char MIN = 32; + BOOL rv = FALSE; + for (size_type i = 0; i < string.size(); i++) + { + if(string[i] < MIN) + { + rv = TRUE; + break; + } + } + return rv; +} + +//static +template +void LLStringUtilBase::stripNonprintable(std::basic_string& string) +{ + const char MIN = 32; + size_type j = 0; + if (string.empty()) + { + return; + } + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; + if(c_string == NULL) + { + return; + } + copy(c_string, string.c_str(), src_size+1); + char* write_head = &c_string[0]; + for (size_type i = 0; i < src_size; i++) + { + char* read_head = &string[i]; + write_head = &c_string[j]; + if(!(*read_head < MIN)) + { + *write_head = *read_head; + ++j; + } + } + c_string[j]= '\0'; + string = c_string; + delete []c_string; +} + +template +void LLStringUtilBase::_makeASCII(std::basic_string& string) +{ + // Replace non-ASCII chars with LL_UNKNOWN_CHAR + for (size_type i = 0; i < string.length(); i++) + { + if (string[i] > 0x7f) + { + string[i] = LL_UNKNOWN_CHAR; + } + } +} + +// static +template +void LLStringUtilBase::copy( T* dst, const T* src, size_type dst_size ) +{ + if( dst_size > 0 ) + { + size_type min_len = 0; + if( src ) + { + min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ + memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ + } + dst[min_len] = '\0'; + } +} + +// static +template +void LLStringUtilBase::copyInto(std::basic_string& dst, const std::basic_string& src, size_type offset) +{ + if ( offset == dst.length() ) + { + // special case - append to end of string and avoid expensive + // (when strings are large) string manipulations + dst += src; + } + else + { + std::basic_string tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; +} + +// True if this is the head of s. +//static +template +BOOL LLStringUtilBase::isHead( const std::basic_string& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } +} + +// static +template +bool LLStringUtilBase::startsWith( + const std::basic_string& string, + const std::basic_string& substr) +{ + if(string.empty() || (substr.empty())) return false; + if(0 == string.find(substr)) return true; + return false; +} + +// static +template +bool LLStringUtilBase::endsWith( + const std::basic_string& string, + const std::basic_string& substr) +{ + if(string.empty() || (substr.empty())) return false; + std::string::size_type idx = string.rfind(substr); + if(std::string::npos == idx) return false; + return (idx == (string.size() - substr.size())); +} + + +template +BOOL LLStringUtilBase::convertToBOOL(const std::basic_string& string, BOOL& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string temp( string ); + trim(temp); + if( + (temp == "1") || + (temp == "T") || + (temp == "t") || + (temp == "TRUE") || + (temp == "true") || + (temp == "True") ) + { + value = TRUE; + return TRUE; + } + else + if( + (temp == "0") || + (temp == "F") || + (temp == "f") || + (temp == "FALSE") || + (temp == "false") || + (temp == "False") ) + { + value = FALSE; + return TRUE; + } + + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToU8(const std::basic_string& string, U8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) + { + value = (U8) value32; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToS8(const std::basic_string& string, S8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) + { + value = (S8) value32; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToS16(const std::basic_string& string, S16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) + { + value = (S16) value32; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToU16(const std::basic_string& string, U16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) + { + value = (U16) value32; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToU32(const std::basic_string& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string temp( string ); + trim(temp); + U32 v; + std::basic_istringstream i_stream((std::basic_string)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToS32(const std::basic_string& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string temp( string ); + trim(temp); + S32 v; + std::basic_istringstream i_stream((std::basic_string)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if((LONG_MAX == v) || (LONG_MIN == v)) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToF32(const std::basic_string& string, F32& value) +{ + F64 value64 = 0.0; + BOOL success = convertToF64(string, value64); + if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) + { + value = (F32) value64; + return TRUE; + } + return FALSE; +} + +template +BOOL LLStringUtilBase::convertToF64(const std::basic_string& string, F64& value) +{ + if( string.empty() ) + { + return FALSE; + } + + std::basic_string temp( string ); + trim(temp); + F64 v; + std::basic_istringstream i_stream((std::basic_string)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; +} + +template +void LLStringUtilBase::truncate(std::basic_string& string, size_type count) +{ + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); +} + +#endif // LL_STRING_H diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 44eff8d357..f5d8174820 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -391,7 +391,7 @@ void LLTabContainer::draw() mNextArrowBtn->setFlashing( TRUE ); } } - } + } idx++; } diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index 20ba5768db..236f79978d 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -531,13 +531,13 @@ private: // this wasn't required in 1.xx viewer but we have to manually // work the Windows message pump now #if defined( LL_WINDOWS ) - MSG msg; - while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) - { - GetMessage( &msg, NULL, 0, 0 ); - TranslateMessage( &msg ); - DispatchMessage( &msg ); - }; + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + GetMessage( &msg, NULL, 0, 0 ); + TranslateMessage( &msg ); + DispatchMessage( &msg ); + }; #endif MCIdle( mMovieController ); diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml index 669235af1b..ab18febccc 100644 --- a/indra/newview/app_settings/ignorable_dialogs.xml +++ b/indra/newview/app_settings/ignorable_dialogs.xml @@ -1,291 +1,291 @@ - - - - FirstAppearance - - Comment - Enables FirstAppearance warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstAttach - - Comment - Enables FirstAttach warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstBalanceDecrease - - Comment - Enables FirstBalanceDecrease warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstBalanceIncrease - - Comment - Enables FirstBalanceIncrease warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstBuild - - Comment - Enables FirstBuild warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstDebugMenus - - Comment - Enables FirstDebugMenus warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstFlexible - - Comment - Enables FirstFlexible warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstGoTo - - Comment - Enables FirstGoTo warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstInventory - - Comment - Enables FirstInventory warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstLeftClickNoHit - - Comment - Enables FirstLeftClickNoHit warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstMap - - Comment - Enables FirstMap warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstMedia - - Comment - Enables FirstMedia warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstOverrideKeys - - Comment - Enables FirstOverrideKeys warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstSandbox - - Comment - Enables FirstSandbox warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstSculptedPrim - - Comment - Enables FirstSculptedPrim warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstSit - - Comment - Enables FirstSit warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstStreamingMusic - - Comment - Enables FirstStreamingMusic warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstStreamingVideo - - Comment - Enables FirstStreamingVideo warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstTeleport - - Comment - Enables FirstTeleport warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - FirstVoice - - Comment - Enables FirstVoice warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - AboutDirectX9 - - Comment - Enables AboutDirectX9 warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - BrowserLaunch - - Comment - Enables BrowserLaunch warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - DeedObject - - Comment - Enables DeedObject warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - NewClassified - - Comment - Enables NewClassified warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - QuickTimeInstalled - - Comment - Enables QuickTimeInstalled warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - ReturnToOwner - - Comment - Enables ReturnToOwner warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - - + + + + FirstAppearance + + Comment + Enables FirstAppearance warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstAttach + + Comment + Enables FirstAttach warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBalanceDecrease + + Comment + Enables FirstBalanceDecrease warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBalanceIncrease + + Comment + Enables FirstBalanceIncrease warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBuild + + Comment + Enables FirstBuild warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstDebugMenus + + Comment + Enables FirstDebugMenus warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstFlexible + + Comment + Enables FirstFlexible warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstGoTo + + Comment + Enables FirstGoTo warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstInventory + + Comment + Enables FirstInventory warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstLeftClickNoHit + + Comment + Enables FirstLeftClickNoHit warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstMap + + Comment + Enables FirstMap warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstMedia + + Comment + Enables FirstMedia warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstOverrideKeys + + Comment + Enables FirstOverrideKeys warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSandbox + + Comment + Enables FirstSandbox warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSculptedPrim + + Comment + Enables FirstSculptedPrim warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSit + + Comment + Enables FirstSit warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstStreamingMusic + + Comment + Enables FirstStreamingMusic warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstStreamingVideo + + Comment + Enables FirstStreamingVideo warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstTeleport + + Comment + Enables FirstTeleport warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstVoice + + Comment + Enables FirstVoice warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + AboutDirectX9 + + Comment + Enables AboutDirectX9 warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + BrowserLaunch + + Comment + Enables BrowserLaunch warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + DeedObject + + Comment + Enables DeedObject warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + NewClassified + + Comment + Enables NewClassified warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + QuickTimeInstalled + + Comment + Enables QuickTimeInstalled warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + ReturnToOwner + + Comment + Enables ReturnToOwner warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + + diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index ad80e7ed61..54b7c124e0 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1,2556 +1,2556 @@ -/** - * @file LLIMMgr.cpp - * @brief Container for Instant Messaging - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llimview.h" - -#include "llfloaterreg.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llerror.h" -#include "llbutton.h" -#include "llhttpclient.h" -#include "llsdutil_math.h" -#include "llstring.h" -#include "lluictrlfactory.h" - -#include "llagent.h" -#include "llavatariconctrl.h" -#include "llbottomtray.h" -#include "llcallingcard.h" -#include "llchat.h" -#include "llchiclet.h" -#include "llresmgr.h" -#include "llfloaterchat.h" -#include "llfloaterchatterbox.h" -#include "llavataractions.h" -#include "llhttpnode.h" -#include "llimfloater.h" -#include "llimpanel.h" -#include "llresizebar.h" -#include "lltabcontainer.h" -#include "llviewercontrol.h" -#include "llfloater.h" -#include "llmutelist.h" -#include "llresizehandle.h" -#include "llkeyboard.h" -#include "llui.h" -#include "llviewermenu.h" -#include "llcallingcard.h" -#include "lltoolbar.h" -#include "llviewermessage.h" -#include "llviewerwindow.h" -#include "llnotify.h" -#include "llviewerregion.h" -#include "llvoicechannel.h" -#include "lltrans.h" -#include "llrecentpeople.h" -#include "llsyswellwindow.h" - -#include "llfirstuse.h" -#include "llagentui.h" - -// -// Globals -// -LLIMMgr* gIMMgr = NULL; - -// -// Statics -// -// *FIXME: make these all either UIStrings or Strings - -const static std::string IM_SEPARATOR(": "); - - -void toast_callback(const LLSD& msg){ - // do not show toast in busy mode or it goes from agent - if (gAgent.getBusy() || gAgent.getID() == msg["from_id"]) - { - return; - } - - // check whether incoming IM belongs to an active session or not - if (LLIMModel::getInstance()->getActiveSessionID() == msg["session_id"]) - { - return; - } - - // Skip toasting for system messages - if (msg["from_id"].asUUID() == LLUUID::null) - { - return; - } - - LLSD args; - args["MESSAGE"] = msg["message"]; - args["TIME"] = msg["time"]; - args["FROM"] = msg["from"]; - args["FROM_ID"] = msg["from_id"]; - args["SESSION_ID"] = msg["session_id"]; - - LLNotifications::instance().add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID())); -} - -void LLIMModel::setActiveSessionID(const LLUUID& session_id) -{ - // check if such an ID really exists - if (!findIMSession(session_id)) - { - llwarns << "Trying to set as active a non-existent session!" << llendl; - return; - } - - mActiveSessionID = session_id; -} - -LLIMModel::LLIMModel() -{ - addNewMsgCallback(LLIMFloater::newIMCallback); - addNewMsgCallback(toast_callback); -} - -LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector& ids) -: mSessionID(session_id), - mName(name), - mType(type), - mNumUnread(0), - mOtherParticipantID(other_participant_id), - mInitialTargetIDs(ids), - mVoiceChannel(NULL), - mSpeakers(NULL), - mSessionInitialized(false), - mCallBackEnabled(true), - mTextIMPossible(true), - mOtherParticipantIsAvatar(true) -{ - if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) - { - mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); - } - else - { - mVoiceChannel = new LLVoiceChannelGroup(session_id, name); - } - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); - - // All participants will be added to the list of people we've recently interacted with. - mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - - //we need to wait for session initialization for outgoing ad-hoc and group chat session - //correct session id for initiated ad-hoc chat will be received from the server - if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, - mInitialTargetIDs, mType)) - { - //we don't need to wait for any responses - //so we're already initialized - mSessionInitialized = true; - } - - if (IM_NOTHING_SPECIAL == type) - { - mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); - mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); - mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID); - } - - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) - LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this); -} - -LLIMModel::LLIMSession::~LLIMSession() -{ - delete mSpeakers; - mSpeakers = NULL; - - // End the text IM session if necessary - if(gVoiceClient && mOtherParticipantID.notNull()) - { - switch(mType) - { - case IM_NOTHING_SPECIAL: - case IM_SESSION_P2P_INVITE: - gVoiceClient->endUserIMSession(mOtherParticipantID); - break; - - default: - // Appease the linux compiler - break; - } - } - - // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). - mVoiceChannel->deactivate(); - - delete mVoiceChannel; - mVoiceChannel = NULL; -} - -void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id) -{ - mSessionInitialized = true; - - if (new_session_id != mSessionID) - { - mSessionID = new_session_id; - mVoiceChannel->updateSessionID(new_session_id); - } -} - -void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time) -{ - LLSD message; - message["from"] = from; - message["from_id"] = from_id; - message["message"] = utf8_text; - message["time"] = time; - message["index"] = (LLSD::Integer)mMsgs.size(); - - mMsgs.push_front(message); - - if (mSpeakers && from_id.notNull()) - { - mSpeakers->speakerChatted(from_id); - mSpeakers->setSpeakerTyping(from_id, FALSE); - } -} - -void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata) -{ - if (!userdata) return; - - LLIMSession* self = (LLIMSession*) userdata; - - if (type == LLLogChat::LOG_LINE) - { - self->addMessage("", LLSD(), msg["message"].asString(), ""); - } - else if (type == LLLogChat::LOG_LLSD) - { - self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString()); - } -} - -LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const -{ - return get_if_there(mId2SessionMap, session_id, - (LLIMModel::LLIMSession*) NULL); -} - -void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) -{ - LLIMSession* session = findIMSession(old_session_id); - if (session) - { - session->sessionInitReplyReceived(new_session_id); - - if (old_session_id != new_session_id) - { - mId2SessionMap.erase(old_session_id); - mId2SessionMap[new_session_id] = session; - - gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); - } - - LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id); - if (im_floater) - { - im_floater->sessionInitReplyReceived(new_session_id); - } - } - - //*TODO remove this "floater" stuff when Communicate Floater is gone - LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(old_session_id); - if (floater) - { - floater->sessionInitReplyReceived(new_session_id); - } -} - -void LLIMModel::testMessages() -{ - LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); - LLUUID bot1_session_id; - std::string from = "IM Tester"; - - bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); - newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); - addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); - - LLUUID bot2_id; - std::string firstname[] = {"Roflcopter", "Joe"}; - std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; - - S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); - S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); - - from = firstname[rand1] + " " + lastname[rand2]; - bot2_id.generate(from); - LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); - newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); - addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); - addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); -} - - -bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, - const LLUUID& other_participant_id, const std::vector& ids) -{ - if (findIMSession(session_id)) - { - llwarns << "IM Session " << session_id << " already exists" << llendl; - return false; - } - - LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids); - mId2SessionMap[session_id] = session; - - LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id); - - return true; - -} - -bool LLIMModel::clearSession(const LLUUID& session_id) -{ - if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; - delete (mId2SessionMap[session_id]); - mId2SessionMap.erase(session_id); - return true; -} - -void LLIMModel::getMessages(const LLUUID& session_id, std::list& messages, int start_index) -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return; - } - - int i = session->mMsgs.size() - start_index; - - for (std::list::iterator iter = session->mMsgs.begin(); - iter != session->mMsgs.end() && i > 0; - iter++) - { - LLSD msg; - msg = *iter; - messages.push_back(*iter); - i--; - } - - session->mNumUnread = 0; - - LLSD arg; - arg["session_id"] = session_id; - arg["num_unread"] = 0; - mNoUnreadMsgsSignal(arg); -} - -bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { - - LLIMSession* session = findIMSession(session_id); - - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return false; - } - - session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp(false)); //might want to add date separately - - return true; -} - -bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) -{ - S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions"); - if (im_log_option != LOG_CHAT) - { - if(im_log_option == LOG_BOTH_TOGETHER) - { - LLLogChat::saveHistory(std::string("chat"), from, from_id, utf8_text); - return true; - } - else - { - LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text); - return true; - } - } - return false; -} - -bool LLIMModel::proccessOnlineOfflineNotification( - const LLUUID& session_id, - const std::string& utf8_text) -{ - // Add message to old one floater - LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id); - if ( floater ) - { - if ( !utf8_text.empty() ) - { - floater->addHistoryLine(utf8_text, LLUIColorTable::instance().getColor("SystemChatColor")); - } - } - // Add system message to history - return addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); -} - -bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, - const std::string& utf8_text, bool log2file /* = true */) { - LLIMSession* session = findIMSession(session_id); - - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return false; - } - - addToHistory(session_id, from, from_id, utf8_text); - if (log2file) logToFile(session_id, from, from_id, utf8_text); - - session->mNumUnread++; - - // notify listeners - LLSD arg; - arg["session_id"] = session_id; - arg["num_unread"] = session->mNumUnread; - arg["message"] = utf8_text; - arg["from"] = from; - arg["from_id"] = from_id; - arg["time"] = LLLogChat::timestamp(false); - mNewMsgSignal(arg); - - return true; -} - - -const std::string& LLIMModel::getName(const LLUUID& session_id) const -{ - LLIMSession* session = findIMSession(session_id); - - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return LLStringUtil::null; - } - - return session->mName; -} - -const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return -1; - } - - return session->mNumUnread; -} - -const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return LLUUID::null; - } - - return session->mOtherParticipantID; -} - -EInstantMessage LLIMModel::getType(const LLUUID& session_id) const -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return IM_COUNT; - } - - return session->mType; -} - -LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return NULL; - } - - return session->mVoiceChannel; -} - -LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const -{ - LLIMSession* session = findIMSession(session_id); - if (!session) - { - llwarns << "session " << session_id << "does not exist " << llendl; - return NULL; - } - - return session->mSpeakers; -} - - -// TODO get rid of other participant ID -void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) -{ - std::string name; - LLAgentUI::buildFullname(name); - - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - std::string("typing"), - IM_ONLINE, - (typing ? IM_TYPING_START : IM_TYPING_STOP), - session_id); - gAgent.sendReliableMessage(); -} - -void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id) -{ - if(session_id.notNull()) - { - std::string name; - LLAgentUI::buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name, - LLStringUtil::null, - IM_ONLINE, - IM_SESSION_LEAVE, - session_id); - gAgent.sendReliableMessage(); - } -} - -//*TODO this method is better be moved to the LLIMMgr -void LLIMModel::sendMessage(const std::string& utf8_text, - const LLUUID& im_session_id, - const LLUUID& other_participant_id, - EInstantMessage dialog) -{ - std::string name; - bool sent = false; - LLAgentUI::buildFullname(name); - - const LLRelationship* info = NULL; - info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); - - U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; - - if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) - { - // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text); - } - - if(!sent) - { - // Send message normally. - - // default to IM_SESSION_SEND unless it's nothing special - in - // which case it's probably an IM to everyone. - U8 new_dialog = dialog; - - if ( dialog != IM_NOTHING_SPECIAL ) - { - new_dialog = IM_SESSION_SEND; - } - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name.c_str(), - utf8_text.c_str(), - offline, - (EInstantMessage)new_dialog, - im_session_id); - gAgent.sendReliableMessage(); - } - - // If there is a mute list and this is not a group chat... - if ( LLMuteList::getInstance() ) - { - // ... the target should not be in our mute list for some message types. - // Auto-remove them if present. - switch( dialog ) - { - case IM_NOTHING_SPECIAL: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. - case IM_LURE_USER: - case IM_GODLIKE_LURE_USER: - case IM_FRIENDSHIP_OFFERED: - LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); - break; - default: ; // do nothing - } - } - - if((dialog == IM_NOTHING_SPECIAL) && - (other_participant_id.notNull())) - { - // Do we have to replace the /me's here? - std::string from; - LLAgentUI::buildFullname(from); - LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); - - //local echo for the legacy communicate panel - std::string history_echo; - LLAgentUI::buildFullname(history_echo); - - history_echo += ": " + utf8_text; - - LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id); - if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID()); - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); - if (speaker_mgr) - { - speaker_mgr->speakerChatted(gAgentID); - speaker_mgr->setSpeakerTyping(gAgentID, FALSE); - } - } - - // Add the recipient to the recent people list. - LLRecentPeople::instance().add(other_participant_id); -} - -void session_starter_helper( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - EInstantMessage im_type) -{ - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addU8Fast(_PREHASH_Dialog, im_type); - msg->addUUIDFast(_PREHASH_ID, temp_session_id); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - - std::string name; - LLAgentUI::buildFullname(name); - - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, LLStringUtil::null); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); -} - -void start_deprecated_conference_chat( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) -{ - U8* bucket; - U8* pos; - S32 count; - S32 bucket_size; - - // *FIX: this could suffer from endian issues - count = agents_to_invite.size(); - bucket_size = UUID_BYTES * count; - bucket = new U8[bucket_size]; - pos = bucket; - - for(S32 i = 0; i < count; ++i) - { - LLUUID agent_id = agents_to_invite[i].asUUID(); - - memcpy(pos, &agent_id, UUID_BYTES); - pos += UUID_BYTES; - } - - session_starter_helper( - temp_session_id, - other_participant_id, - IM_SESSION_CONFERENCE_START); - - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - bucket, - bucket_size); - - gAgent.sendReliableMessage(); - - delete[] bucket; -} - -class LLStartConferenceChatResponder : public LLHTTPClient::Responder -{ -public: - LLStartConferenceChatResponder( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) - { - mTempSessionID = temp_session_id; - mCreatorID = creator_id; - mOtherParticipantID = other_participant_id; - mAgents = agents_to_invite; - } - - virtual void error(U32 statusNum, const std::string& reason) - { - //try an "old school" way. - if ( statusNum == 400 ) - { - start_deprecated_conference_chat( - mTempSessionID, - mCreatorID, - mOtherParticipantID, - mAgents); - } - - //else throw an error back to the client? - //in theory we should have just have these error strings - //etc. set up in this file as opposed to the IMMgr, - //but the error string were unneeded here previously - //and it is not worth the effort switching over all - //the possible different language translations - } - -private: - LLUUID mTempSessionID; - LLUUID mCreatorID; - LLUUID mOtherParticipantID; - - LLSD mAgents; -}; - -// Returns true if any messages were sent, false otherwise. -// Is sort of equivalent to "does the server need to do anything?" -bool LLIMModel::sendStartSession( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - const std::vector& ids, - EInstantMessage dialog) -{ - if ( dialog == IM_SESSION_GROUP_START ) - { - session_starter_helper( - temp_session_id, - other_participant_id, - dialog); - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); - gAgent.sendReliableMessage(); - - return true; - } - else if ( dialog == IM_SESSION_CONFERENCE_START ) - { - LLSD agents; - for (int i = 0; i < (S32) ids.size(); i++) - { - agents.append(ids[i]); - } - - //we have a new way of starting conference calls now - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string url = region->getCapability( - "ChatSessionRequest"); - LLSD data; - data["method"] = "start conference"; - data["session-id"] = temp_session_id; - - data["params"] = agents; - - LLHTTPClient::post( - url, - data, - new LLStartConferenceChatResponder( - temp_session_id, - gAgent.getID(), - other_participant_id, - data["params"])); - } - else - { - start_deprecated_conference_chat( - temp_session_id, - gAgent.getID(), - other_participant_id, - agents); - } - - //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) - return true; - } - - return false; -} - -// static -void LLIMModel::sendSessionInitialized(const LLUUID &session_id) -{ - LLIMSession* session = getInstance()->findIMSession(session_id); - if (session) - { - LLSD arg; - arg["session_id"] = session_id; - getInstance()->mSessionInitializedSignal(arg); - } -} - -// -// Helper Functions -// - -class LLViewerChatterBoxInvitationAcceptResponder : - public LLHTTPClient::Responder -{ -public: - LLViewerChatterBoxInvitationAcceptResponder( - const LLUUID& session_id, - LLIMMgr::EInvitationType invitation_type) - { - mSessionID = session_id; - mInvitiationType = invitation_type; - } - - void result(const LLSD& content) - { - if ( gIMMgr) - { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); - if (speaker_mgr) - { - //we've accepted our invitation - //and received a list of agents that were - //currently in the session when the reply was sent - //to us. Now, it is possible that there were some agents - //to slip in/out between when that message was sent to us - //and now. - - //the agent list updates we've received have been - //accurate from the time we were added to the session - //but unfortunately, our base that we are receiving here - //may not be the most up to date. It was accurate at - //some point in time though. - speaker_mgr->setSpeakers(content); - - //we now have our base of users in the session - //that was accurate at some point, but maybe not now - //so now we apply all of the udpates we've received - //in case of race conditions - speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); - } - - if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType) - { - gIMMgr->startCall(mSessionID); - } - - if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE - || mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) - && LLIMModel::getInstance()->findIMSession(mSessionID)) - { - // always open IM window when connecting to voice - LLIMFloater::show(mSessionID); - } - - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInvitation(mSessionID); - } - } - - void error(U32 statusNum, const std::string& reason) - { - //throw something back to the viewer here? - if ( gIMMgr ) - { - gIMMgr->clearPendingAgentListUpdates(mSessionID); - gIMMgr->clearPendingInvitation(mSessionID); - if ( 404 == statusNum ) - { - std::string error_string; - error_string = "does not exist"; - gIMMgr->showSessionStartError(error_string, mSessionID); - } - } - } - -private: - LLUUID mSessionID; - LLIMMgr::EInvitationType mInvitiationType; -}; - - -// the other_participant_id is either an agent_id, a group_id, or an inventory -// folder item_id (collection of calling cards) - -// static -LLUUID LLIMMgr::computeSessionID( - EInstantMessage dialog, - const LLUUID& other_participant_id) -{ - LLUUID session_id; - if (IM_SESSION_GROUP_START == dialog) - { - // slam group session_id to the group_id (other_participant_id) - session_id = other_participant_id; - } - else if (IM_SESSION_CONFERENCE_START == dialog) - { - session_id.generate(); - } - else if (IM_SESSION_INVITE == dialog) - { - // use provided session id for invites - session_id = other_participant_id; - } - else - { - LLUUID agent_id = gAgent.getID(); - if (other_participant_id == agent_id) - { - // if we try to send an IM to ourselves then the XOR would be null - // so we just make the session_id the same as the agent_id - session_id = agent_id; - } - else - { - // peer-to-peer or peer-to-asset session_id is the XOR - session_id = other_participant_id ^ agent_id; - } - } - return session_id; -} - -inline LLFloater* getFloaterBySessionID(const LLUUID session_id) -{ - LLFloater* floater = NULL; - if ( gIMMgr ) - { - floater = dynamic_cast < LLFloater* > - ( gIMMgr->findFloaterBySession(session_id) ); - } - if ( !floater ) - { - floater = dynamic_cast < LLFloater* > - ( LLIMFloater::findInstance(session_id) ); - } - return floater; -} - -void -LLIMMgr::showSessionStartError( - const std::string& error_string, - const LLUUID session_id) -{ - const LLFloater* floater = getFloaterBySessionID (session_id); - if (!floater) return; - - LLSD args; - args["REASON"] = LLTrans::getString(error_string); - args["RECIPIENT"] = floater->getTitle(); - - LLSD payload; - payload["session_id"] = session_id; - - LLNotifications::instance().add( - "ChatterBoxSessionStartError", - args, - payload, - LLIMMgr::onConfirmForceCloseError); -} - -void -LLIMMgr::showSessionEventError( - const std::string& event_string, - const std::string& error_string, - const LLUUID session_id) -{ - const LLFloater* floater = getFloaterBySessionID (session_id); - if (!floater) return; - - LLSD args; - args["REASON"] = - LLTrans::getString(error_string); - args["EVENT"] = - LLTrans::getString(event_string); - args["RECIPIENT"] = floater->getTitle(); - - LLNotifications::instance().add( - "ChatterBoxSessionEventError", - args); -} - -void -LLIMMgr::showSessionForceClose( - const std::string& reason_string, - const LLUUID session_id) -{ - const LLFloater* floater = getFloaterBySessionID (session_id); - if (!floater) return; - - LLSD args; - - args["NAME"] = floater->getTitle(); - args["REASON"] = LLTrans::getString(reason_string); - - LLSD payload; - payload["session_id"] = session_id; - - LLNotifications::instance().add( - "ForceCloseChatterBoxSession", - args, - payload, - LLIMMgr::onConfirmForceCloseError); -} - -//static -bool -LLIMMgr::onConfirmForceCloseError( - const LLSD& notification, - const LLSD& response) -{ - //only 1 option really - LLUUID session_id = notification["payload"]["session_id"]; - - LLFloater* floater = getFloaterBySessionID (session_id); - if ( floater ) - { - floater->closeFloater(FALSE); - } - return false; -} - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLOutgoingCallDialog -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : - LLDockableFloater(NULL, false, payload), - mPayload(payload) -{ -} - -void LLOutgoingCallDialog::getAllowedRect(LLRect& rect) -{ - rect = gViewerWindow->getWorldViewRectScaled(); -} - -void LLOutgoingCallDialog::onOpen(const LLSD& key) -{ - // tell the user which voice channel they are leaving - if (!mPayload["old_channel_name"].asString().empty()) - { - childSetTextArg("leaving", "[CURRENT_CHAT]", mPayload["old_channel_name"].asString()); - } - else - { - childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat")); - } - - std::string callee_name = mPayload["session_name"].asString(); - if (callee_name == "anonymous") - { - callee_name = getString("anonymous"); - } - - setTitle(callee_name); - - LLSD callee_id = mPayload["other_user_id"]; - childSetTextArg("calling", "[CALLEE_NAME]", callee_name); - childSetTextArg("connecting", "[CALLEE_NAME]", callee_name); - LLAvatarIconCtrl* icon = getChild("avatar_icon"); - icon->setValue(callee_id); -} - - -//static -void LLOutgoingCallDialog::onCancel(void* user_data) -{ - LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; - - if (!gIMMgr) - return; - - LLUUID session_id = self->mPayload["session_id"].asUUID(); - gIMMgr->endCall(session_id); - - self->closeFloater(); -} - - -BOOL LLOutgoingCallDialog::postBuild() -{ - BOOL success = LLDockableFloater::postBuild(); - - childSetAction("Cancel", onCancel, this); - - // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), - this, getDockTongue(), LLDockControl::TOP, - boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); - - return success; -} - - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIncomingCallDialog -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : - LLDockableFloater(NULL, false, payload), - mPayload(payload) -{ -} - -BOOL LLIncomingCallDialog::postBuild() -{ - LLDockableFloater::postBuild(); - - LLSD caller_id = mPayload["caller_id"]; - EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); - - std::string call_type = getString("VoiceInviteP2P"); - std::string caller_name = mPayload["caller_name"].asString(); - if (caller_name == "anonymous") - { - caller_name = getString("anonymous"); - } - - setTitle(caller_name + " " + call_type); - - // If it is not a P2P invite, then it's an AdHoc invite - if ( type != IM_SESSION_P2P_INVITE ) - { - call_type = getString("VoiceInviteAdHoc"); - } - - // check to see if this is an Avaline call - LLUUID session_id = mPayload["session_id"].asUUID(); - bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); - childSetVisible("Start IM", is_avatar); // no IM for avaline - - LLUICtrl* caller_name_widget = getChild("caller name"); - caller_name_widget->setValue(caller_name + " " + call_type); - LLAvatarIconCtrl* icon = getChild("avatar_icon"); - icon->setValue(caller_id); - - childSetAction("Accept", onAccept, this); - childSetAction("Reject", onReject, this); - childSetAction("Start IM", onStartIM, this); - childSetFocus("Accept"); - - return TRUE; -} - -void LLIncomingCallDialog::getAllowedRect(LLRect& rect) -{ - rect = gViewerWindow->getWorldViewRectScaled(); -} - -void LLIncomingCallDialog::onOpen(const LLSD& key) -{ - // tell the user which voice channel they would be leaving - LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); - if (voice && !voice->getSessionName().empty()) - { - childSetTextArg("question", "[CURRENT_CHAT]", voice->getSessionName()); - } - else - { - childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat")); - } - - // dock the dialog to the sys well, where other sys messages appear - setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), - this, getDockTongue(), LLDockControl::TOP, - boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); -} - -//static -void LLIncomingCallDialog::onAccept(void* user_data) -{ - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - self->processCallResponse(0); - self->closeFloater(); -} - -//static -void LLIncomingCallDialog::onReject(void* user_data) -{ - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - self->processCallResponse(1); - self->closeFloater(); -} - -//static -void LLIncomingCallDialog::onStartIM(void* user_data) -{ - LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; - self->processCallResponse(2); - self->closeFloater(); -} - -void LLIncomingCallDialog::processCallResponse(S32 response) -{ - if (!gIMMgr) - return; - - LLUUID session_id = mPayload["session_id"].asUUID(); - EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger(); - bool voice = true; - switch(response) - { - case 2: // start IM: just don't start the voice chat - { - voice = false; - /* FALLTHROUGH */ - } - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - mPayload["session_name"].asString(), - mPayload["caller_id"].asUUID(), - mPayload["session_handle"].asString()); - - if (voice) - { - if (gIMMgr->startCall(session_id)) - { - // always open IM window when connecting to voice - LLIMFloater::show(session_id); - } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - LLUUID session_id = gIMMgr->addSession( - mPayload["session_name"].asString(), - type, - session_id); - if (session_id != LLUUID::null) - { - LLIMFloater::show(session_id); - } - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - if (voice) - { - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - inv_type)); - } - } - if (voice) - { - break; - } - } - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - if(gVoiceClient) - { - std::string s = mPayload["session_handle"].asString(); - gVoiceClient->declineInvite(s); - } - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - NULL); - } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } -} - -bool inviteUserResponse(const LLSD& notification, const LLSD& response) -{ - if (!gIMMgr) - return false; - - const LLSD& payload = notification["payload"]; - LLUUID session_id = payload["session_id"].asUUID(); - EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); - LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: // accept - { - if (type == IM_SESSION_P2P_INVITE) - { - // create a normal IM session - session_id = gIMMgr->addP2PSession( - payload["session_name"].asString(), - payload["caller_id"].asUUID(), - payload["session_handle"].asString(), - payload["session_uri"].asString()); - - if (gIMMgr->startCall(session_id)) - { - // always open IM window when connecting to voice - LLIMFloater::show(session_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - } - else - { - LLUUID session_id = gIMMgr->addSession( - payload["session_name"].asString(), - type, - session_id); - if (session_id != LLUUID::null) - { - LLIMFloater::show(session_id); - } - - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - inv_type)); - } - } - break; - case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) - { - // mute the sender of this invite - if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) - { - LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } - /* FALLTHROUGH */ - - case 1: // decline - { - if (type == IM_SESSION_P2P_INVITE) - { - if(gVoiceClient) - { - std::string s = payload["session_handle"].asString(); - gVoiceClient->declineInvite(s); - } - } - else - { - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - LLSD data; - data["method"] = "decline invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - NULL); - } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - gIMMgr->clearPendingInvitation(session_id); - break; - } - - return false; -} - -// -// Member Functions -// - -LLIMMgr::LLIMMgr() : - mIMReceived(FALSE) -{ - mPendingInvitations = LLSD::emptyMap(); - mPendingAgentListUpdates = LLSD::emptyMap(); -} - -// Add a message to a session. -void LLIMMgr::addMessage( - const LLUUID& session_id, - const LLUUID& target_id, - const std::string& from, - const std::string& msg, - const std::string& session_name, - EInstantMessage dialog, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, - bool link_name) // If this is true, then we insert the name and link it to a profile -{ - LLUUID other_participant_id = target_id; - - // don't process muted IMs - if (LLMuteList::getInstance()->isMuted( - other_participant_id, - LLMute::flagTextChat) && !LLMuteList::getInstance()->isLinden(from)) - { - return; - } - - LLFloaterIMPanel* floater; - LLUUID new_session_id = session_id; - if (new_session_id.isNull()) - { - //no session ID...compute new one - new_session_id = computeSessionID(dialog, other_participant_id); - } - - //*NOTE session_name is empty in case of incoming P2P sessions - std::string fixed_session_name = from; - if(!session_name.empty() && session_name.size()>1) - { - fixed_session_name = session_name; - } - - bool new_session = !hasSession(new_session_id); - if (new_session) - { - LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id); - } - - floater = findFloaterBySession(new_session_id); - if (!floater) - { - floater = findFloaterBySession(other_participant_id); - if (floater) - { - llinfos << "found the IM session " << session_id - << " by participant " << other_participant_id << llendl; - } - } - - // create IM window as necessary - if(!floater) - { - floater = createFloater( - new_session_id, - other_participant_id, - fixed_session_name, - dialog, - FALSE); - } - - if (new_session) - { - // When we get a new IM, and if you are a god, display a bit - // of information about the source. This is to help liaisons - // when answering questions. - if(gAgent.isGodlike()) - { - // *TODO:translate (low priority, god ability) - std::ostringstream bonus_info; - bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " " - << parent_estate_id - << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") - << ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : ""); - - // once we have web-services (or something) which returns - // information about a region id, we can print this out - // and even have it link to map-teleport or something. - //<< "*** region_id: " << region_id << std::endl - //<< "*** position: " << position << std::endl; - - floater->addHistoryLine(bonus_info.str(), LLUIColorTable::instance().getColor("SystemChatColor")); - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); - } - - make_ui_sound("UISndNewIncomingIMSession"); - } - - // now add message to floater - bool is_from_system = target_id.isNull() || (from == SYSTEM_FROM); - const LLColor4& color = ( is_from_system ? - LLUIColorTable::instance().getColor("SystemChatColor") : - LLUIColorTable::instance().getColor("IMChatColor")); - if ( !link_name ) - { - floater->addHistoryLine(msg,color); // No name to prepend, so just add the message normally - } - else - { - floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message - } - - LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); - - if( !LLFloaterReg::instanceVisible("communicate") && !floater->getVisible()) - { - LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(); - - //if the IM window is not open and the floater is not visible (i.e. not torn off) - LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater(); - - // select the newly added floater (or the floater with the new line added to it). - // it should be there. - chat_floater->selectFloater(floater); - - //there was a previously unseen IM, make that old tab flashing - //it is assumed that the most recently unseen IM tab is the one current selected/active - if ( previouslyActiveFloater && getIMReceived() ) - { - chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE); - } - - //notify of a new IM - notifyNewIM(); - } -} - -void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) -{ - LLUIString message; - - // null session id means near me (chat history) - if (session_id.isNull()) - { - message = LLTrans::getString(message_name); - message.setArgs(args); - - LLChat chat(message); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChatHistory(chat); - } - else // going to IM session - { - if (hasSession(session_id)) - { - message = LLTrans::getString(message_name + "-im"); - message.setArgs(args); - gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); - } - } -} - -void LLIMMgr::notifyNewIM() -{ - if(!LLFloaterReg::instanceVisible("communicate")) - { - mIMReceived = TRUE; - } -} - -S32 LLIMMgr::getNumberOfUnreadIM() -{ - std::map::iterator it; - - S32 num = 0; - for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) - { - num += (*it).second->mNumUnread; - } - - return num; -} - -void LLIMMgr::clearNewIMNotification() -{ - mIMReceived = FALSE; -} - -BOOL LLIMMgr::getIMReceived() const -{ - return mIMReceived; -} - -LLUUID LLIMMgr::addP2PSession(const std::string& name, - const LLUUID& other_participant_id, - const std::string& voice_session_handle, - const std::string& caller_uri) -{ - LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id); - if (session_id != LLUUID::null) - { - LLIMFloater::show(session_id); - } - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - LLVoiceChannelP2P* voice_channel = dynamic_cast(speaker_mgr->getVoiceChannel()); - if (voice_channel) - { - voice_channel->setSessionHandle(voice_session_handle, caller_uri); - } - } - return session_id; -} - -// This adds a session to the talk view. The name is the local name of -// the session, dialog specifies the type of session. If the session -// exists, it is brought forward. Specifying id = NULL results in an -// im session to everyone. Returns the uuid of the session. -LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id) -{ - LLDynamicArray ids; - ids.put(other_participant_id); - return addSession(name, dialog, other_participant_id, ids); -} - -// Adds a session using the given session_id. If the session already exists -// the dialog type is assumed correct. Returns the uuid of the session. -LLUUID LLIMMgr::addSession( - const std::string& name, - EInstantMessage dialog, - const LLUUID& other_participant_id, - const LLDynamicArray& ids) -{ - if (0 == ids.getLength()) - { - return LLUUID::null; - } - - LLUUID session_id = computeSessionID(dialog,other_participant_id); - - bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); - - if (new_session) - { - LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids); - } - - - //*TODO remove this "floater" thing when Communicate Floater's gone - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if(!floater) - { - // On creation, use the first element of ids as the - // "other_participant_id" - floater = createFloater( - session_id, - other_participant_id, - name, - dialog, - TRUE, - ids); - } - - //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions - if (!new_session) return session_id; - - noteOfflineUsers(session_id, floater, ids); - - // Only warn for regular IMs - not group IMs - if( dialog == IM_NOTHING_SPECIAL ) - { - noteMutedUsers(session_id, floater, ids); - } - - return session_id; -} - -bool LLIMMgr::leaveSession(const LLUUID& session_id) -{ - LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); - if (!im_session) return false; - - LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); - gIMMgr->removeSession(session_id); - return true; -} - -// Removes data associated with a particular session specified by session_id -void LLIMMgr::removeSession(const LLUUID& session_id) -{ - llassert_always(hasSession(session_id)); - - //*TODO remove this floater thing when Communicate Floater is being deleted (IB) - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if(floater) - { - mFloaters.erase(floater->getHandle()); - LLFloaterChatterBox::getInstance()->removeFloater(floater); - } - - clearPendingInvitation(session_id); - clearPendingAgentListUpdates(session_id); - - LLIMModel::getInstance()->clearSession(session_id); - - notifyObserverSessionRemoved(session_id); -} - -void LLIMMgr::inviteToSession( - const LLUUID& session_id, - const std::string& session_name, - const LLUUID& caller_id, - const std::string& caller_name, - EInstantMessage type, - EInvitationType inv_type, - const std::string& session_handle, - const std::string& session_uri) -{ - //ignore invites from muted residents - if (LLMuteList::getInstance()->isMuted(caller_id)) - { - return; - } - - std::string notify_box_type; - - BOOL ad_hoc_invite = FALSE; - if(type == IM_SESSION_P2P_INVITE) - { - //P2P is different...they only have voice invitations - notify_box_type = "VoiceInviteP2P"; - } - else if ( gAgent.isInGroup(session_id) ) - { - //only really old school groups have voice invitations - notify_box_type = "VoiceInviteGroup"; - } - else if ( inv_type == INVITATION_TYPE_VOICE ) - { - //else it's an ad-hoc - //and a voice ad-hoc - notify_box_type = "VoiceInviteAdHoc"; - ad_hoc_invite = TRUE; - } - else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) - { - notify_box_type = "InviteAdHoc"; - ad_hoc_invite = TRUE; - } - - LLSD payload; - payload["session_id"] = session_id; - payload["session_name"] = session_name; - payload["caller_id"] = caller_id; - payload["caller_name"] = caller_name; - payload["type"] = type; - payload["inv_type"] = inv_type; - payload["session_handle"] = session_handle; - payload["session_uri"] = session_uri; - payload["notify_box_type"] = notify_box_type; - - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); - if (channelp && channelp->callStarted()) - { - // you have already started a call to the other user, so just accept the invite - LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 0); - return; - } - - if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite) - { - // is the inviter a friend? - if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL) - { - // if not, and we are ignoring voice invites from non-friends - // then silently decline - if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) - { - // invite not from a friend, so decline - LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1); - return; - } - } - } - - if ( !mPendingInvitations.has(session_id.asString()) ) - { - if (caller_name.empty()) - { - gCacheName->get(caller_id, FALSE, boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3, _4)); - } - else - { - if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") - { - LLFloaterReg::showInstance("incoming_call", payload, TRUE); - } - else - { - LLSD args; - args["NAME"] = caller_name; - args["GROUP"] = session_name; - - LLNotifications::instance().add(notify_box_type, args, payload, &inviteUserResponse); - } - } - mPendingInvitations[session_id.asString()] = LLSD(); - } -} - -void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) -{ - payload["caller_name"] = first + " " + last; - payload["session_name"] = payload["caller_name"].asString(); - - std::string notify_box_type = payload["notify_box_type"].asString(); - - if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") - { - LLFloaterReg::showInstance("incoming_call", payload, TRUE); - } - else - { - LLSD args; - args["NAME"] = payload["caller_name"].asString(); - - LLNotifications::instance().add( - payload["notify_box_type"].asString(), - args, - payload, - &inviteUserResponse); - } -} - -void LLIMMgr::disconnectAllSessions() -{ - LLFloaterIMPanel* floater = NULL; - std::set >::iterator handle_it; - for(handle_it = mFloaters.begin(); - handle_it != mFloaters.end(); - ) - { - floater = (LLFloaterIMPanel*)handle_it->get(); - - // MUST do this BEFORE calling floater->onClose() because that may remove the item from the set, causing the subsequent increment to crash. - ++handle_it; - - if (floater) - { - floater->setEnabled(FALSE); - floater->closeFloater(TRUE); - } - } -} - - -// This method returns the im panel corresponding to the uuid -// provided. The uuid can either be a session id or an agent -// id. Returns NULL if there is no matching panel. -LLFloaterIMPanel* LLIMMgr::findFloaterBySession(const LLUUID& session_id) -{ - LLFloaterIMPanel* rv = NULL; - std::set >::iterator handle_it; - for(handle_it = mFloaters.begin(); - handle_it != mFloaters.end(); - ++handle_it) - { - rv = (LLFloaterIMPanel*)handle_it->get(); - if(rv && session_id == rv->getSessionID()) - { - break; - } - rv = NULL; - } - return rv; -} - - -BOOL LLIMMgr::hasSession(const LLUUID& session_id) -{ - return LLIMModel::getInstance()->findIMSession(session_id) != NULL; -} - -void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) -{ - if ( mPendingInvitations.has(session_id.asString()) ) - { - mPendingInvitations.erase(session_id.asString()); - } -} - -void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body) -{ - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); - if ( im_floater ) - { - im_floater->processAgentListUpdates(body); - } - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->updateSpeakers(body); - } - else - { - //we don't have a speaker manager yet..something went wrong - //we are probably receiving an update here before - //a start or an acceptance of an invitation. Race condition. - gIMMgr->addPendingAgentListUpdates( - session_id, - body); - } -} - -LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id) -{ - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - return mPendingAgentListUpdates[session_id.asString()]; - } - else - { - return LLSD(); - } -} - -void LLIMMgr::addPendingAgentListUpdates( - const LLUUID& session_id, - const LLSD& updates) -{ - LLSD::map_const_iterator iter; - - if ( !mPendingAgentListUpdates.has(session_id.asString()) ) - { - //this is a new agent list update for this session - mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); - } - - if ( - updates.has("agent_updates") && - updates["agent_updates"].isMap() && - updates.has("updates") && - updates["updates"].isMap() ) - { - //new school update - LLSD update_types = LLSD::emptyArray(); - LLSD::array_iterator array_iter; - - update_types.append("agent_updates"); - update_types.append("updates"); - - for ( - array_iter = update_types.beginArray(); - array_iter != update_types.endArray(); - ++array_iter) - { - //we only want to include the last update for a given agent - for ( - iter = updates[array_iter->asString()].beginMap(); - iter != updates[array_iter->asString()].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = - iter->second; - } - } - } - else if ( - updates.has("updates") && - updates["updates"].isMap() ) - { - //old school update where the SD contained just mappings - //of agent_id -> "LEAVE"/"ENTER" - - //only want to keep last update for each agent - for ( - iter = updates["updates"].beginMap(); - iter != updates["updates"].endMap(); - ++iter) - { - mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = - iter->second; - } - } -} - -void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) -{ - if ( mPendingAgentListUpdates.has(session_id.asString()) ) - { - mPendingAgentListUpdates.erase(session_id.asString()); - } -} - -void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) -{ - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionAdded(session_id, name, other_participant_id); - } -} - -void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) -{ - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionRemoved(session_id); - } -} - -void LLIMMgr::notifyObserverSessionIDUpdated( const LLUUID& old_session_id, const LLUUID& new_session_id ) -{ - for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) - { - (*it)->sessionIDUpdated(old_session_id, new_session_id); - } - -} - -void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer) -{ - mSessionObservers.push_back(observer); -} - -void LLIMMgr::removeSessionObserver(LLIMSessionObserver *observer) -{ - mSessionObservers.remove(observer); -} - -bool LLIMMgr::startCall(const LLUUID& session_id) -{ - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; - - voice_channel->activate(); - return true; -} - -bool LLIMMgr::endCall(const LLUUID& session_id) -{ - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); - if (!voice_channel) return false; - - voice_channel->deactivate(); - return true; -} - -// create a floater and update internal representation for -// consistency. Returns the pointer, caller (the class instance since -// it is a private method) is not responsible for deleting the -// pointer. Add the floater to this but do not select it. -LLFloaterIMPanel* LLIMMgr::createFloater( - const LLUUID& session_id, - const LLUUID& other_participant_id, - const std::string& session_label, - EInstantMessage dialog, - BOOL user_initiated, - const LLDynamicArray& ids) -{ - if (session_id.isNull()) - { - llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl; - } - - llinfos << "LLIMMgr::createFloater: from " << other_participant_id - << " in session " << session_id << llendl; - LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, - session_id, - other_participant_id, - ids, - dialog); - LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; - LLFloaterChatterBox::getInstance()->addFloater(floater, FALSE, i_pt); - mFloaters.insert(floater->getHandle()); - return floater; -} - -void LLIMMgr::noteOfflineUsers( - const LLUUID& session_id, - LLFloaterIMPanel* floater, - const LLDynamicArray& ids) -{ - S32 count = ids.count(); - if(count == 0) - { - const std::string& only_user = LLTrans::getString("only_user_message"); - if (floater) - { - floater->addHistoryLine(only_user, LLUIColorTable::instance().getColor("SystemChatColor")); - } - LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); - } - else - { - const LLRelationship* info = NULL; - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLIMModel& im_model = LLIMModel::instance(); - for(S32 i = 0; i < count; ++i) - { - info = at.getBuddyInfo(ids.get(i)); - std::string first, last; - if(info && !info->isOnline() - && gCacheName->getName(ids.get(i), first, last)) - { - LLUIString offline = LLTrans::getString("offline_message"); - offline.setArg("[FIRST]", first); - offline.setArg("[LAST]", last); - im_model.proccessOnlineOfflineNotification(session_id, offline); - } - } - } -} - -void LLIMMgr::noteMutedUsers(const LLUUID& session_id, LLFloaterIMPanel* floater, - const LLDynamicArray& ids) -{ - // Don't do this if we don't have a mute list. - LLMuteList *ml = LLMuteList::getInstance(); - if( !ml ) - { - return; - } - - S32 count = ids.count(); - if(count > 0) - { - LLIMModel* im_model = LLIMModel::getInstance(); - - for(S32 i = 0; i < count; ++i) - { - if( ml->isMuted(ids.get(i)) ) - { - LLUIString muted = LLTrans::getString("muted_message"); - - //*TODO remove this "floater" thing when Communicate Floater's gone - floater->addHistoryLine(muted); - - im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); - break; - } - } - } -} - -void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info) -{ - processIMTypingCore(im_info, TRUE); -} - -void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info) -{ - processIMTypingCore(im_info, FALSE); -} - -void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing) -{ - LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID); - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if (floater) - { - floater->processIMTyping(im_info, typing); - } - - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); - if ( im_floater ) - { - im_floater->processIMTyping(im_info, typing); - } -} - -class LLViewerChatterBoxSessionStartReply : public LLHTTPNode -{ -public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); - desc.postAPI(); - desc.input( - "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLSD body; - LLUUID temp_session_id; - LLUUID session_id; - bool success; - - body = input["body"]; - success = body["success"].asBoolean(); - temp_session_id = body["temp_session_id"].asUUID(); - - if ( success ) - { - session_id = body["session_id"].asUUID(); - - LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); - - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); - if (speaker_mgr) - { - speaker_mgr->setSpeakers(body); - speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); - } - - LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); - if (floaterp) - { - if ( body.has("session_info") ) - { - floaterp->processSessionUpdate(body["session_info"]); - } - } - - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); - if ( im_floater ) - { - if ( body.has("session_info") ) - { - im_floater->processSessionUpdate(body["session_info"]); - } - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } - else - { - //throw an error dialog and close the temp session's floater - gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); - } - - gIMMgr->clearPendingAgentListUpdates(session_id); - } -}; - -class LLViewerChatterBoxSessionEventReply : public LLHTTPNode -{ -public: - virtual void describe(Description& desc) const - { - desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); - desc.postAPI(); - desc.input( - "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); - desc.source(__FILE__, __LINE__); - } - - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - bool success; - - LLSD body = input["body"]; - success = body["success"].asBoolean(); - session_id = body["session_id"].asUUID(); - - if ( !success ) - { - //throw an error dialog - gIMMgr->showSessionEventError( - body["event"].asString(), - body["error"].asString(), - session_id); - } - } -}; - -class LLViewerForceCloseChatterBoxSession: public LLHTTPNode -{ -public: - virtual void post(ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id; - std::string reason; - - session_id = input["body"]["session_id"].asUUID(); - reason = input["body"]["reason"].asString(); - - gIMMgr->showSessionForceClose(reason, session_id); - } -}; - -class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode -{ -public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - const LLUUID& session_id = input["body"]["session_id"].asUUID(); - gIMMgr->processAgentListUpdates(session_id, input["body"]); - } -}; - -class LLViewerChatterBoxSessionUpdate : public LLHTTPNode -{ -public: - virtual void post( - ResponsePtr responder, - const LLSD& context, - const LLSD& input) const - { - LLUUID session_id = input["body"]["session_id"].asUUID(); - LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); - if (floaterp) - { - floaterp->processSessionUpdate(input["body"]["info"]); - } - LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); - if ( im_floater ) - { - im_floater->processSessionUpdate(input["body"]["info"]); - } - } -}; - - -class LLViewerChatterBoxInvitation : public LLHTTPNode -{ -public: - - virtual void post( - ResponsePtr response, - const LLSD& context, - const LLSD& input) const - { - //for backwards compatiblity reasons...we need to still - //check for 'text' or 'voice' invitations...bleh - if ( input["body"].has("instantmessage") ) - { - LLSD message_params = - input["body"]["instantmessage"]["message_params"]; - - //do something here to have the IM invite behave - //just like a normal IM - //this is just replicated code from process_improved_im - //and should really go in it's own function -jwolk - if (gNoRender) - { - return; - } - LLChat chat; - - std::string message = message_params["message"].asString(); - std::string name = message_params["from_name"].asString(); - LLUUID from_id = message_params["from_id"].asUUID(); - LLUUID session_id = message_params["id"].asUUID(); - std::vector bin_bucket = message_params["data"]["binary_bucket"].asBinary(); - U8 offline = (U8)message_params["offline"].asInteger(); - - time_t timestamp = - (time_t) message_params["timestamp"].asInteger(); - - BOOL is_busy = gAgent.getBusy(); - BOOL is_muted = LLMuteList::getInstance()->isMuted( - from_id, - name, - LLMute::flagTextChat); - - BOOL is_linden = LLMuteList::getInstance()->isLinden(name); - std::string separator_string(": "); - - chat.mMuted = is_muted && !is_linden; - chat.mFromID = from_id; - chat.mFromName = name; - - if (!is_linden && (is_busy || is_muted)) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); - } - std::string buffer = saved + message; - - BOOL is_this_agent = FALSE; - if(from_id == gAgentID) - { - is_this_agent = TRUE; - } - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - std::string((char*)&bin_bucket[0]), - IM_SESSION_INVITE, - message_params["parent_estate_id"].asInteger(), - message_params["region_id"].asUUID(), - ll_vector3_from_sd(message_params["position"]), - true); - - chat.mText = std::string("IM: ") + name + separator_string + saved + message; - LLFloaterChat::addChat(chat, TRUE, is_this_agent); - - //K now we want to accept the invitation - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); - - if ( url != "" ) - { - LLSD data; - data["method"] = "accept invitation"; - data["session-id"] = session_id; - LLHTTPClient::post( - url, - data, - new LLViewerChatterBoxInvitationAcceptResponder( - session_id, - LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); - } - } //end if invitation has instant message - else if ( input["body"].has("voice") ) - { - if (gNoRender) - { - return; - } - - if(!LLVoiceClient::voiceEnabled()) - { - // Don't display voice invites unless the user has voice enabled. - return; - } - - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_VOICE); - } - else if ( input["body"].has("immediate") ) - { - gIMMgr->inviteToSession( - input["body"]["session_id"].asUUID(), - input["body"]["session_name"].asString(), - input["body"]["from_id"].asUUID(), - input["body"]["from_name"].asString(), - IM_SESSION_INVITE, - LLIMMgr::INVITATION_TYPE_IMMEDIATE); - } - } -}; - -LLHTTPRegistration - gHTTPRegistrationMessageChatterboxsessionstartreply( - "/message/ChatterBoxSessionStartReply"); - -LLHTTPRegistration - gHTTPRegistrationMessageChatterboxsessioneventreply( - "/message/ChatterBoxSessionEventReply"); - -LLHTTPRegistration - gHTTPRegistrationMessageForceclosechatterboxsession( - "/message/ForceCloseChatterBoxSession"); - -LLHTTPRegistration - gHTTPRegistrationMessageChatterboxsessionagentlistupdates( - "/message/ChatterBoxSessionAgentListUpdates"); - -LLHTTPRegistration - gHTTPRegistrationMessageChatterBoxSessionUpdate( - "/message/ChatterBoxSessionUpdate"); - -LLHTTPRegistration - gHTTPRegistrationMessageChatterBoxInvitation( - "/message/ChatterBoxInvitation"); - +/** + * @file LLIMMgr.cpp + * @brief Container for Instant Messaging + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llimview.h" + +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llrect.h" +#include "llerror.h" +#include "llbutton.h" +#include "llhttpclient.h" +#include "llsdutil_math.h" +#include "llstring.h" +#include "lluictrlfactory.h" + +#include "llagent.h" +#include "llavatariconctrl.h" +#include "llbottomtray.h" +#include "llcallingcard.h" +#include "llchat.h" +#include "llchiclet.h" +#include "llresmgr.h" +#include "llfloaterchat.h" +#include "llfloaterchatterbox.h" +#include "llavataractions.h" +#include "llhttpnode.h" +#include "llimfloater.h" +#include "llimpanel.h" +#include "llresizebar.h" +#include "lltabcontainer.h" +#include "llviewercontrol.h" +#include "llfloater.h" +#include "llmutelist.h" +#include "llresizehandle.h" +#include "llkeyboard.h" +#include "llui.h" +#include "llviewermenu.h" +#include "llcallingcard.h" +#include "lltoolbar.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llnotify.h" +#include "llviewerregion.h" +#include "llvoicechannel.h" +#include "lltrans.h" +#include "llrecentpeople.h" +#include "llsyswellwindow.h" + +#include "llfirstuse.h" +#include "llagentui.h" + +// +// Globals +// +LLIMMgr* gIMMgr = NULL; + +// +// Statics +// +// *FIXME: make these all either UIStrings or Strings + +const static std::string IM_SEPARATOR(": "); + + +void toast_callback(const LLSD& msg){ + // do not show toast in busy mode or it goes from agent + if (gAgent.getBusy() || gAgent.getID() == msg["from_id"]) + { + return; + } + + // check whether incoming IM belongs to an active session or not + if (LLIMModel::getInstance()->getActiveSessionID() == msg["session_id"]) + { + return; + } + + // Skip toasting for system messages + if (msg["from_id"].asUUID() == LLUUID::null) + { + return; + } + + LLSD args; + args["MESSAGE"] = msg["message"]; + args["TIME"] = msg["time"]; + args["FROM"] = msg["from"]; + args["FROM_ID"] = msg["from_id"]; + args["SESSION_ID"] = msg["session_id"]; + + LLNotifications::instance().add("IMToast", args, LLSD(), boost::bind(&LLIMFloater::show, msg["session_id"].asUUID())); +} + +void LLIMModel::setActiveSessionID(const LLUUID& session_id) +{ + // check if such an ID really exists + if (!findIMSession(session_id)) + { + llwarns << "Trying to set as active a non-existent session!" << llendl; + return; + } + + mActiveSessionID = session_id; +} + +LLIMModel::LLIMModel() +{ + addNewMsgCallback(LLIMFloater::newIMCallback); + addNewMsgCallback(toast_callback); +} + +LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id, const std::vector& ids) +: mSessionID(session_id), + mName(name), + mType(type), + mNumUnread(0), + mOtherParticipantID(other_participant_id), + mInitialTargetIDs(ids), + mVoiceChannel(NULL), + mSpeakers(NULL), + mSessionInitialized(false), + mCallBackEnabled(true), + mTextIMPossible(true), + mOtherParticipantIsAvatar(true) +{ + if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type) + { + mVoiceChannel = new LLVoiceChannelP2P(session_id, name, other_participant_id); + } + else + { + mVoiceChannel = new LLVoiceChannelGroup(session_id, name); + } + mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + + // All participants will be added to the list of people we've recently interacted with. + mSpeakers->addListener(&LLRecentPeople::instance(), "add"); + + //we need to wait for session initialization for outgoing ad-hoc and group chat session + //correct session id for initiated ad-hoc chat will be received from the server + if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID, + mInitialTargetIDs, mType)) + { + //we don't need to wait for any responses + //so we're already initialized + mSessionInitialized = true; + } + + if (IM_NOTHING_SPECIAL == type) + { + mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); + mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); + mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID); + } + + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + LLLogChat::loadHistory(mName, &chatFromLogFile, (void *)this); +} + +LLIMModel::LLIMSession::~LLIMSession() +{ + delete mSpeakers; + mSpeakers = NULL; + + // End the text IM session if necessary + if(gVoiceClient && mOtherParticipantID.notNull()) + { + switch(mType) + { + case IM_NOTHING_SPECIAL: + case IM_SESSION_P2P_INVITE: + gVoiceClient->endUserIMSession(mOtherParticipantID); + break; + + default: + // Appease the linux compiler + break; + } + } + + // HAVE to do this here -- if it happens in the LLVoiceChannel destructor it will call the wrong version (since the object's partially deconstructed at that point). + mVoiceChannel->deactivate(); + + delete mVoiceChannel; + mVoiceChannel = NULL; +} + +void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_id) +{ + mSessionInitialized = true; + + if (new_session_id != mSessionID) + { + mSessionID = new_session_id; + mVoiceChannel->updateSessionID(new_session_id); + } +} + +void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time) +{ + LLSD message; + message["from"] = from; + message["from_id"] = from_id; + message["message"] = utf8_text; + message["time"] = time; + message["index"] = (LLSD::Integer)mMsgs.size(); + + mMsgs.push_front(message); + + if (mSpeakers && from_id.notNull()) + { + mSpeakers->speakerChatted(from_id); + mSpeakers->setSpeakerTyping(from_id, FALSE); + } +} + +void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata) +{ + if (!userdata) return; + + LLIMSession* self = (LLIMSession*) userdata; + + if (type == LLLogChat::LOG_LINE) + { + self->addMessage("", LLSD(), msg["message"].asString(), ""); + } + else if (type == LLLogChat::LOG_LLSD) + { + self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString()); + } +} + +LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const +{ + return get_if_there(mId2SessionMap, session_id, + (LLIMModel::LLIMSession*) NULL); +} + +void LLIMModel::processSessionInitializedReply(const LLUUID& old_session_id, const LLUUID& new_session_id) +{ + LLIMSession* session = findIMSession(old_session_id); + if (session) + { + session->sessionInitReplyReceived(new_session_id); + + if (old_session_id != new_session_id) + { + mId2SessionMap.erase(old_session_id); + mId2SessionMap[new_session_id] = session; + + gIMMgr->notifyObserverSessionIDUpdated(old_session_id, new_session_id); + } + + LLIMFloater* im_floater = LLIMFloater::findInstance(old_session_id); + if (im_floater) + { + im_floater->sessionInitReplyReceived(new_session_id); + } + } + + //*TODO remove this "floater" stuff when Communicate Floater is gone + LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(old_session_id); + if (floater) + { + floater->sessionInitReplyReceived(new_session_id); + } +} + +void LLIMModel::testMessages() +{ + LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); + LLUUID bot1_session_id; + std::string from = "IM Tester"; + + bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); + newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); + addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); + + LLUUID bot2_id; + std::string firstname[] = {"Roflcopter", "Joe"}; + std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; + + S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); + S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); + + from = firstname[rand1] + " " + lastname[rand2]; + bot2_id.generate(from); + LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); + newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); + addMessage(bot2_session_id, from, bot2_id, "Test Message: Hello there, I have a question. Can I bother you for a second? "); + addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); +} + + +bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, + const LLUUID& other_participant_id, const std::vector& ids) +{ + if (findIMSession(session_id)) + { + llwarns << "IM Session " << session_id << " already exists" << llendl; + return false; + } + + LLIMSession* session = new LLIMSession(session_id, name, type, other_participant_id, ids); + mId2SessionMap[session_id] = session; + + LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id); + + return true; + +} + +bool LLIMModel::clearSession(const LLUUID& session_id) +{ + if (mId2SessionMap.find(session_id) == mId2SessionMap.end()) return false; + delete (mId2SessionMap[session_id]); + mId2SessionMap.erase(session_id); + return true; +} + +void LLIMModel::getMessages(const LLUUID& session_id, std::list& messages, int start_index) +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return; + } + + int i = session->mMsgs.size() - start_index; + + for (std::list::iterator iter = session->mMsgs.begin(); + iter != session->mMsgs.end() && i > 0; + iter++) + { + LLSD msg; + msg = *iter; + messages.push_back(*iter); + i--; + } + + session->mNumUnread = 0; + + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = 0; + mNoUnreadMsgsSignal(arg); +} + +bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) { + + LLIMSession* session = findIMSession(session_id); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return false; + } + + session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp(false)); //might want to add date separately + + return true; +} + +bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) +{ + S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions"); + if (im_log_option != LOG_CHAT) + { + if(im_log_option == LOG_BOTH_TOGETHER) + { + LLLogChat::saveHistory(std::string("chat"), from, from_id, utf8_text); + return true; + } + else + { + LLLogChat::saveHistory(LLIMModel::getInstance()->getName(session_id), from, from_id, utf8_text); + return true; + } + } + return false; +} + +bool LLIMModel::proccessOnlineOfflineNotification( + const LLUUID& session_id, + const std::string& utf8_text) +{ + // Add message to old one floater + LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id); + if ( floater ) + { + if ( !utf8_text.empty() ) + { + floater->addHistoryLine(utf8_text, LLUIColorTable::instance().getColor("SystemChatColor")); + } + } + // Add system message to history + return addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); +} + +bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, + const std::string& utf8_text, bool log2file /* = true */) { + LLIMSession* session = findIMSession(session_id); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return false; + } + + addToHistory(session_id, from, from_id, utf8_text); + if (log2file) logToFile(session_id, from, from_id, utf8_text); + + session->mNumUnread++; + + // notify listeners + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = session->mNumUnread; + arg["message"] = utf8_text; + arg["from"] = from; + arg["from_id"] = from_id; + arg["time"] = LLLogChat::timestamp(false); + mNewMsgSignal(arg); + + return true; +} + + +const std::string& LLIMModel::getName(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return LLStringUtil::null; + } + + return session->mName; +} + +const S32 LLIMModel::getNumUnread(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return -1; + } + + return session->mNumUnread; +} + +const LLUUID& LLIMModel::getOtherParticipantID(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return LLUUID::null; + } + + return session->mOtherParticipantID; +} + +EInstantMessage LLIMModel::getType(const LLUUID& session_id) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return IM_COUNT; + } + + return session->mType; +} + +LLVoiceChannel* LLIMModel::getVoiceChannel( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mVoiceChannel; +} + +LLIMSpeakerMgr* LLIMModel::getSpeakerManager( const LLUUID& session_id ) const +{ + LLIMSession* session = findIMSession(session_id); + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return NULL; + } + + return session->mSpeakers; +} + + +// TODO get rid of other participant ID +void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) +{ + std::string name; + LLAgentUI::buildFullname(name); + + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + std::string("typing"), + IM_ONLINE, + (typing ? IM_TYPING_START : IM_TYPING_STOP), + session_id); + gAgent.sendReliableMessage(); +} + +void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id) +{ + if(session_id.notNull()) + { + std::string name; + LLAgentUI::buildFullname(name); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + LLStringUtil::null, + IM_ONLINE, + IM_SESSION_LEAVE, + session_id); + gAgent.sendReliableMessage(); + } +} + +//*TODO this method is better be moved to the LLIMMgr +void LLIMModel::sendMessage(const std::string& utf8_text, + const LLUUID& im_session_id, + const LLUUID& other_participant_id, + EInstantMessage dialog) +{ + std::string name; + bool sent = false; + LLAgentUI::buildFullname(name); + + const LLRelationship* info = NULL; + info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); + + U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; + + if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) + { + // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. + sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text); + } + + if(!sent) + { + // Send message normally. + + // default to IM_SESSION_SEND unless it's nothing special - in + // which case it's probably an IM to everyone. + U8 new_dialog = dialog; + + if ( dialog != IM_NOTHING_SPECIAL ) + { + new_dialog = IM_SESSION_SEND; + } + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name.c_str(), + utf8_text.c_str(), + offline, + (EInstantMessage)new_dialog, + im_session_id); + gAgent.sendReliableMessage(); + } + + // If there is a mute list and this is not a group chat... + if ( LLMuteList::getInstance() ) + { + // ... the target should not be in our mute list for some message types. + // Auto-remove them if present. + switch( dialog ) + { + case IM_NOTHING_SPECIAL: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. + case IM_LURE_USER: + case IM_GODLIKE_LURE_USER: + case IM_FRIENDSHIP_OFFERED: + LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); + break; + default: ; // do nothing + } + } + + if((dialog == IM_NOTHING_SPECIAL) && + (other_participant_id.notNull())) + { + // Do we have to replace the /me's here? + std::string from; + LLAgentUI::buildFullname(from); + LLIMModel::getInstance()->addMessage(im_session_id, from, gAgentID, utf8_text); + + //local echo for the legacy communicate panel + std::string history_echo; + LLAgentUI::buildFullname(history_echo); + + history_echo += ": " + utf8_text; + + LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id); + if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID()); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(im_session_id); + if (speaker_mgr) + { + speaker_mgr->speakerChatted(gAgentID); + speaker_mgr->setSpeakerTyping(gAgentID, FALSE); + } + } + + // Add the recipient to the recent people list. + LLRecentPeople::instance().add(other_participant_id); +} + +void session_starter_helper( + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + EInstantMessage im_type) +{ + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_MessageBlock); + msg->addBOOLFast(_PREHASH_FromGroup, FALSE); + msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addU8Fast(_PREHASH_Dialog, im_type); + msg->addUUIDFast(_PREHASH_ID, temp_session_id); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + + std::string name; + LLAgentUI::buildFullname(name); + + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, LLStringUtil::null); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); +} + +void start_deprecated_conference_chat( + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) +{ + U8* bucket; + U8* pos; + S32 count; + S32 bucket_size; + + // *FIX: this could suffer from endian issues + count = agents_to_invite.size(); + bucket_size = UUID_BYTES * count; + bucket = new U8[bucket_size]; + pos = bucket; + + for(S32 i = 0; i < count; ++i) + { + LLUUID agent_id = agents_to_invite[i].asUUID(); + + memcpy(pos, &agent_id, UUID_BYTES); + pos += UUID_BYTES; + } + + session_starter_helper( + temp_session_id, + other_participant_id, + IM_SESSION_CONFERENCE_START); + + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + bucket, + bucket_size); + + gAgent.sendReliableMessage(); + + delete[] bucket; +} + +class LLStartConferenceChatResponder : public LLHTTPClient::Responder +{ +public: + LLStartConferenceChatResponder( + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) + { + mTempSessionID = temp_session_id; + mCreatorID = creator_id; + mOtherParticipantID = other_participant_id; + mAgents = agents_to_invite; + } + + virtual void error(U32 statusNum, const std::string& reason) + { + //try an "old school" way. + if ( statusNum == 400 ) + { + start_deprecated_conference_chat( + mTempSessionID, + mCreatorID, + mOtherParticipantID, + mAgents); + } + + //else throw an error back to the client? + //in theory we should have just have these error strings + //etc. set up in this file as opposed to the IMMgr, + //but the error string were unneeded here previously + //and it is not worth the effort switching over all + //the possible different language translations + } + +private: + LLUUID mTempSessionID; + LLUUID mCreatorID; + LLUUID mOtherParticipantID; + + LLSD mAgents; +}; + +// Returns true if any messages were sent, false otherwise. +// Is sort of equivalent to "does the server need to do anything?" +bool LLIMModel::sendStartSession( + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + const std::vector& ids, + EInstantMessage dialog) +{ + if ( dialog == IM_SESSION_GROUP_START ) + { + session_starter_helper( + temp_session_id, + other_participant_id, + dialog); + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); + gAgent.sendReliableMessage(); + + return true; + } + else if ( dialog == IM_SESSION_CONFERENCE_START ) + { + LLSD agents; + for (int i = 0; i < (S32) ids.size(); i++) + { + agents.append(ids[i]); + } + + //we have a new way of starting conference calls now + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string url = region->getCapability( + "ChatSessionRequest"); + LLSD data; + data["method"] = "start conference"; + data["session-id"] = temp_session_id; + + data["params"] = agents; + + LLHTTPClient::post( + url, + data, + new LLStartConferenceChatResponder( + temp_session_id, + gAgent.getID(), + other_participant_id, + data["params"])); + } + else + { + start_deprecated_conference_chat( + temp_session_id, + gAgent.getID(), + other_participant_id, + agents); + } + + //we also need to wait for reply from the server in case of ad-hoc chat (we'll get new session id) + return true; + } + + return false; +} + +// static +void LLIMModel::sendSessionInitialized(const LLUUID &session_id) +{ + LLIMSession* session = getInstance()->findIMSession(session_id); + if (session) + { + LLSD arg; + arg["session_id"] = session_id; + getInstance()->mSessionInitializedSignal(arg); + } +} + +// +// Helper Functions +// + +class LLViewerChatterBoxInvitationAcceptResponder : + public LLHTTPClient::Responder +{ +public: + LLViewerChatterBoxInvitationAcceptResponder( + const LLUUID& session_id, + LLIMMgr::EInvitationType invitation_type) + { + mSessionID = session_id; + mInvitiationType = invitation_type; + } + + void result(const LLSD& content) + { + if ( gIMMgr) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) + { + //we've accepted our invitation + //and received a list of agents that were + //currently in the session when the reply was sent + //to us. Now, it is possible that there were some agents + //to slip in/out between when that message was sent to us + //and now. + + //the agent list updates we've received have been + //accurate from the time we were added to the session + //but unfortunately, our base that we are receiving here + //may not be the most up to date. It was accurate at + //some point in time though. + speaker_mgr->setSpeakers(content); + + //we now have our base of users in the session + //that was accurate at some point, but maybe not now + //so now we apply all of the udpates we've received + //in case of race conditions + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(mSessionID)); + } + + if (LLIMMgr::INVITATION_TYPE_VOICE == mInvitiationType) + { + gIMMgr->startCall(mSessionID); + } + + if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE + || mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) + && LLIMModel::getInstance()->findIMSession(mSessionID)) + { + // always open IM window when connecting to voice + LLIMFloater::show(mSessionID); + } + + gIMMgr->clearPendingAgentListUpdates(mSessionID); + gIMMgr->clearPendingInvitation(mSessionID); + } + } + + void error(U32 statusNum, const std::string& reason) + { + //throw something back to the viewer here? + if ( gIMMgr ) + { + gIMMgr->clearPendingAgentListUpdates(mSessionID); + gIMMgr->clearPendingInvitation(mSessionID); + if ( 404 == statusNum ) + { + std::string error_string; + error_string = "does not exist"; + gIMMgr->showSessionStartError(error_string, mSessionID); + } + } + } + +private: + LLUUID mSessionID; + LLIMMgr::EInvitationType mInvitiationType; +}; + + +// the other_participant_id is either an agent_id, a group_id, or an inventory +// folder item_id (collection of calling cards) + +// static +LLUUID LLIMMgr::computeSessionID( + EInstantMessage dialog, + const LLUUID& other_participant_id) +{ + LLUUID session_id; + if (IM_SESSION_GROUP_START == dialog) + { + // slam group session_id to the group_id (other_participant_id) + session_id = other_participant_id; + } + else if (IM_SESSION_CONFERENCE_START == dialog) + { + session_id.generate(); + } + else if (IM_SESSION_INVITE == dialog) + { + // use provided session id for invites + session_id = other_participant_id; + } + else + { + LLUUID agent_id = gAgent.getID(); + if (other_participant_id == agent_id) + { + // if we try to send an IM to ourselves then the XOR would be null + // so we just make the session_id the same as the agent_id + session_id = agent_id; + } + else + { + // peer-to-peer or peer-to-asset session_id is the XOR + session_id = other_participant_id ^ agent_id; + } + } + return session_id; +} + +inline LLFloater* getFloaterBySessionID(const LLUUID session_id) +{ + LLFloater* floater = NULL; + if ( gIMMgr ) + { + floater = dynamic_cast < LLFloater* > + ( gIMMgr->findFloaterBySession(session_id) ); + } + if ( !floater ) + { + floater = dynamic_cast < LLFloater* > + ( LLIMFloater::findInstance(session_id) ); + } + return floater; +} + +void +LLIMMgr::showSessionStartError( + const std::string& error_string, + const LLUUID session_id) +{ + const LLFloater* floater = getFloaterBySessionID (session_id); + if (!floater) return; + + LLSD args; + args["REASON"] = LLTrans::getString(error_string); + args["RECIPIENT"] = floater->getTitle(); + + LLSD payload; + payload["session_id"] = session_id; + + LLNotifications::instance().add( + "ChatterBoxSessionStartError", + args, + payload, + LLIMMgr::onConfirmForceCloseError); +} + +void +LLIMMgr::showSessionEventError( + const std::string& event_string, + const std::string& error_string, + const LLUUID session_id) +{ + const LLFloater* floater = getFloaterBySessionID (session_id); + if (!floater) return; + + LLSD args; + args["REASON"] = + LLTrans::getString(error_string); + args["EVENT"] = + LLTrans::getString(event_string); + args["RECIPIENT"] = floater->getTitle(); + + LLNotifications::instance().add( + "ChatterBoxSessionEventError", + args); +} + +void +LLIMMgr::showSessionForceClose( + const std::string& reason_string, + const LLUUID session_id) +{ + const LLFloater* floater = getFloaterBySessionID (session_id); + if (!floater) return; + + LLSD args; + + args["NAME"] = floater->getTitle(); + args["REASON"] = LLTrans::getString(reason_string); + + LLSD payload; + payload["session_id"] = session_id; + + LLNotifications::instance().add( + "ForceCloseChatterBoxSession", + args, + payload, + LLIMMgr::onConfirmForceCloseError); +} + +//static +bool +LLIMMgr::onConfirmForceCloseError( + const LLSD& notification, + const LLSD& response) +{ + //only 1 option really + LLUUID session_id = notification["payload"]["session_id"]; + + LLFloater* floater = getFloaterBySessionID (session_id); + if ( floater ) + { + floater->closeFloater(FALSE); + } + return false; +} + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLOutgoingCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLOutgoingCallDialog::LLOutgoingCallDialog(const LLSD& payload) : + LLDockableFloater(NULL, false, payload), + mPayload(payload) +{ +} + +void LLOutgoingCallDialog::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRectScaled(); +} + +void LLOutgoingCallDialog::onOpen(const LLSD& key) +{ + // tell the user which voice channel they are leaving + if (!mPayload["old_channel_name"].asString().empty()) + { + childSetTextArg("leaving", "[CURRENT_CHAT]", mPayload["old_channel_name"].asString()); + } + else + { + childSetTextArg("leaving", "[CURRENT_CHAT]", getString("localchat")); + } + + std::string callee_name = mPayload["session_name"].asString(); + if (callee_name == "anonymous") + { + callee_name = getString("anonymous"); + } + + setTitle(callee_name); + + LLSD callee_id = mPayload["other_user_id"]; + childSetTextArg("calling", "[CALLEE_NAME]", callee_name); + childSetTextArg("connecting", "[CALLEE_NAME]", callee_name); + LLAvatarIconCtrl* icon = getChild("avatar_icon"); + icon->setValue(callee_id); +} + + +//static +void LLOutgoingCallDialog::onCancel(void* user_data) +{ + LLOutgoingCallDialog* self = (LLOutgoingCallDialog*)user_data; + + if (!gIMMgr) + return; + + LLUUID session_id = self->mPayload["session_id"].asUUID(); + gIMMgr->endCall(session_id); + + self->closeFloater(); +} + + +BOOL LLOutgoingCallDialog::postBuild() +{ + BOOL success = LLDockableFloater::postBuild(); + + childSetAction("Cancel", onCancel, this); + + // dock the dialog to the sys well, where other sys messages appear + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + this, getDockTongue(), LLDockControl::TOP, + boost::bind(&LLOutgoingCallDialog::getAllowedRect, this, _1))); + + return success; +} + + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIncomingCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : + LLDockableFloater(NULL, false, payload), + mPayload(payload) +{ +} + +BOOL LLIncomingCallDialog::postBuild() +{ + LLDockableFloater::postBuild(); + + LLSD caller_id = mPayload["caller_id"]; + EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); + + std::string call_type = getString("VoiceInviteP2P"); + std::string caller_name = mPayload["caller_name"].asString(); + if (caller_name == "anonymous") + { + caller_name = getString("anonymous"); + } + + setTitle(caller_name + " " + call_type); + + // If it is not a P2P invite, then it's an AdHoc invite + if ( type != IM_SESSION_P2P_INVITE ) + { + call_type = getString("VoiceInviteAdHoc"); + } + + // check to see if this is an Avaline call + LLUUID session_id = mPayload["session_id"].asUUID(); + bool is_avatar = LLVoiceClient::getInstance()->isParticipantAvatar(session_id); + childSetVisible("Start IM", is_avatar); // no IM for avaline + + LLUICtrl* caller_name_widget = getChild("caller name"); + caller_name_widget->setValue(caller_name + " " + call_type); + LLAvatarIconCtrl* icon = getChild("avatar_icon"); + icon->setValue(caller_id); + + childSetAction("Accept", onAccept, this); + childSetAction("Reject", onReject, this); + childSetAction("Start IM", onStartIM, this); + childSetFocus("Accept"); + + return TRUE; +} + +void LLIncomingCallDialog::getAllowedRect(LLRect& rect) +{ + rect = gViewerWindow->getWorldViewRectScaled(); +} + +void LLIncomingCallDialog::onOpen(const LLSD& key) +{ + // tell the user which voice channel they would be leaving + LLVoiceChannel *voice = LLVoiceChannel::getCurrentVoiceChannel(); + if (voice && !voice->getSessionName().empty()) + { + childSetTextArg("question", "[CURRENT_CHAT]", voice->getSessionName()); + } + else + { + childSetTextArg("question", "[CURRENT_CHAT]", getString("localchat")); + } + + // dock the dialog to the sys well, where other sys messages appear + setDockControl(new LLDockControl(LLBottomTray::getInstance()->getSysWell(), + this, getDockTongue(), LLDockControl::TOP, + boost::bind(&LLIncomingCallDialog::getAllowedRect, this, _1))); +} + +//static +void LLIncomingCallDialog::onAccept(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(0); + self->closeFloater(); +} + +//static +void LLIncomingCallDialog::onReject(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(1); + self->closeFloater(); +} + +//static +void LLIncomingCallDialog::onStartIM(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(2); + self->closeFloater(); +} + +void LLIncomingCallDialog::processCallResponse(S32 response) +{ + if (!gIMMgr) + return; + + LLUUID session_id = mPayload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger(); + bool voice = true; + switch(response) + { + case 2: // start IM: just don't start the voice chat + { + voice = false; + /* FALLTHROUGH */ + } + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + mPayload["session_name"].asString(), + mPayload["caller_id"].asUUID(), + mPayload["session_handle"].asString()); + + if (voice) + { + if (gIMMgr->startCall(session_id)) + { + // always open IM window when connecting to voice + LLIMFloater::show(session_id); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + LLUUID session_id = gIMMgr->addSession( + mPayload["session_name"].asString(), + type, + session_id); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + if (voice) + { + LLSD data; + data["method"] = "accept invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + new LLViewerChatterBoxInvitationAcceptResponder( + session_id, + inv_type)); + } + } + if (voice) + { + break; + } + } + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(gVoiceClient) + { + std::string s = mPayload["session_handle"].asString(); + gVoiceClient->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + NULL); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } +} + +bool inviteUserResponse(const LLSD& notification, const LLSD& response) +{ + if (!gIMMgr) + return false; + + const LLSD& payload = notification["payload"]; + LLUUID session_id = payload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)payload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger(); + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + payload["session_name"].asString(), + payload["caller_id"].asUUID(), + payload["session_handle"].asString(), + payload["session_uri"].asString()); + + if (gIMMgr->startCall(session_id)) + { + // always open IM window when connecting to voice + LLIMFloater::show(session_id); + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + LLUUID session_id = gIMMgr->addSession( + payload["session_name"].asString(), + type, + session_id); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "accept invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + new LLViewerChatterBoxInvitationAcceptResponder( + session_id, + inv_type)); + } + } + break; + case 2: // mute (also implies ignore, so this falls through to the "ignore" case below) + { + // mute the sender of this invite + if (!LLMuteList::getInstance()->isMuted(payload["caller_id"].asUUID())) + { + LLMute mute(payload["caller_id"].asUUID(), payload["caller_name"].asString(), LLMute::AGENT); + LLMuteList::getInstance()->add(mute); + } + } + /* FALLTHROUGH */ + + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(gVoiceClient) + { + std::string s = payload["session_handle"].asString(); + gVoiceClient->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + NULL); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + break; + } + + return false; +} + +// +// Member Functions +// + +LLIMMgr::LLIMMgr() : + mIMReceived(FALSE) +{ + mPendingInvitations = LLSD::emptyMap(); + mPendingAgentListUpdates = LLSD::emptyMap(); +} + +// Add a message to a session. +void LLIMMgr::addMessage( + const LLUUID& session_id, + const LLUUID& target_id, + const std::string& from, + const std::string& msg, + const std::string& session_name, + EInstantMessage dialog, + U32 parent_estate_id, + const LLUUID& region_id, + const LLVector3& position, + bool link_name) // If this is true, then we insert the name and link it to a profile +{ + LLUUID other_participant_id = target_id; + + // don't process muted IMs + if (LLMuteList::getInstance()->isMuted( + other_participant_id, + LLMute::flagTextChat) && !LLMuteList::getInstance()->isLinden(from)) + { + return; + } + + LLFloaterIMPanel* floater; + LLUUID new_session_id = session_id; + if (new_session_id.isNull()) + { + //no session ID...compute new one + new_session_id = computeSessionID(dialog, other_participant_id); + } + + //*NOTE session_name is empty in case of incoming P2P sessions + std::string fixed_session_name = from; + if(!session_name.empty() && session_name.size()>1) + { + fixed_session_name = session_name; + } + + bool new_session = !hasSession(new_session_id); + if (new_session) + { + LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id); + } + + floater = findFloaterBySession(new_session_id); + if (!floater) + { + floater = findFloaterBySession(other_participant_id); + if (floater) + { + llinfos << "found the IM session " << session_id + << " by participant " << other_participant_id << llendl; + } + } + + // create IM window as necessary + if(!floater) + { + floater = createFloater( + new_session_id, + other_participant_id, + fixed_session_name, + dialog, + FALSE); + } + + if (new_session) + { + // When we get a new IM, and if you are a god, display a bit + // of information about the source. This is to help liaisons + // when answering questions. + if(gAgent.isGodlike()) + { + // *TODO:translate (low priority, god ability) + std::ostringstream bonus_info; + bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " " + << parent_estate_id + << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") + << ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : ""); + + // once we have web-services (or something) which returns + // information about a region id, we can print this out + // and even have it link to map-teleport or something. + //<< "*** region_id: " << region_id << std::endl + //<< "*** position: " << position << std::endl; + + floater->addHistoryLine(bonus_info.str(), LLUIColorTable::instance().getColor("SystemChatColor")); + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); + } + + make_ui_sound("UISndNewIncomingIMSession"); + } + + // now add message to floater + bool is_from_system = target_id.isNull() || (from == SYSTEM_FROM); + const LLColor4& color = ( is_from_system ? + LLUIColorTable::instance().getColor("SystemChatColor") : + LLUIColorTable::instance().getColor("IMChatColor")); + if ( !link_name ) + { + floater->addHistoryLine(msg,color); // No name to prepend, so just add the message normally + } + else + { + floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message + } + + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); + + if( !LLFloaterReg::instanceVisible("communicate") && !floater->getVisible()) + { + LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(); + + //if the IM window is not open and the floater is not visible (i.e. not torn off) + LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater(); + + // select the newly added floater (or the floater with the new line added to it). + // it should be there. + chat_floater->selectFloater(floater); + + //there was a previously unseen IM, make that old tab flashing + //it is assumed that the most recently unseen IM tab is the one current selected/active + if ( previouslyActiveFloater && getIMReceived() ) + { + chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE); + } + + //notify of a new IM + notifyNewIM(); + } +} + +void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args) +{ + LLUIString message; + + // null session id means near me (chat history) + if (session_id.isNull()) + { + message = LLTrans::getString(message_name); + message.setArgs(args); + + LLChat chat(message); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChatHistory(chat); + } + else // going to IM session + { + if (hasSession(session_id)) + { + message = LLTrans::getString(message_name + "-im"); + message.setArgs(args); + gIMMgr->addMessage(session_id, LLUUID::null, SYSTEM_FROM, message.getString()); + } + } +} + +void LLIMMgr::notifyNewIM() +{ + if(!LLFloaterReg::instanceVisible("communicate")) + { + mIMReceived = TRUE; + } +} + +S32 LLIMMgr::getNumberOfUnreadIM() +{ + std::map::iterator it; + + S32 num = 0; + for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it) + { + num += (*it).second->mNumUnread; + } + + return num; +} + +void LLIMMgr::clearNewIMNotification() +{ + mIMReceived = FALSE; +} + +BOOL LLIMMgr::getIMReceived() const +{ + return mIMReceived; +} + +LLUUID LLIMMgr::addP2PSession(const std::string& name, + const LLUUID& other_participant_id, + const std::string& voice_session_handle, + const std::string& caller_uri) +{ + LLUUID session_id = addSession(name, IM_NOTHING_SPECIAL, other_participant_id); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + LLVoiceChannelP2P* voice_channel = dynamic_cast(speaker_mgr->getVoiceChannel()); + if (voice_channel) + { + voice_channel->setSessionHandle(voice_session_handle, caller_uri); + } + } + return session_id; +} + +// This adds a session to the talk view. The name is the local name of +// the session, dialog specifies the type of session. If the session +// exists, it is brought forward. Specifying id = NULL results in an +// im session to everyone. Returns the uuid of the session. +LLUUID LLIMMgr::addSession( + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id) +{ + LLDynamicArray ids; + ids.put(other_participant_id); + return addSession(name, dialog, other_participant_id, ids); +} + +// Adds a session using the given session_id. If the session already exists +// the dialog type is assumed correct. Returns the uuid of the session. +LLUUID LLIMMgr::addSession( + const std::string& name, + EInstantMessage dialog, + const LLUUID& other_participant_id, + const LLDynamicArray& ids) +{ + if (0 == ids.getLength()) + { + return LLUUID::null; + } + + LLUUID session_id = computeSessionID(dialog,other_participant_id); + + bool new_session = !LLIMModel::getInstance()->findIMSession(session_id); + + if (new_session) + { + LLIMModel::getInstance()->newSession(session_id, name, dialog, other_participant_id, ids); + } + + + //*TODO remove this "floater" thing when Communicate Floater's gone + LLFloaterIMPanel* floater = findFloaterBySession(session_id); + if(!floater) + { + // On creation, use the first element of ids as the + // "other_participant_id" + floater = createFloater( + session_id, + other_participant_id, + name, + dialog, + TRUE, + ids); + } + + //we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions + if (!new_session) return session_id; + + noteOfflineUsers(session_id, floater, ids); + + // Only warn for regular IMs - not group IMs + if( dialog == IM_NOTHING_SPECIAL ) + { + noteMutedUsers(session_id, floater, ids); + } + + return session_id; +} + +bool LLIMMgr::leaveSession(const LLUUID& session_id) +{ + LLIMModel::LLIMSession* im_session = LLIMModel::getInstance()->findIMSession(session_id); + if (!im_session) return false; + + LLIMModel::getInstance()->sendLeaveSession(session_id, im_session->mOtherParticipantID); + gIMMgr->removeSession(session_id); + return true; +} + +// Removes data associated with a particular session specified by session_id +void LLIMMgr::removeSession(const LLUUID& session_id) +{ + llassert_always(hasSession(session_id)); + + //*TODO remove this floater thing when Communicate Floater is being deleted (IB) + LLFloaterIMPanel* floater = findFloaterBySession(session_id); + if(floater) + { + mFloaters.erase(floater->getHandle()); + LLFloaterChatterBox::getInstance()->removeFloater(floater); + } + + clearPendingInvitation(session_id); + clearPendingAgentListUpdates(session_id); + + LLIMModel::getInstance()->clearSession(session_id); + + notifyObserverSessionRemoved(session_id); +} + +void LLIMMgr::inviteToSession( + const LLUUID& session_id, + const std::string& session_name, + const LLUUID& caller_id, + const std::string& caller_name, + EInstantMessage type, + EInvitationType inv_type, + const std::string& session_handle, + const std::string& session_uri) +{ + //ignore invites from muted residents + if (LLMuteList::getInstance()->isMuted(caller_id)) + { + return; + } + + std::string notify_box_type; + + BOOL ad_hoc_invite = FALSE; + if(type == IM_SESSION_P2P_INVITE) + { + //P2P is different...they only have voice invitations + notify_box_type = "VoiceInviteP2P"; + } + else if ( gAgent.isInGroup(session_id) ) + { + //only really old school groups have voice invitations + notify_box_type = "VoiceInviteGroup"; + } + else if ( inv_type == INVITATION_TYPE_VOICE ) + { + //else it's an ad-hoc + //and a voice ad-hoc + notify_box_type = "VoiceInviteAdHoc"; + ad_hoc_invite = TRUE; + } + else if ( inv_type == INVITATION_TYPE_IMMEDIATE ) + { + notify_box_type = "InviteAdHoc"; + ad_hoc_invite = TRUE; + } + + LLSD payload; + payload["session_id"] = session_id; + payload["session_name"] = session_name; + payload["caller_id"] = caller_id; + payload["caller_name"] = caller_name; + payload["type"] = type; + payload["inv_type"] = inv_type; + payload["session_handle"] = session_handle; + payload["session_uri"] = session_uri; + payload["notify_box_type"] = notify_box_type; + + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(session_id); + if (channelp && channelp->callStarted()) + { + // you have already started a call to the other user, so just accept the invite + LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 0); + return; + } + + if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite) + { + // is the inviter a friend? + if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL) + { + // if not, and we are ignoring voice invites from non-friends + // then silently decline + if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly")) + { + // invite not from a friend, so decline + LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1); + return; + } + } + } + + if ( !mPendingInvitations.has(session_id.asString()) ) + { + if (caller_name.empty()) + { + gCacheName->get(caller_id, FALSE, boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3, _4)); + } + else + { + if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") + { + LLFloaterReg::showInstance("incoming_call", payload, TRUE); + } + else + { + LLSD args; + args["NAME"] = caller_name; + args["GROUP"] = session_name; + + LLNotifications::instance().add(notify_box_type, args, payload, &inviteUserResponse); + } + } + mPendingInvitations[session_id.asString()] = LLSD(); + } +} + +void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +{ + payload["caller_name"] = first + " " + last; + payload["session_name"] = payload["caller_name"].asString(); + + std::string notify_box_type = payload["notify_box_type"].asString(); + + if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") + { + LLFloaterReg::showInstance("incoming_call", payload, TRUE); + } + else + { + LLSD args; + args["NAME"] = payload["caller_name"].asString(); + + LLNotifications::instance().add( + payload["notify_box_type"].asString(), + args, + payload, + &inviteUserResponse); + } +} + +void LLIMMgr::disconnectAllSessions() +{ + LLFloaterIMPanel* floater = NULL; + std::set >::iterator handle_it; + for(handle_it = mFloaters.begin(); + handle_it != mFloaters.end(); + ) + { + floater = (LLFloaterIMPanel*)handle_it->get(); + + // MUST do this BEFORE calling floater->onClose() because that may remove the item from the set, causing the subsequent increment to crash. + ++handle_it; + + if (floater) + { + floater->setEnabled(FALSE); + floater->closeFloater(TRUE); + } + } +} + + +// This method returns the im panel corresponding to the uuid +// provided. The uuid can either be a session id or an agent +// id. Returns NULL if there is no matching panel. +LLFloaterIMPanel* LLIMMgr::findFloaterBySession(const LLUUID& session_id) +{ + LLFloaterIMPanel* rv = NULL; + std::set >::iterator handle_it; + for(handle_it = mFloaters.begin(); + handle_it != mFloaters.end(); + ++handle_it) + { + rv = (LLFloaterIMPanel*)handle_it->get(); + if(rv && session_id == rv->getSessionID()) + { + break; + } + rv = NULL; + } + return rv; +} + + +BOOL LLIMMgr::hasSession(const LLUUID& session_id) +{ + return LLIMModel::getInstance()->findIMSession(session_id) != NULL; +} + +void LLIMMgr::clearPendingInvitation(const LLUUID& session_id) +{ + if ( mPendingInvitations.has(session_id.asString()) ) + { + mPendingInvitations.erase(session_id.asString()); + } +} + +void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body) +{ + LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + if ( im_floater ) + { + im_floater->processAgentListUpdates(body); + } + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->updateSpeakers(body); + } + else + { + //we don't have a speaker manager yet..something went wrong + //we are probably receiving an update here before + //a start or an acceptance of an invitation. Race condition. + gIMMgr->addPendingAgentListUpdates( + session_id, + body); + } +} + +LLSD LLIMMgr::getPendingAgentListUpdates(const LLUUID& session_id) +{ + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + return mPendingAgentListUpdates[session_id.asString()]; + } + else + { + return LLSD(); + } +} + +void LLIMMgr::addPendingAgentListUpdates( + const LLUUID& session_id, + const LLSD& updates) +{ + LLSD::map_const_iterator iter; + + if ( !mPendingAgentListUpdates.has(session_id.asString()) ) + { + //this is a new agent list update for this session + mPendingAgentListUpdates[session_id.asString()] = LLSD::emptyMap(); + } + + if ( + updates.has("agent_updates") && + updates["agent_updates"].isMap() && + updates.has("updates") && + updates["updates"].isMap() ) + { + //new school update + LLSD update_types = LLSD::emptyArray(); + LLSD::array_iterator array_iter; + + update_types.append("agent_updates"); + update_types.append("updates"); + + for ( + array_iter = update_types.beginArray(); + array_iter != update_types.endArray(); + ++array_iter) + { + //we only want to include the last update for a given agent + for ( + iter = updates[array_iter->asString()].beginMap(); + iter != updates[array_iter->asString()].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()][array_iter->asString()][iter->first] = + iter->second; + } + } + } + else if ( + updates.has("updates") && + updates["updates"].isMap() ) + { + //old school update where the SD contained just mappings + //of agent_id -> "LEAVE"/"ENTER" + + //only want to keep last update for each agent + for ( + iter = updates["updates"].beginMap(); + iter != updates["updates"].endMap(); + ++iter) + { + mPendingAgentListUpdates[session_id.asString()]["updates"][iter->first] = + iter->second; + } + } +} + +void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) +{ + if ( mPendingAgentListUpdates.has(session_id.asString()) ) + { + mPendingAgentListUpdates.erase(session_id.asString()); + } +} + +void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionAdded(session_id, name, other_participant_id); + } +} + +void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionRemoved(session_id); + } +} + +void LLIMMgr::notifyObserverSessionIDUpdated( const LLUUID& old_session_id, const LLUUID& new_session_id ) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionIDUpdated(old_session_id, new_session_id); + } + +} + +void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer) +{ + mSessionObservers.push_back(observer); +} + +void LLIMMgr::removeSessionObserver(LLIMSessionObserver *observer) +{ + mSessionObservers.remove(observer); +} + +bool LLIMMgr::startCall(const LLUUID& session_id) +{ + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; + + voice_channel->activate(); + return true; +} + +bool LLIMMgr::endCall(const LLUUID& session_id) +{ + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id); + if (!voice_channel) return false; + + voice_channel->deactivate(); + return true; +} + +// create a floater and update internal representation for +// consistency. Returns the pointer, caller (the class instance since +// it is a private method) is not responsible for deleting the +// pointer. Add the floater to this but do not select it. +LLFloaterIMPanel* LLIMMgr::createFloater( + const LLUUID& session_id, + const LLUUID& other_participant_id, + const std::string& session_label, + EInstantMessage dialog, + BOOL user_initiated, + const LLDynamicArray& ids) +{ + if (session_id.isNull()) + { + llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl; + } + + llinfos << "LLIMMgr::createFloater: from " << other_participant_id + << " in session " << session_id << llendl; + LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, + session_id, + other_participant_id, + ids, + dialog); + LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; + LLFloaterChatterBox::getInstance()->addFloater(floater, FALSE, i_pt); + mFloaters.insert(floater->getHandle()); + return floater; +} + +void LLIMMgr::noteOfflineUsers( + const LLUUID& session_id, + LLFloaterIMPanel* floater, + const LLDynamicArray& ids) +{ + S32 count = ids.count(); + if(count == 0) + { + const std::string& only_user = LLTrans::getString("only_user_message"); + if (floater) + { + floater->addHistoryLine(only_user, LLUIColorTable::instance().getColor("SystemChatColor")); + } + LLIMModel::getInstance()->addMessage(session_id, SYSTEM_FROM, LLUUID::null, only_user); + } + else + { + const LLRelationship* info = NULL; + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLIMModel& im_model = LLIMModel::instance(); + for(S32 i = 0; i < count; ++i) + { + info = at.getBuddyInfo(ids.get(i)); + std::string first, last; + if(info && !info->isOnline() + && gCacheName->getName(ids.get(i), first, last)) + { + LLUIString offline = LLTrans::getString("offline_message"); + offline.setArg("[FIRST]", first); + offline.setArg("[LAST]", last); + im_model.proccessOnlineOfflineNotification(session_id, offline); + } + } + } +} + +void LLIMMgr::noteMutedUsers(const LLUUID& session_id, LLFloaterIMPanel* floater, + const LLDynamicArray& ids) +{ + // Don't do this if we don't have a mute list. + LLMuteList *ml = LLMuteList::getInstance(); + if( !ml ) + { + return; + } + + S32 count = ids.count(); + if(count > 0) + { + LLIMModel* im_model = LLIMModel::getInstance(); + + for(S32 i = 0; i < count; ++i) + { + if( ml->isMuted(ids.get(i)) ) + { + LLUIString muted = LLTrans::getString("muted_message"); + + //*TODO remove this "floater" thing when Communicate Floater's gone + floater->addHistoryLine(muted); + + im_model->addMessage(session_id, SYSTEM_FROM, LLUUID::null, muted); + break; + } + } + } +} + +void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info) +{ + processIMTypingCore(im_info, TRUE); +} + +void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info) +{ + processIMTypingCore(im_info, FALSE); +} + +void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing) +{ + LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID); + LLFloaterIMPanel* floater = findFloaterBySession(session_id); + if (floater) + { + floater->processIMTyping(im_info, typing); + } + + LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + if ( im_floater ) + { + im_floater->processIMTyping(im_info, typing); + } +} + +class LLViewerChatterBoxSessionStartReply : public LLHTTPNode +{ +public: + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); + desc.postAPI(); + desc.input( + "{\"client_session_id\": UUID, \"session_id\": UUID, \"success\" boolean, \"reason\": string"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD body; + LLUUID temp_session_id; + LLUUID session_id; + bool success; + + body = input["body"]; + success = body["success"].asBoolean(); + temp_session_id = body["temp_session_id"].asUUID(); + + if ( success ) + { + session_id = body["session_id"].asUUID(); + + LLIMModel::getInstance()->processSessionInitializedReply(temp_session_id, session_id); + + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(session_id); + if (speaker_mgr) + { + speaker_mgr->setSpeakers(body); + speaker_mgr->updateSpeakers(gIMMgr->getPendingAgentListUpdates(session_id)); + } + + LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); + if (floaterp) + { + if ( body.has("session_info") ) + { + floaterp->processSessionUpdate(body["session_info"]); + } + } + + LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + if ( im_floater ) + { + if ( body.has("session_info") ) + { + im_floater->processSessionUpdate(body["session_info"]); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } + else + { + //throw an error dialog and close the temp session's floater + gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id); + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + } +}; + +class LLViewerChatterBoxSessionEventReply : public LLHTTPNode +{ +public: + virtual void describe(Description& desc) const + { + desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); + desc.postAPI(); + desc.input( + "{\"event\": string, \"reason\": string, \"success\": boolean, \"session_id\": UUID"); + desc.source(__FILE__, __LINE__); + } + + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + bool success; + + LLSD body = input["body"]; + success = body["success"].asBoolean(); + session_id = body["session_id"].asUUID(); + + if ( !success ) + { + //throw an error dialog + gIMMgr->showSessionEventError( + body["event"].asString(), + body["error"].asString(), + session_id); + } + } +}; + +class LLViewerForceCloseChatterBoxSession: public LLHTTPNode +{ +public: + virtual void post(ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id; + std::string reason; + + session_id = input["body"]["session_id"].asUUID(); + reason = input["body"]["reason"].asString(); + + gIMMgr->showSessionForceClose(reason, session_id); + } +}; + +class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + const LLUUID& session_id = input["body"]["session_id"].asUUID(); + gIMMgr->processAgentListUpdates(session_id, input["body"]); + } +}; + +class LLViewerChatterBoxSessionUpdate : public LLHTTPNode +{ +public: + virtual void post( + ResponsePtr responder, + const LLSD& context, + const LLSD& input) const + { + LLUUID session_id = input["body"]["session_id"].asUUID(); + LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id); + if (floaterp) + { + floaterp->processSessionUpdate(input["body"]["info"]); + } + LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); + if ( im_floater ) + { + im_floater->processSessionUpdate(input["body"]["info"]); + } + } +}; + + +class LLViewerChatterBoxInvitation : public LLHTTPNode +{ +public: + + virtual void post( + ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + //for backwards compatiblity reasons...we need to still + //check for 'text' or 'voice' invitations...bleh + if ( input["body"].has("instantmessage") ) + { + LLSD message_params = + input["body"]["instantmessage"]["message_params"]; + + //do something here to have the IM invite behave + //just like a normal IM + //this is just replicated code from process_improved_im + //and should really go in it's own function -jwolk + if (gNoRender) + { + return; + } + LLChat chat; + + std::string message = message_params["message"].asString(); + std::string name = message_params["from_name"].asString(); + LLUUID from_id = message_params["from_id"].asUUID(); + LLUUID session_id = message_params["id"].asUUID(); + std::vector bin_bucket = message_params["data"]["binary_bucket"].asBinary(); + U8 offline = (U8)message_params["offline"].asInteger(); + + time_t timestamp = + (time_t) message_params["timestamp"].asInteger(); + + BOOL is_busy = gAgent.getBusy(); + BOOL is_muted = LLMuteList::getInstance()->isMuted( + from_id, + name, + LLMute::flagTextChat); + + BOOL is_linden = LLMuteList::getInstance()->isLinden(name); + std::string separator_string(": "); + + chat.mMuted = is_muted && !is_linden; + chat.mFromID = from_id; + chat.mFromName = name; + + if (!is_linden && (is_busy || is_muted)) + { + return; + } + + // standard message, not from system + std::string saved; + if(offline == IM_OFFLINE) + { + saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); + } + std::string buffer = saved + message; + + BOOL is_this_agent = FALSE; + if(from_id == gAgentID) + { + is_this_agent = TRUE; + } + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + std::string((char*)&bin_bucket[0]), + IM_SESSION_INVITE, + message_params["parent_estate_id"].asInteger(), + message_params["region_id"].asUUID(), + ll_vector3_from_sd(message_params["position"]), + true); + + chat.mText = std::string("IM: ") + name + separator_string + saved + message; + LLFloaterChat::addChat(chat, TRUE, is_this_agent); + + //K now we want to accept the invitation + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + if ( url != "" ) + { + LLSD data; + data["method"] = "accept invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + new LLViewerChatterBoxInvitationAcceptResponder( + session_id, + LLIMMgr::INVITATION_TYPE_INSTANT_MESSAGE)); + } + } //end if invitation has instant message + else if ( input["body"].has("voice") ) + { + if (gNoRender) + { + return; + } + + if(!LLVoiceClient::voiceEnabled()) + { + // Don't display voice invites unless the user has voice enabled. + return; + } + + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_VOICE); + } + else if ( input["body"].has("immediate") ) + { + gIMMgr->inviteToSession( + input["body"]["session_id"].asUUID(), + input["body"]["session_name"].asString(), + input["body"]["from_id"].asUUID(), + input["body"]["from_name"].asString(), + IM_SESSION_INVITE, + LLIMMgr::INVITATION_TYPE_IMMEDIATE); + } + } +}; + +LLHTTPRegistration + gHTTPRegistrationMessageChatterboxsessionstartreply( + "/message/ChatterBoxSessionStartReply"); + +LLHTTPRegistration + gHTTPRegistrationMessageChatterboxsessioneventreply( + "/message/ChatterBoxSessionEventReply"); + +LLHTTPRegistration + gHTTPRegistrationMessageForceclosechatterboxsession( + "/message/ForceCloseChatterBoxSession"); + +LLHTTPRegistration + gHTTPRegistrationMessageChatterboxsessionagentlistupdates( + "/message/ChatterBoxSessionAgentListUpdates"); + +LLHTTPRegistration + gHTTPRegistrationMessageChatterBoxSessionUpdate( + "/message/ChatterBoxSessionUpdate"); + +LLHTTPRegistration + gHTTPRegistrationMessageChatterBoxInvitation( + "/message/ChatterBoxInvitation"); + diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 173f2634aa..a6a5ecb8e7 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1,5146 +1,5146 @@ -/** - * @file llinventorybridge.cpp - * @brief Implementation of the Inventory-Folder-View-Bridge classes. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llinventorybridge.h" - -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llavataractions.h" -#include "llfloatercustomize.h" -#include "llfloaterinventory.h" -#include "llfloateropenobject.h" -#include "llfloaterreg.h" -#include "llfloaterworldmap.h" -#include "llfriendcard.h" -#include "llgesturemgr.h" -#include "llimfloater.h" -#include "llimview.h" -#include "llinventoryclipboard.h" -#include "llinventoryfunctions.h" -#include "llinventorymodel.h" -#include "llinventorypanel.h" -#include "llpreviewanim.h" -#include "llpreviewgesture.h" -#include "llpreviewtexture.h" -#include "llselectmgr.h" -#include "llsidetray.h" -#include "lltrans.h" -#include "llviewerassettype.h" -#include "llviewermessage.h" -#include "llviewerobjectlist.h" -#include "llviewerwindow.h" -#include "llvoavatarself.h" -#include "llwearablelist.h" - -using namespace LLOldEvents; - -// Helpers -// bug in busy count inc/dec right now, logic is complex... do we really need it? -void inc_busy_count() -{ -// gViewerWindow->getWindow()->incBusyCount(); -// check balance of these calls if this code is changed to ever actually -// *do* something! -} -void dec_busy_count() -{ -// gViewerWindow->getWindow()->decBusyCount(); -// check balance of these calls if this code is changed to ever actually -// *do* something! -} - -// Function declarations -void wear_add_inventory_item_on_avatar(LLInventoryItem* item); -void remove_inventory_category_from_avatar(LLInventoryCategory* category); -void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); -bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); - -std::string ICON_NAME[ICON_NAME_COUNT] = -{ - "Inv_Texture", - "Inv_Sound", - "Inv_CallingCard", - "Inv_CallingCard", - "Inv_Landmark", - "Inv_Landmark", - "Inv_Script", - "Inv_Clothing", - "Inv_Object", - "Inv_Object", - "Inv_Notecard", - "Inv_Skin", - "Inv_Snapshot", - - "Inv_BodyShape", - "Inv_Skin", - "Inv_Hair", - "Inv_Eye", - "Inv_Shirt", - "Inv_Pants", - "Inv_Shoe", - "Inv_Socks", - "Inv_Jacket", - "Inv_Gloves", - "Inv_Undershirt", - "Inv_Underpants", - "Inv_Skirt", - "Inv_Alpha", - "Inv_Tattoo", - - "Inv_Animation", - "Inv_Gesture", - - "inv_item_linkitem.tga", - "inv_item_linkfolder.tga" -}; - -// +=================================================+ -// | LLInvFVBridge | -// +=================================================+ - -LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : -mUUID(uuid), mInvType(LLInventoryType::IT_NONE) -{ - mInventoryPanel = inventory->getHandle(); -} - -const std::string& LLInvFVBridge::getName() const -{ - LLInventoryObject* obj = getInventoryObject(); - if(obj) - { - return obj->getName(); - } - return LLStringUtil::null; -} - -const std::string& LLInvFVBridge::getDisplayName() const -{ - return getName(); -} - -// Folders have full perms -PermissionMask LLInvFVBridge::getPermissionMask() const -{ - - return PERM_ALL; -} - -// virtual -LLFolderType::EType LLInvFVBridge::getPreferredType() const -{ - return LLFolderType::FT_NONE; -} - - -// Folders don't have creation dates. -time_t LLInvFVBridge::getCreationDate() const -{ - return 0; -} - -// Can be destoryed (or moved to trash) -BOOL LLInvFVBridge::isItemRemovable() -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - if(model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return TRUE; - } - return FALSE; -} - -// Can be moved to another folder -BOOL LLInvFVBridge::isItemMovable() const -{ - return TRUE; -} - -/*virtual*/ -/** - * @brief Adds this item into clipboard storage - */ -void LLInvFVBridge::cutToClipboard() -{ - if(isItemMovable()) - { - LLInventoryClipboard::instance().cut(mUUID); - } -} -// *TODO: make sure this does the right thing -void LLInvFVBridge::showProperties() -{ - LLSD key; - key["id"] = mUUID; - LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); - - // Disable old properties floater; this is replaced by the sidepanel. - /* - LLFloaterReg::showInstance("properties", mUUID); - */ -} - -void LLInvFVBridge::removeBatch(LLDynamicArray& batch) -{ - // Deactivate gestures when moving them into Trash - LLInvFVBridge* bridge; - LLInventoryModel* model = getInventoryModel(); - LLViewerInventoryItem* item = NULL; - LLViewerInventoryCategory* cat = NULL; - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - S32 count = batch.count(); - S32 i,j; - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch.get(i)); - if(!bridge || !bridge->isItemRemovable()) continue; - item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); - if (item) - { - if(LLAssetType::AT_GESTURE == item->getType()) - { - LLGestureManager::instance().deactivateGesture(item->getUUID()); - } - } - } - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch.get(i)); - if(!bridge || !bridge->isItemRemovable()) continue; - cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); - if (cat) - { - gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE ); - for (j=0; jgetType()) - { - LLGestureManager::instance().deactivateGesture(descendent_items[j]->getUUID()); - } - } - } - } - removeBatchNoCheck(batch); -} - -void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray& batch) -{ - // this method moves a bunch of items and folders to the trash. As - // per design guidelines for the inventory model, the message is - // built and the accounting is performed first. After all of that, - // we call LLInventoryModel::moveObject() to move everything - // around. - LLInvFVBridge* bridge; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLMessageSystem* msg = gMessageSystem; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - LLViewerInventoryItem* item = NULL; - LLViewerInventoryCategory* cat = NULL; - std::vector move_ids; - LLInventoryModel::update_map_t update; - bool start_new_message = true; - S32 count = batch.count(); - S32 i; - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch.get(i)); - if(!bridge || !bridge->isItemRemovable()) continue; - item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); - if(item) - { - if(item->getParentUUID() == trash_id) continue; - move_ids.push_back(item->getUUID()); - LLPreview::hide(item->getUUID()); - --update[item->getParentUUID()]; - ++update[trash_id]; - if(start_new_message) - { - start_new_message = false; - msg->newMessageFast(_PREHASH_MoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOLFast(_PREHASH_Stamp, TRUE); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, item->getUUID()); - msg->addUUIDFast(_PREHASH_FolderID, trash_id); - msg->addString("NewName", NULL); - if(msg->isSendFullFast(_PREHASH_InventoryData)) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - } - } - if(!start_new_message) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - for(i = 0; i < count; ++i) - { - bridge = (LLInvFVBridge*)(batch.get(i)); - if(!bridge || !bridge->isItemRemovable()) continue; - cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); - if(cat) - { - if(cat->getParentUUID() == trash_id) continue; - move_ids.push_back(cat->getUUID()); - --update[cat->getParentUUID()]; - ++update[trash_id]; - if(start_new_message) - { - start_new_message = false; - msg->newMessageFast(_PREHASH_MoveInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addBOOL("Stamp", TRUE); - } - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID()); - msg->addUUIDFast(_PREHASH_ParentID, trash_id); - if(msg->isSendFullFast(_PREHASH_InventoryData)) - { - start_new_message = true; - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - update.clear(); - } - } - } - if(!start_new_message) - { - gAgent.sendReliableMessage(); - gInventory.accountForUpdate(update); - } - - // move everything. - std::vector::iterator it = move_ids.begin(); - std::vector::iterator end = move_ids.end(); - for(; it != end; ++it) - { - gInventory.moveObject((*it), trash_id); - } - - // notify inventory observers. - model->notifyObservers(); -} - -BOOL LLInvFVBridge::isClipboardPasteable() const -{ - if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) - { - return FALSE; - } - LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return FALSE; - } - - const LLUUID &agent_id = gAgent.getID(); - - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); - for(S32 i = 0; i < count; i++) - { - const LLUUID &item_id = objects.get(i); - - // Can't paste folders - const LLInventoryCategory *cat = model->getCategory(item_id); - if (cat) - { - return FALSE; - } - - const LLInventoryItem *item = model->getItem(item_id); - if (item) - { - if (!item->getPermissions().allowCopyBy(agent_id)) - { - return FALSE; - } - } - } - return TRUE; -} - -BOOL LLInvFVBridge::isClipboardPasteableAsLink() const -{ - if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) - { - return FALSE; - } - const LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return FALSE; - } - - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); - for(S32 i = 0; i < count; i++) - { - const LLInventoryItem *item = model->getItem(objects.get(i)); - if (item) - { - if (!LLAssetType::lookupCanLink(item->getActualType())) - { - return FALSE; - } - } - const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i)); - if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - return FALSE; - } - } - return TRUE; -} - -void hide_context_entries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries) -{ - const LLView::child_list_t *list = menu.getChildList(); - - LLView::child_list_t::const_iterator itor; - for (itor = list->begin(); itor != list->end(); ++itor) - { - std::string name = (*itor)->getName(); - - // descend into split menus: - LLMenuItemBranchGL* branchp = dynamic_cast(*itor); - if ((name == "More") && branchp) - { - hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); - } - - - bool found = false; - std::vector::const_iterator itor2; - for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2) - { - if (*itor2 == name) - { - found = true; - } - } - if (!found) - { - (*itor)->setVisible(FALSE); - } - else - { - for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) - { - if (*itor2 == name) - { - (*itor)->setEnabled(FALSE); - } - } - } - } -} - -// Helper for commonly-used entries -void LLInvFVBridge::getClipboardEntries(bool show_asset_id, - std::vector &items, - std::vector &disabled_items, U32 flags) -{ - items.push_back(std::string("Rename")); - if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Rename")); - } - - if (show_asset_id) - { - items.push_back(std::string("Copy Asset UUID")); - if ( (! ( isItemPermissive() || gAgent.isGodlike() ) ) - || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Copy Asset UUID")); - } - } - - items.push_back(std::string("Copy Separator")); - - items.push_back(std::string("Copy")); - if (!isItemCopyable()) - { - disabled_items.push_back(std::string("Copy")); - } - - items.push_back(std::string("Paste")); - if (!isClipboardPasteable() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Paste")); - } - - items.push_back(std::string("Paste As Link")); - if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Paste As Link")); - } - items.push_back(std::string("Paste Separator")); - - items.push_back(std::string("Delete")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } - - // If multiple items are selected, disable properties (if it exists). - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Properties")); - } -} - -void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - if(isInTrash()) - { - items.push_back(std::string("PurgeItem")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("PurgeItem")); - } - items.push_back(std::string("RestoreItem")); - } - else - { - items.push_back(std::string("Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - hide_context_entries(menu, items, disabled_items); -} - -// *TODO: remove this -BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const -{ - BOOL rv = FALSE; - - const LLInventoryObject* obj = getInventoryObject(); - - if(obj) - { - *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); - if(*type == DAD_NONE) - { - return FALSE; - } - - *id = obj->getUUID(); - //object_ids.put(obj->getUUID()); - - if (*type == DAD_CATEGORY) - { - gInventory.startBackgroundFetch(obj->getUUID()); - } - - rv = TRUE; - } - - return rv; -} - -LLInventoryObject* LLInvFVBridge::getInventoryObject() const -{ - LLInventoryObject* obj = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - obj = (LLInventoryObject*)model->getObject(mUUID); - } - return obj; -} - -LLInventoryModel* LLInvFVBridge::getInventoryModel() const -{ - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - return panel ? panel->getModel() : NULL; -} - -BOOL LLInvFVBridge::isInTrash() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return model->isObjectDescendentOf(mUUID, trash_id); -} - -BOOL LLInvFVBridge::isLinkedObjectInTrash() const -{ - if (isInTrash()) return TRUE; - - const LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); - } - return FALSE; -} - -BOOL LLInvFVBridge::isAgentInventory() const -{ - const LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - if(gInventory.getRootFolderID() == mUUID) return TRUE; - return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); -} - -BOOL LLInvFVBridge::isCOFFolder() const -{ - const LLInventoryModel* model = getInventoryModel(); - if(!model) return TRUE; - const LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - if (mUUID == cof_id || model->isObjectDescendentOf(mUUID, cof_id)) - { - return TRUE; - } - return FALSE; -} - -BOOL LLInvFVBridge::isItemPermissive() const -{ - return FALSE; -} - -// static -void LLInvFVBridge::changeItemParent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent, - BOOL restamp) -{ - if(item->getParentUUID() != new_parent) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent); - new_item->updateParentOnServer(restamp); - model->updateItem(new_item); - model->notifyObservers(); - } -} - -// static -void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent, - BOOL restamp) -{ - if(cat->getParentUUID() != new_parent) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); - } -} - - -const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type) -{ - const std::string rv= LLInventoryType::lookup(inv_type); - if(rv.empty()) - { - return std::string(""); - } - return rv; -} - -LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, - LLAssetType::EType actual_asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - const LLUUID& uuid, - U32 flags) -{ - LLInvFVBridge* new_listener = NULL; - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLTextureBridge(inventory, uuid, inv_type); - break; - - case LLAssetType::AT_SOUND: - if(!(inv_type == LLInventoryType::IT_SOUND)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLSoundBridge(inventory, uuid); - break; - - case LLAssetType::AT_LANDMARK: - if(!(inv_type == LLInventoryType::IT_LANDMARK)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLandmarkBridge(inventory, uuid, flags); - break; - - case LLAssetType::AT_CALLINGCARD: - if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLCallingCardBridge(inventory, uuid); - break; - - case LLAssetType::AT_SCRIPT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLScriptBridge(inventory, uuid); - break; - - case LLAssetType::AT_OBJECT: - if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); - break; - - case LLAssetType::AT_NOTECARD: - if(!(inv_type == LLInventoryType::IT_NOTECARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLNotecardBridge(inventory, uuid); - break; - - case LLAssetType::AT_ANIMATION: - if(!(inv_type == LLInventoryType::IT_ANIMATION)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLAnimationBridge(inventory, uuid); - break; - - case LLAssetType::AT_GESTURE: - if(!(inv_type == LLInventoryType::IT_GESTURE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLGestureBridge(inventory, uuid); - break; - - case LLAssetType::AT_LSL_TEXT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLSLTextBridge(inventory, uuid); - break; - - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - if(!(inv_type == LLInventoryType::IT_WEARABLE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); - break; - case LLAssetType::AT_CATEGORY: - if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) - { - // Create a link folder handler instead. - new_listener = new LLLinkFolderBridge(inventory, uuid); - break; - } - new_listener = new LLFolderBridge(inventory, uuid); - break; - case LLAssetType::AT_LINK: - // Only should happen for broken links. - new_listener = new LLLinkItemBridge(inventory, uuid); - break; - case LLAssetType::AT_LINK_FOLDER: - // Only should happen for broken links. - new_listener = new LLLinkItemBridge(inventory, uuid); - break; - default: - llinfos << "Unhandled asset type (llassetstorage.h): " - << (S32)asset_type << llendl; - break; - } - - if (new_listener) - { - new_listener->mInvType = inv_type; - } - - return new_listener; -} - -void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) -{ - LLInventoryCategory* cat = model->getCategory(uuid); - if (cat) - { - model->purgeDescendentsOf(uuid); - model->notifyObservers(); - } - LLInventoryObject* obj = model->getObject(uuid); - if (obj) - { - model->purgeObject(uuid); - model->notifyObservers(); - } -} - -// +=================================================+ -// | InventoryFVBridgeBuilder | -// +=================================================+ -LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type, - LLAssetType::EType actual_asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - const LLUUID& uuid, - U32 flags /* = 0x00 */) const -{ - return LLInvFVBridge::createBridge(asset_type, - actual_asset_type, - inv_type, - inventory, - uuid, - flags); -} - -// +=================================================+ -// | LLItemBridge | -// +=================================================+ - -void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("goto" == action) - { - gotoItem(folder); - } - if ("open" == action) - { - openItem(); - return; - } - else if ("properties" == action) - { - showProperties(); - return; - } - else if ("purge" == action) - { - purgeItem(model, mUUID); - return; - } - else if ("restoreToWorld" == action) - { - restoreToWorld(); - return; - } - else if ("restore" == action) - { - restoreItem(); - return; - } - else if ("copy_uuid" == action) - { - // Single item only - LLInventoryItem* item = model->getItem(mUUID); - if(!item) return; - LLUUID asset_id = item->getAssetUUID(); - std::string buffer; - asset_id.toString(buffer); - - gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer)); - return; - } - else if ("copy" == action) - { - copyToClipboard(); - return; - } - else if ("paste" == action) - { - // Single item only - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - - LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); - if (!folder_view_itemp) return; - - folder_view_itemp->getListener()->pasteFromClipboard(); - return; - } - else if ("paste_link" == action) - { - // Single item only - LLInventoryItem* itemp = model->getItem(mUUID); - if (!itemp) return; - - LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); - if (!folder_view_itemp) return; - - folder_view_itemp->getListener()->pasteLinkFromClipboard(); - return; - } -} - -void LLItemBridge::selectItem() -{ - LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); - if(item && !item->isComplete()) - { - item->fetchFromServer(); - } -} - -void LLItemBridge::restoreItem() -{ - LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); - if(item) - { - LLInventoryModel* model = getInventoryModel(); - const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); - // do not restamp on restore. - LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE); - } -} - -void LLItemBridge::restoreToWorld() -{ - LLViewerInventoryItem* itemp = (LLViewerInventoryItem*)getItem(); - if (itemp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("RezRestoreToWorld"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_InventoryData); - itemp->packMessage(msg); - msg->sendReliable(gAgent.getRegion()->getHost()); - } - - //Similar functionality to the drag and drop rez logic - BOOL remove_from_inventory = FALSE; - - //remove local inventory copy, sim will deal with permissions and removing the item - //from the actual inventory if its a no-copy etc - if(!itemp->getPermissions().allowCopyBy(gAgent.getID())) - { - remove_from_inventory = TRUE; - } - - // Check if it's in the trash. (again similar to the normal rez logic) - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id)) - { - remove_from_inventory = TRUE; - } - - if(remove_from_inventory) - { - gInventory.deleteObject(itemp->getUUID()); - gInventory.notifyObservers(); - } -} - -void LLItemBridge::gotoItem(LLFolderView *folder) -{ - LLInventoryObject *obj = getInventoryObject(); - if (obj && obj->getIsLinkType()) - { - LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); - if (active_panel) - { - active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); - } - } -} - -LLUIImagePtr LLItemBridge::getIcon() const -{ - return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); -} - -PermissionMask LLItemBridge::getPermissionMask() const -{ - LLViewerInventoryItem* item = getItem(); - PermissionMask perm_mask = 0; - if(item) - { - BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); - BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); - BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID()); - - if (copy) perm_mask |= PERM_COPY; - if (mod) perm_mask |= PERM_MODIFY; - if (xfer) perm_mask |= PERM_TRANSFER; - - } - return perm_mask; -} - -const std::string& LLItemBridge::getDisplayName() const -{ - if(mDisplayName.empty()) - { - buildDisplayName(getItem(), mDisplayName); - } - return mDisplayName; -} - -void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name) -{ - if(item) - { - name.assign(item->getName()); - } - else - { - name.assign(LLStringUtil::null); - } -} - -LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const -{ - U8 font = LLFontGL::NORMAL; - - if( gAgentWearables.isWearingItem( mUUID ) ) - { - // llinfos << "BOLD" << llendl; - font |= LLFontGL::BOLD; - } - - const LLViewerInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) - { - font |= LLFontGL::ITALIC; - } - return (LLFontGL::StyleFlags)font; -} - -std::string LLItemBridge::getLabelSuffix() const -{ - // String table is loaded before login screen and inventory items are - // loaded after login, so LLTrans should be ready. - static std::string NO_COPY =LLTrans::getString("no_copy"); - static std::string NO_MOD = LLTrans::getString("no_modify"); - static std::string NO_XFER = LLTrans::getString("no_transfer"); - static std::string LINK = LLTrans::getString("link"); - static std::string BROKEN_LINK = LLTrans::getString("broken_link"); - std::string suffix; - LLInventoryItem* item = getItem(); - if(item) - { - // it's a bit confusing to put nocopy/nomod/etc on calling cards. - if(LLAssetType::AT_CALLINGCARD != item->getType() - && item->getPermissions().getOwner() == gAgent.getID()) - { - BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); - if (broken_link) return BROKEN_LINK; - - BOOL link = item->getIsLinkType(); - if (link) return LINK; - - BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); - if (!copy) - { - suffix += NO_COPY; - } - BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); - if (!mod) - { - suffix += NO_MOD; - } - BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, - gAgent.getID()); - if (!xfer) - { - suffix += NO_XFER; - } - } - } - return suffix; -} - -time_t LLItemBridge::getCreationDate() const -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - return item->getCreationDate(); - } - return 0; -} - - -BOOL LLItemBridge::isItemRenameable() const -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - // (For now) Don't allow calling card rename since that may confuse users as to - // what the calling card points to. - if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD) - { - return FALSE; - } - return (item->getPermissions().allowModifyBy(gAgent.getID())); - } - return FALSE; -} - -BOOL LLItemBridge::renameItem(const std::string& new_name) -{ - if(!isItemRenameable()) - return FALSE; - LLPreview::dirty(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) - return FALSE; - LLViewerInventoryItem* item = getItem(); - if(item && (item->getName() != new_name)) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - buildDisplayName(new_item, mDisplayName); - new_item->updateServer(FALSE); - model->updateItem(new_item); - - model->notifyObservers(); - } - // return FALSE because we either notified observers (& therefore - // rebuilt) or we didn't update. - return FALSE; -} - - -BOOL LLItemBridge::removeItem() -{ - if(!isItemRemovable()) - { - return FALSE; - } - // move it to the trash - LLPreview::hide(mUUID, TRUE); - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - LLViewerInventoryItem* item = getItem(); - - // if item is not already in trash - if(item && !model->isObjectDescendentOf(mUUID, trash_id)) - { - // move to trash, and restamp - LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE); - // delete was successful - return TRUE; - } - else - { - // tried to delete already item in trash (should purge?) - return FALSE; - } -} - -BOOL LLItemBridge::isItemCopyable() const -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - // can't copy worn objects. DEV-15183 - LLVOAvatarSelf *avatarp = gAgent.getAvatarObject(); - if( !avatarp ) - { - return FALSE; - } - - if(avatarp->isWearingAttachment(mUUID)) - { - return FALSE; - } - - // All items can be copied, not all can be pasted. - // The only time an item can't be copied is if it's a link - // return (item->getPermissions().allowCopyBy(gAgent.getID())); - if (item->getIsLinkType()) - { - return FALSE; - } - return TRUE; - } - return FALSE; -} -BOOL LLItemBridge::copyToClipboard() const -{ - if(isItemCopyable()) - { - LLInventoryClipboard::instance().add(mUUID); - return TRUE; - } - return FALSE; -} - -LLViewerInventoryItem* LLItemBridge::getItem() const -{ - LLViewerInventoryItem* item = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - item = (LLViewerInventoryItem*)model->getItem(mUUID); - } - return item; -} - -BOOL LLItemBridge::isItemPermissive() const -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - U32 mask = item->getPermissions().getMaskBase(); - if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - { - return TRUE; - } - } - return FALSE; -} - -// +=================================================+ -// | LLFolderBridge | -// +=================================================+ - -LLFolderBridge* LLFolderBridge::sSelf=NULL; - -// Can be moved to another folder -BOOL LLFolderBridge::isItemMovable() const -{ - LLInventoryObject* obj = getInventoryObject(); - if(obj) - { - return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())); - } - return FALSE; -} - -void LLFolderBridge::selectItem() -{ -} - - -// Can be destroyed (or moved to trash) -BOOL LLFolderBridge::isItemRemovable() -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) - { - return FALSE; - } - - if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) - { - return FALSE; - } - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if( !avatar ) - { - return FALSE; - } - - LLInventoryCategory* category = model->getCategory(mUUID); - if( !category ) - { - return FALSE; - } - - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) - { - return FALSE; - } - - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); - - S32 i; - for( i = 0; i < descendent_categories.count(); i++ ) - { - LLInventoryCategory* category = descendent_categories[i]; - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) - { - return FALSE; - } - } - - for( i = 0; i < descendent_items.count(); i++ ) - { - LLInventoryItem* item = descendent_items[i]; - if( (item->getType() == LLAssetType::AT_CLOTHING) || - (item->getType() == LLAssetType::AT_BODYPART) ) - { - if(gAgentWearables.isWearingItem(item->getUUID())) - { - return FALSE; - } - } - else - if( item->getType() == LLAssetType::AT_OBJECT ) - { - if(avatar->isWearingAttachment(item->getUUID())) - { - return FALSE; - } - } - } - - return TRUE; -} - -BOOL LLFolderBridge::isUpToDate() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); - if( !category ) - { - return FALSE; - } - - return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; -} - -BOOL LLFolderBridge::isItemCopyable() const -{ - return TRUE; -} - -BOOL LLFolderBridge::copyToClipboard() const -{ - if(isItemCopyable()) - { - LLInventoryClipboard::instance().add(mUUID); - return TRUE; - } - return FALSE; -} - -BOOL LLFolderBridge::isClipboardPasteable() const -{ - if ( ! LLInvFVBridge::isClipboardPasteable() ) - return FALSE; - - // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 - if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) ) - { - LLInventoryModel* model = getInventoryModel(); - if ( !model ) - { - return FALSE; - } - - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - const LLViewerInventoryCategory *current_cat = getCategory(); - - // Search for the direct descendent of current Friends subfolder among all pasted items, - // and return false if is found. - for(S32 i = objects.count() - 1; i >= 0; --i) - { - const LLUUID &obj_id = objects.get(i); - if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) - { - return FALSE; - } - } - - } - return TRUE; -} - -BOOL LLFolderBridge::isClipboardPasteableAsLink() const -{ - // Check normal paste-as-link permissions - if (!LLInvFVBridge::isClipboardPasteableAsLink()) - { - return FALSE; - } - - const LLInventoryModel* model = getInventoryModel(); - if (!model) - { - return FALSE; - } - - const LLViewerInventoryCategory *current_cat = getCategory(); - if (current_cat) - { - const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat ); - const LLUUID ¤t_cat_id = current_cat->getUUID(); - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); - for(S32 i = 0; i < count; i++) - { - const LLUUID &obj_id = objects.get(i); - const LLInventoryCategory *cat = model->getCategory(obj_id); - if (cat) - { - const LLUUID &cat_id = cat->getUUID(); - // Don't allow recursive pasting - if ((cat_id == current_cat_id) || - model->isObjectDescendentOf(current_cat_id, cat_id)) - { - return FALSE; - } - } - // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 - if ( is_in_friend_folder ) - { - // If object is direct descendent of current Friends subfolder than return false. - // Note: We can't use 'const LLInventoryCategory *cat', because it may be null - // in case type of obj_id is LLInventoryItem. - if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) - { - return FALSE; - } - } - } - } - return TRUE; - -} - -BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, - BOOL drop) -{ - // This should never happen, but if an inventory item is incorrectly parented, - // the UI will get confused and pass in a NULL. - if(!inv_cat) return FALSE; - - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if(!avatar) return FALSE; - - // cannot drag categories into library - if(!isAgentInventory()) - { - return FALSE; - } - - // check to make sure source is agent inventory, and is represented there. - LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) - && (LLToolDragAndDrop::SOURCE_AGENT == source); - - BOOL accept = FALSE; - S32 i; - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - if(is_agent_inventory) - { - const LLUUID& cat_id = inv_cat->getUUID(); - - // Is the destination the trash? - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - BOOL move_is_into_trash = (mUUID == trash_id) - || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (!LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - if (move_is_into_current_outfit || move_is_into_outfit) - { - // BAP - restrictions? - is_movable = true; - } - - if (mUUID == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)) - { - is_movable = FALSE; // It's generally movable but not into Favorites folder. EXT-1604 - } - - if( is_movable ) - { - gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); - - for( i = 0; i < descendent_categories.count(); i++ ) - { - LLInventoryCategory* category = descendent_categories[i]; - if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) - { - // ...can't move "special folders" like Textures - is_movable = FALSE; - break; - } - } - - if( is_movable ) - { - if( move_is_into_trash ) - { - for( i = 0; i < descendent_items.count(); i++ ) - { - LLInventoryItem* item = descendent_items[i]; - if( (item->getType() == LLAssetType::AT_CLOTHING) || - (item->getType() == LLAssetType::AT_BODYPART) ) - { - if( gAgentWearables.isWearingItem( item->getUUID() ) ) - { - is_movable = FALSE; // It's generally movable, but not into the trash! - break; - } - } - else - if( item->getType() == LLAssetType::AT_OBJECT ) - { - if( avatar->isWearingAttachment( item->getUUID() ) ) - { - is_movable = FALSE; // It's generally movable, but not into the trash! - break; - } - } - } - } - } - } - - - accept = is_movable - && (mUUID != cat_id) // Can't move a folder into itself - && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing - && !(model->isObjectDescendentOf(mUUID, cat_id)); // Avoid circularity - if(accept && drop) - { - // Look for any gestures and deactivate them - if (move_is_into_trash) - { - for (i = 0; i < descendent_items.count(); i++) - { - LLInventoryItem* item = descendent_items[i]; - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureManager::instance().isGestureActive(item->getUUID())) - { - LLGestureManager::instance().deactivateGesture(item->getUUID()); - } - } - } - // if target is an outfit or current outfit folder we use link - if (move_is_into_current_outfit || move_is_into_outfit) - { - if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) - { - if (move_is_into_current_outfit) - { - // traverse category and add all contents to currently worn. - BOOL append = true; - LLAppearanceManager::instance().wearInventoryCategory(inv_cat, false, append); - } - else - { - // Recursively create links in target outfit. - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(inv_cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH); - LLAppearanceManager::instance().linkAll(mUUID,items,NULL); - } - } - else - { -#if SUPPORT_ENSEMBLES - // BAP - should skip if dup. - if (move_is_into_current_outfit) - { - LLAppearanceManager::instance().addEnsembleLink(inv_cat); - } - else - { - LLPointer cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_cat->getUUID(), - mUUID, - inv_cat->getName(), - LLAssetType::AT_LINK_FOLDER, - cb); - } -#endif - } - } - else - { - - // Reparent the folder and restamp children if it's moving - // into trash. - LLInvFVBridge::changeCategoryParent( - model, - (LLViewerInventoryCategory*)inv_cat, - mUUID, - move_is_into_trash); - } - } - } - else if(LLToolDragAndDrop::SOURCE_WORLD == source) - { - // content category has same ID as object itself - LLUUID object_id = inv_cat->getUUID(); - LLUUID category_id = mUUID; - accept = move_inv_category_world_to_agent(object_id, category_id, drop); - } - return accept; -} - -void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv) -{ - const char* dialog = NULL; - if (object->flagScripted()) - { - dialog = "MoveInventoryFromScriptedObject"; - } - else - { - dialog = "MoveInventoryFromObject"; - } - LLNotifications::instance().add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv)); -} - -// Move/copy all inventory items from the Contents folder of an in-world -// object to the agent's inventory, inside a given category. -BOOL move_inv_category_world_to_agent(const LLUUID& object_id, - const LLUUID& category_id, - BOOL drop, - void (*callback)(S32, void*), - void* user_data) -{ - // Make sure the object exists. If we allowed dragging from - // anonymous objects, it would be possible to bypass - // permissions. - // content category has same ID as object itself - LLViewerObject* object = gObjectList.findObject(object_id); - if(!object) - { - llinfos << "Object not found for drop." << llendl; - return FALSE; - } - - // this folder is coming from an object, as there is only one folder in an object, the root, - // we need to collect the entire contents and handle them as a group - InventoryObjectList inventory_objects; - object->getInventoryContents(inventory_objects); - - if (inventory_objects.empty()) - { - llinfos << "Object contents not found for drop." << llendl; - return FALSE; - } - - BOOL accept = TRUE; - BOOL is_move = FALSE; - - // coming from a task. Need to figure out if the person can - // move/copy this item. - InventoryObjectList::iterator it = inventory_objects.begin(); - InventoryObjectList::iterator end = inventory_objects.end(); - for ( ; it != end; ++it) - { - // coming from a task. Need to figure out if the person can - // move/copy this item. - LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions()); - if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) - && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) - { - accept = TRUE; - } - else if(object->permYouOwner()) - { - // If the object cannot be copied, but the object the - // inventory is owned by the agent, then the item can be - // moved from the task to agent inventory. - is_move = TRUE; - accept = TRUE; - } - else - { - accept = FALSE; - break; - } - } - - if(drop && accept) - { - it = inventory_objects.begin(); - InventoryObjectList::iterator first_it = inventory_objects.begin(); - LLMoveInv* move_inv = new LLMoveInv; - move_inv->mObjectID = object_id; - move_inv->mCategoryID = category_id; - move_inv->mCallback = callback; - move_inv->mUserData = user_data; - - for ( ; it != end; ++it) - { - two_uuids_t two(category_id, (*it)->getUUID()); - move_inv->mMoveList.push_back(two); - } - - if(is_move) - { - // Callback called from within here. - warn_move_inventory(object, move_inv); - } - else - { - LLNotification::Params params("MoveInventoryFromObject"); - params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); - LLNotifications::instance().forceResponse(params, 0); - } - } - return accept; -} - -bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - // Valid COF items are: - // - links to wearables (body parts or clothing) - // - links to attachments - // - links to gestures - // - links to ensemble folders - LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); // BAP - safe? - if (linked_item) - { - LLAssetType::EType type = linked_item->getType(); - return (type == LLAssetType::AT_CLOTHING || - type == LLAssetType::AT_BODYPART || - type == LLAssetType::AT_GESTURE || - type == LLAssetType::AT_OBJECT); - } - else - { - LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); // BAP - safe? - // BAP remove AT_NONE support after ensembles are fully working? - return (linked_category && - ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || - (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); - } -} - - -bool LLFindWearables::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CLOTHING) - || (item->getType() == LLAssetType::AT_BODYPART)) - { - return TRUE; - } - } - return FALSE; -} - - - -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver -{ -public: - LLRightClickInventoryFetchObserver() : - mCopyItems(false) - { }; - LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) : - mCatID(cat_id), - mCopyItems(copy_items) - { }; - virtual void done() - { - // we've downloaded all the items, so repaint the dialog - LLFolderBridge::staticFolderOptionsMenu(); - - gInventory.removeObserver(this); - delete this; - } - - -protected: - LLUUID mCatID; - bool mCopyItems; - -}; - -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {} - ~LLRightClickInventoryFetchDescendentsObserver() {} - virtual void done(); -protected: - bool mCopyItems; -}; - -void LLRightClickInventoryFetchDescendentsObserver::done() -{ - // Avoid passing a NULL-ref as mCompleteFolders.front() down to - // gInventory.collectDescendents() - if( mCompleteFolders.empty() ) - { - llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; - dec_busy_count(); - gInventory.removeObserver(this); - delete this; - return; - } - - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mCompleteFolders.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); -#if 0 // HACK/TODO: Why? - // This early causes a giant menu to get produced, and doesn't seem to be needed. - if(!count) - { - llwarns << "Nothing fetched in category " << mCompleteFolders.front() - << llendl; - dec_busy_count(); - gInventory.removeObserver(this); - delete this; - return; - } -#endif - - LLRightClickInventoryFetchObserver* outfit; - outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems); - LLInventoryFetchObserver::item_ref_t ids; - for(S32 i = 0; i < count; ++i) - { - ids.push_back(item_array.get(i)->getUUID()); - } - - // clean up, and remove this as an observer since the call to the - // outfit could notify observers and throw us into an infinite - // loop. - dec_busy_count(); - gInventory.removeObserver(this); - delete this; - - // increment busy count and either tell the inventory to check & - // call done, or add this object to the inventory for observation. - inc_busy_count(); - - // do the fetch - outfit->fetchItems(ids); - outfit->done(); //Not interested in waiting and this will be right 99% of the time. -//Uncomment the following code for laggy Inventory UI. -/* if(outfit->isEverythingComplete()) - { - // everything is already here - call done. - outfit->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - }*/ -} - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryWearObserver -// -// Observer for "copy and wear" operation to support knowing -// when the all of the contents have been added to inventory. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryCopyAndWearObserver : public LLInventoryObserver -{ -public: - LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {} - virtual ~LLInventoryCopyAndWearObserver() {} - virtual void changed(U32 mask); - -protected: - LLUUID mCatID; - int mContentsCount; - BOOL mFolderAdded; -}; - - - -void LLInventoryCopyAndWearObserver::changed(U32 mask) -{ - if((mask & (LLInventoryObserver::ADD)) != 0) - { - if (!mFolderAdded) - { - const std::set& changed_items = gInventory.getChangedIDs(); - - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - if ((*id_it) == mCatID) - { - mFolderAdded = TRUE; - break; - } - } - } - - if (mFolderAdded) - { - LLViewerInventoryCategory* category = gInventory.getCategory(mCatID); - - if (NULL == category) - { - llwarns << "gInventory.getCategory(" << mCatID - << ") was NULL" << llendl; - } - else - { - if (category->getDescendentCount() == - mContentsCount) - { - gInventory.removeObserver(this); - LLAppearanceManager::instance().wearInventoryCategory(category, FALSE, TRUE); - delete this; - } - } - } - - } -} - - - -void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("open" == action) - { - openItem(); - return; - } - else if ("paste" == action) - { - pasteFromClipboard(); - return; - } - else if ("paste_link" == action) - { - pasteLinkFromClipboard(); - return; - } - else if ("properties" == action) - { - showProperties(); - return; - } - else if ("replaceoutfit" == action) - { - modifyOutfit(FALSE); - return; - } -#if SUPPORT_ENSEMBLES - else if ("wearasensemble" == action) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - LLAppearanceManager::instance().addEnsembleLink(cat,true); - return; - } -#endif - else if ("addtooutfit" == action) - { - modifyOutfit(TRUE); - return; - } - else if ("copy" == action) - { - copyToClipboard(); - return; - } - else if ("removefromoutfit" == action) - { - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - - remove_inventory_category_from_avatar ( cat ); - return; - } - else if ("purge" == action) - { - purgeItem(model, mUUID); - return; - } - else if ("restore" == action) - { - restoreItem(); - return; - } -} - -void LLFolderBridge::openItem() -{ - lldebugs << "LLFolderBridge::openItem()" << llendl; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - if(mUUID.isNull()) return; - bool fetching_inventory = model->fetchDescendentsOf(mUUID); - // Only change folder type if we have the folder contents. - if (!fetching_inventory) - { - // Disabling this for now, it's causing crash when new items are added to folders - // since folder type may change before new item item has finished processing. - // determineFolderType(); - } -} - -void LLFolderBridge::closeItem() -{ - determineFolderType(); -} - -void LLFolderBridge::determineFolderType() -{ - if (isUpToDate()) - { - LLInventoryModel* model = getInventoryModel(); - LLViewerInventoryCategory* category = model->getCategory(mUUID); - category->determineFolderType(); - } -} - -BOOL LLFolderBridge::isItemRenameable() const -{ - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) - && (cat->getOwnerID() == gAgent.getID())) - { - return TRUE; - } - return FALSE; -} - -void LLFolderBridge::restoreItem() -{ - LLViewerInventoryCategory* cat; - cat = (LLViewerInventoryCategory*)getCategory(); - if(cat) - { - LLInventoryModel* model = getInventoryModel(); - const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType())); - // do not restamp children on restore - LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE); - } -} - -LLFolderType::EType LLFolderBridge::getPreferredType() const -{ - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - preferred_type = cat->getPreferredType(); - } - - return preferred_type; -} - -// Icons for folders are based on the preferred type -LLUIImagePtr LLFolderBridge::getIcon() const -{ - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - preferred_type = cat->getPreferredType(); - } - return getIcon(preferred_type); -} - -LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) -{ - // we only have one folder image now - return LLUI::getUIImage("Inv_FolderClosed"); -} - -BOOL LLFolderBridge::renameItem(const std::string& new_name) -{ - if(!isItemRenameable()) - return FALSE; - LLInventoryModel* model = getInventoryModel(); - if(!model) - return FALSE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat && (cat->getName() != new_name)) - { - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); - - model->notifyObservers(); - } - // return FALSE because we either notified observers (& therefore - // rebuilt) or we didn't update. - return FALSE; -} - -BOOL LLFolderBridge::removeItem() -{ - if(!isItemRemovable()) - { - return FALSE; - } - // move it to the trash - LLPreview::hide(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); - - S32 i; - for (i = 0; i < descendent_items.count(); i++) - { - LLInventoryItem* item = descendent_items[i]; - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureManager::instance().isGestureActive(item->getUUID())) - { - LLGestureManager::instance().deactivateGesture(item->getUUID()); - } - } - - // go ahead and do the normal remove if no 'last calling - // cards' are being removed. - LLViewerInventoryCategory* cat = getCategory(); - if(cat) - { - LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE); - } - - return TRUE; -} - -void LLFolderBridge::pasteFromClipboard() -{ - LLInventoryModel* model = getInventoryModel(); - if(model && isClipboardPasteable()) - { - LLInventoryItem* item = NULL; - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); - const LLUUID parent_id(mUUID); - for(S32 i = 0; i < count; i++) - { - item = model->getItem(objects.get(i)); - if (item) - { - if(LLInventoryClipboard::instance().isCutMode()) - { - // move_inventory_item() is not enough, - //we have to update inventory locally too - changeItemParent(model, dynamic_cast(item), parent_id, FALSE); - } - else - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - parent_id, - std::string(), - LLPointer(NULL)); - } - } - } - } -} - -void LLFolderBridge::pasteLinkFromClipboard() -{ - const LLInventoryModel* model = getInventoryModel(); - if(model) - { - LLDynamicArray objects; - LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); - LLUUID parent_id(mUUID); - for(S32 i = 0; i < count; i++) - { - const LLUUID &object_id = objects.get(i); -#if SUPPORT_ENSEMBLES - if (LLInventoryCategory *cat = model->getCategory(object_id)) - { - link_inventory_item( - gAgent.getID(), - cat->getUUID(), - parent_id, - cat->getName(), - LLAssetType::AT_LINK_FOLDER, - LLPointer(NULL)); - } - else -#endif - if (LLInventoryItem *item = model->getItem(object_id)) - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - parent_id, - item->getName(), - LLAssetType::AT_LINK, - LLPointer(NULL)); - } - } - } -} - -void LLFolderBridge::staticFolderOptionsMenu() -{ - if (!sSelf) return; - sSelf->folderOptionsMenu(); -} - -void LLFolderBridge::folderOptionsMenu() -{ - std::vector disabled_items; - - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - - const LLInventoryCategory* category = model->getCategory(mUUID); - LLFolderType::EType type = category->getPreferredType(); - const bool is_default_folder = category && LLFolderType::lookupIsProtectedType(type); - // BAP change once we're no longer treating regular categories as ensembles. - const bool is_ensemble = category && (type == LLFolderType::FT_NONE || - LLFolderType::lookupIsEnsembleType(type)); - - // calling card related functionality for folders. - - // Only enable calling-card related options for non-default folders. - if (!is_default_folder) - { - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) - { - mItems.push_back(std::string("Calling Card Separator")); - mItems.push_back(std::string("Conference Chat Folder")); - mItems.push_back(std::string("IM All Contacts In Folder")); - } - } - - // wearables related functionality for folders. - //is_wearable - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (mWearables || - checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) - { - mItems.push_back(std::string("Folder Wearables Separator")); - - // Only enable add/replace outfit for non-default folders. - if (!is_default_folder) - { - mItems.push_back(std::string("Add To Outfit")); - mItems.push_back(std::string("Replace Outfit")); - } - if (is_ensemble) - { - mItems.push_back(std::string("Wear As Ensemble")); - } - mItems.push_back(std::string("Remove From Outfit")); - } - hide_context_entries(*mMenu, mItems, disabled_items); -} - -BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) -{ - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_type); - return ((item_array.count() > 0) ? TRUE : FALSE ); -} - -// Flags unused -void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - mItems.clear(); - mDisabledItems.clear(); - - lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; -// std::vector disabled_items; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - - mItems.clear(); //adding code to clear out member Items (which means Items should not have other data here at this point) - mDisabledItems.clear(); //adding code to clear out disabled members from previous - if (lost_and_found_id == mUUID) - { - // This is the lost+found folder. - mItems.push_back(std::string("Empty Lost And Found")); - } - - if(trash_id == mUUID) - { - // This is the trash. - mItems.push_back(std::string("Empty Trash")); - } - else if(model->isObjectDescendentOf(mUUID, trash_id)) - { - // This is a folder in the trash. - mItems.clear(); // clear any items that used to exist - mItems.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - mDisabledItems.push_back(std::string("Purge Item")); - } - - mItems.push_back(std::string("Restore Item")); - } - else if(isAgentInventory()) // do not allow creating in library - { - LLViewerInventoryCategory *cat = getCategory(); - // BAP removed protected check to re-enable standard ops in untyped folders. - // Not sure what the right thing is to do here. - if (!isCOFFolder() && cat /*&& - LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())*/) - { - // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. - if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) - mItems.push_back(std::string("New Folder")); - mItems.push_back(std::string("New Script")); - mItems.push_back(std::string("New Note")); - mItems.push_back(std::string("New Gesture")); - mItems.push_back(std::string("New Clothes")); - mItems.push_back(std::string("New Body Parts")); - mItems.push_back(std::string("Change Type")); - - LLViewerInventoryCategory *cat = getCategory(); - if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) - { - mDisabledItems.push_back(std::string("Change Type")); - } - - getClipboardEntries(false, mItems, mDisabledItems, flags); - } - else - { - // Want some but not all of the items from getClipboardEntries for outfits. - if (cat && cat->getPreferredType()==LLFolderType::FT_OUTFIT) - { - mItems.push_back(std::string("Rename")); - mItems.push_back(std::string("Delete")); - } - } - - //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 - mCallingCards = mWearables = FALSE; - - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (checkFolderForContentsOfType(model, is_callingcard)) - { - mCallingCards=TRUE; - } - - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) - { - mWearables=TRUE; - } - - mMenu = &menu; - sSelf = this; - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); - - LLInventoryFetchDescendentsObserver::folder_ref_t folders; - LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); - if (category) - { - folders.push_back(category->getUUID()); - } - fetch->fetchDescendents(folders); - inc_busy_count(); - if(fetch->isEverythingComplete()) - { - // everything is already here - call done. - fetch->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(fetch); - } - } - else - { - mItems.push_back(std::string("--no options--")); - mDisabledItems.push_back(std::string("--no options--")); - } - hide_context_entries(menu, mItems, mDisabledItems); -} - -BOOL LLFolderBridge::hasChildren() const -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - LLInventoryModel::EHasChildren has_children; - has_children = gInventory.categoryHasChildren(mUUID); - return has_children != LLInventoryModel::CHILDREN_NO; -} - -BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) -{ - //llinfos << "LLFolderBridge::dragOrDrop()" << llendl; - BOOL accept = FALSE; - switch(cargo_type) - { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_CALLINGCARD: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_CLOTHING: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - case DAD_LINK: - accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, - drop); - break; - case DAD_CATEGORY: - if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID)) - { - accept = FALSE; - } - else - { - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop); - } - break; - default: - break; - } - return accept; -} - -LLViewerInventoryCategory* LLFolderBridge::getCategory() const -{ - LLViewerInventoryCategory* cat = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - cat = (LLViewerInventoryCategory*)model->getCategory(mUUID); - } - return cat; -} - - -// static -void LLFolderBridge::pasteClipboard(void* user_data) -{ - LLFolderBridge* self = (LLFolderBridge*)user_data; - if(self) self->pasteFromClipboard(); -} - -void LLFolderBridge::createNewCategory(void* user_data) -{ - LLFolderBridge* bridge = (LLFolderBridge*)user_data; - if(!bridge) return; - LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel.get()); - if (!panel) return; - LLInventoryModel* model = panel->getModel(); - if(!model) return; - LLUUID id; - id = model->createNewCategory(bridge->getUUID(), - LLFolderType::FT_NONE, - LLStringUtil::null); - model->notifyObservers(); - - // At this point, the bridge has probably been deleted, but the - // view is still there. - panel->setSelection(id, TAKE_FOCUS_YES); -} - -void LLFolderBridge::createNewShirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT); -} - -void LLFolderBridge::createNewPants(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS); -} - -void LLFolderBridge::createNewShoes(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES); -} - -void LLFolderBridge::createNewSocks(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS); -} - -void LLFolderBridge::createNewJacket(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET); -} - -void LLFolderBridge::createNewSkirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT); -} - -void LLFolderBridge::createNewGloves(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES); -} - -void LLFolderBridge::createNewUndershirt(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT); -} - -void LLFolderBridge::createNewUnderpants(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS); -} - -void LLFolderBridge::createNewShape(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE); -} - -void LLFolderBridge::createNewSkin(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN); -} - -void LLFolderBridge::createNewHair(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR); -} - -void LLFolderBridge::createNewEyes(void* user_data) -{ - LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); -} - -// static -void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) -{ - if(!bridge) return; - LLUUID parent_id = bridge->getUUID(); - createWearable(parent_id, type); -} - -// Separate function so can be called by global menu as well as right-click -// menu. -// static -void LLFolderBridge::createWearable(const LLUUID &parent_id, EWearableType type) -{ - LLWearable* wearable = LLWearableList::instance().createNewWearable(type); - LLAssetType::EType asset_type = wearable->getAssetType(); - LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent_id, wearable->getTransactionID(), wearable->getName(), - wearable->getDescription(), asset_type, inv_type, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - LLPointer(NULL)); -} - -void LLFolderBridge::modifyOutfit(BOOL append) -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - LLViewerInventoryCategory* cat = getCategory(); - if(!cat) return; - - // BAP - was: - // wear_inventory_category_on_avatar( cat, append ); - LLAppearanceManager::instance().wearInventoryCategory( cat, FALSE, append ); -} - -// helper stuff -bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv* move_inv) -{ - LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData; - LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID); - S32 option = LLNotification::getSelectedOption(notification, response); - - if(option == 0 && object) - { - if (cat_and_wear && cat_and_wear->mWear) - { - InventoryObjectList inventory_objects; - object->getInventoryContents(inventory_objects); - int contents_count = inventory_objects.size()-1; //subtract one for containing folder - - LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count); - gInventory.addObserver(inventoryObserver); - } - - two_uuids_list_t::iterator move_it; - for (move_it = move_inv->mMoveList.begin(); - move_it != move_inv->mMoveList.end(); - ++move_it) - { - object->moveInventory(move_it->first, move_it->second); - } - - // update the UI. - dialog_refresh_all(); - } - - if (move_inv->mCallback) - { - move_inv->mCallback(option, move_inv->mUserData); - } - - delete move_inv; - return false; -} - -/* -Next functions intended to reorder items in the inventory folder and save order on server -Is now used for Favorites folder. - -*TODO: refactoring is needed with Favorites Bar functionality. Probably should be moved in LLInventoryModel -*/ -void saveItemsOrder(LLInventoryModel::item_array_t& items) -{ - int sortField = 0; - - // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field - for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) - { - LLViewerInventoryItem* item = *i; - - item->setSortField(++sortField); - item->setComplete(TRUE); - item->updateServer(FALSE); - - gInventory.updateItem(item); - } - - gInventory.notifyObservers(); -} - -LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) -{ - LLInventoryModel::item_array_t::iterator result = items.end(); - - for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) - { - if ((*i)->getUUID() == id) - { - result = i; - break; - } - } - - return result; -} - -void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId) -{ - LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId); - LLViewerInventoryItem* destItem = gInventory.getItem(destItemId); - - items.erase(findItemByUUID(items, srcItem->getUUID())); - items.insert(findItemByUUID(items, destItem->getUUID()), srcItem); -} - -BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, - BOOL drop) -{ - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - - // cannot drag into library - if(!isAgentInventory()) - { - return FALSE; - } - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if(!avatar) return FALSE; - - LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - BOOL accept = FALSE; - LLViewerObject* object = NULL; - if(LLToolDragAndDrop::SOURCE_AGENT == source) - { - - BOOL is_movable = TRUE; - switch( inv_item->getActualType() ) - { - case LLAssetType::AT_CATEGORY: - is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); - break; - default: - break; - } - - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - - if(is_movable && move_is_into_trash) - { - switch(inv_item->getType()) - { - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - is_movable = !gAgentWearables.isWearingItem(inv_item->getUUID()); - break; - - case LLAssetType::AT_OBJECT: - is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); - break; - default: - break; - } - } - - if ( is_movable ) - { - // Don't allow creating duplicates in the Calling Card/Friends - // subfolders, see bug EXT-1599. Check is item direct descendent - // of target folder and forbid item's movement if it so. - // Note: isItemDirectDescendentOfCategory checks if - // passed category is in the Calling Card/Friends folder - is_movable = ! LLFriendCardsManager::instance() - .isObjDirectDescendentOfCategory (inv_item, getCategory()); - } - - const LLUUID& favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - const LLUUID& landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - const BOOL folder_allows_reorder = ((mUUID == landmarks_id) || (mUUID == favorites_id)); - - // we can move item inside a folder only if this folder is Favorites. See EXT-719 - accept = is_movable && ((mUUID != inv_item->getParentUUID()) || folder_allows_reorder); - if(accept && drop) - { - if (inv_item->getType() == LLAssetType::AT_GESTURE - && LLGestureManager::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash) - { - LLGestureManager::instance().deactivateGesture(inv_item->getUUID()); - } - // If an item is being dragged between windows, unselect - // everything in the active window so that we don't follow - // the selection to its new location (which is very - // annoying). - if (LLFloaterInventory::getActiveInventory()) - { - LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - if (active_panel && (panel != active_panel)) - { - active_panel->unSelectAll(); - } - } - - // if dragging from/into favorites folder only reorder items - if ((mUUID == inv_item->getParentUUID()) && folder_allows_reorder) - { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLIsType is_type(LLAssetType::AT_LANDMARK); - model->collectDescendentsIf(mUUID, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); - - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; - if (itemp) - { - LLUUID srcItemId = inv_item->getUUID(); - LLUUID destItemId = itemp->getListener()->getUUID(); - - // update order - updateItemsOrder(items, srcItemId, destItemId); - - saveItemsOrder(items); - } - } - else if (favorites_id == mUUID) // if target is the favorites folder we use copy - { - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - LLPointer(NULL)); - } - else if (move_is_into_current_outfit || move_is_into_outfit) - { - // BAP - should skip if dup. - if (move_is_into_current_outfit) - { - LLAppearanceManager::instance().addCOFItemLink(inv_item); - } - else - { - LLPointer cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_item->getLinkedUUID(), - mUUID, - inv_item->getName(), - LLAssetType::AT_LINK, - cb); - } - } - else - { - // restamp if the move is into the trash. - LLInvFVBridge::changeItemParent( - model, - (LLViewerInventoryItem*)inv_item, - mUUID, - move_is_into_trash); - } - } - } - else if(LLToolDragAndDrop::SOURCE_WORLD == source) - { - // Make sure the object exists. If we allowed dragging from - // anonymous objects, it would be possible to bypass - // permissions. - object = gObjectList.findObject(inv_item->getParentUUID()); - if(!object) - { - llinfos << "Object not found for drop." << llendl; - return FALSE; - } - - // coming from a task. Need to figure out if the person can - // move/copy this item. - LLPermissions perm(inv_item->getPermissions()); - BOOL is_move = FALSE; - if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) - && perm.allowTransferTo(gAgent.getID()))) -// || gAgent.isGodlike()) - - { - accept = TRUE; - } - else if(object->permYouOwner()) - { - // If the object cannot be copied, but the object the - // inventory is owned by the agent, then the item can be - // moved from the task to agent inventory. - is_move = TRUE; - accept = TRUE; - } - if(drop && accept) - { - LLMoveInv* move_inv = new LLMoveInv; - move_inv->mObjectID = inv_item->getParentUUID(); - two_uuids_t item_pair(mUUID, inv_item->getUUID()); - move_inv->mMoveList.push_back(item_pair); - move_inv->mCallback = NULL; - move_inv->mUserData = NULL; - if(is_move) - { - warn_move_inventory(object, move_inv); - } - else - { - LLNotification::Params params("MoveInventoryFromObject"); - params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); - LLNotifications::instance().forceResponse(params, 0); - } - } - - } - else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) - { - accept = TRUE; - if(drop) - { - copy_inventory_from_notecard(LLToolDragAndDrop::getInstance()->getObjectID(), - LLToolDragAndDrop::getInstance()->getSourceID(), inv_item); - } - } - else if(LLToolDragAndDrop::SOURCE_LIBRARY == source) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item; - if(item && item->isComplete()) - { - accept = TRUE; - if(drop) - { - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - mUUID, - std::string(), - LLPointer(NULL)); - } - } - } - else - { - llwarns << "unhandled drag source" << llendl; - } - return accept; -} - -// +=================================================+ -// | LLScriptBridge (DEPRECTED) | -// +=================================================+ - -LLUIImagePtr LLScriptBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - -// +=================================================+ -// | LLTextureBridge | -// +=================================================+ - -LLUIImagePtr LLTextureBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE); -} - -void LLTextureBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -} - -void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back(std::string("Texture Separator")); - items.push_back(std::string("Save As")); - } - hide_context_entries(menu, items, disabled_items); -} - -// virtual -void LLTextureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("save_as" == action) - { - LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); - LLPreviewTexture* preview_texture = LLFloaterReg::findTypedInstance("preview_texture", mUUID); - if (preview_texture) - { - preview_texture->openToSave(); - } - } - else LLItemBridge::performAction(folder, model, action); -} - -// +=================================================+ -// | LLSoundBridge | -// +=================================================+ - -LLUIImagePtr LLSoundBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); -} - -void LLSoundBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* -// Changed this back to the way it USED to work: -// only open the preview dialog through the contextual right-click menu -// double-click just plays the sound - - LLViewerInventoryItem* item = getItem(); - if(item) - { - openSoundPreview((void*)this); - //send_uuid_sound_trigger(item->getAssetUUID(), 1.0); - } -*/ -} - -void LLSoundBridge::previewItem() -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - send_sound_trigger(item->getAssetUUID(), 1.0); - } -} - -void LLSoundBridge::openSoundPreview(void* which) -{ - LLSoundBridge *me = (LLSoundBridge *)which; - LLFloaterReg::showInstance("preview_sound", LLSD(me->mUUID), TAKE_FOCUS_YES); -} - -void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLSoundBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Sound Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Sound Separator")); - items.push_back(std::string("Sound Play")); - - hide_context_entries(menu, items, disabled_items); -} - -// +=================================================+ -// | LLLandmarkBridge | -// +=================================================+ - -LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags/* = 0x00*/) : -LLItemBridge(inventory, uuid) -{ - mVisited = FALSE; - if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) - { - mVisited = TRUE; - } -} - -LLUIImagePtr LLLandmarkBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE); -} - -void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - std::vector items; - std::vector disabled_items; - - lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Landmark Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Landmark Separator")); - items.push_back(std::string("About Landmark")); - - // Disable "About Landmark" menu item for - // multiple landmarks selected. Only one landmark - // info panel can be shown at a time. - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("About Landmark")); - } - - hide_context_entries(menu, items, disabled_items); -} - -// Convenience function for the two functions below. -void teleport_via_landmark(const LLUUID& asset_id) -{ - gAgent.teleportViaLandmark( asset_id ); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); - if( floater_world_map ) - { - floater_world_map->trackLandmark( asset_id ); - } -} - -// virtual -void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("teleport" == action) - { - LLViewerInventoryItem* item = getItem(); - if(item) - { - teleport_via_landmark(item->getAssetUUID()); - } - } - else if ("about" == action) - { - LLViewerInventoryItem* item = getItem(); - if(item) - { - LLSD key; - key["type"] = "landmark"; - key["id"] = item->getUUID(); - - LLSideTray::getInstance()->showPanel("panel_places", key); - } - } - else - { - LLItemBridge::performAction(folder, model, action); - } -} - -static bool open_landmark_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - LLUUID asset_id = notification["payload"]["asset_id"].asUUID(); - if (option == 0) - { - teleport_via_landmark(asset_id); - } - - return false; -} -static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFromLandmark", open_landmark_callback); - - -void LLLandmarkBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if( item ) - { - // Opening (double-clicking) a landmark immediately teleports, - // but warns you the first time. - // open_landmark(item); - LLSD payload; - payload["asset_id"] = item->getAssetUUID(); - LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); - } -*/ -} - - -// +=================================================+ -// | LLCallingCardObserver | -// +=================================================+ -void LLCallingCardObserver::changed(U32 mask) -{ - mBridgep->refreshFolderViewItem(); -} - -// +=================================================+ -// | LLCallingCardBridge | -// +=================================================+ - -LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) : - LLItemBridge(inventory, uuid) -{ - mObserver = new LLCallingCardObserver(this); - LLAvatarTracker::instance().addObserver(mObserver); -} - -LLCallingCardBridge::~LLCallingCardBridge() -{ - LLAvatarTracker::instance().removeObserver(mObserver); - delete mObserver; -} - -void LLCallingCardBridge::refreshFolderViewItem() -{ - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; - if (itemp) - { - itemp->refresh(); - } -} - -// virtual -void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("begin_im" == action) - { - LLViewerInventoryItem *item = getItem(); - if (item && (item->getCreatorUUID() != gAgent.getID()) && - (!item->getCreatorUUID().isNull())) - { - std::string callingcard_name; - gCacheName->getFullName(item->getCreatorUUID(), callingcard_name); - LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); - if (session_id != LLUUID::null) - { - LLIMFloater::show(session_id); - } - } - } - else if ("lure" == action) - { - LLViewerInventoryItem *item = getItem(); - if (item && (item->getCreatorUUID() != gAgent.getID()) && - (!item->getCreatorUUID().isNull())) - { - LLAvatarActions::offerTeleport(item->getCreatorUUID()); - } - } - else LLItemBridge::performAction(folder, model, action); -} - -LLUIImagePtr LLCallingCardBridge::getIcon() const -{ - BOOL online = FALSE; - LLViewerInventoryItem* item = getItem(); - if(item) - { - online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); - } - return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE); -} - -std::string LLCallingCardBridge::getLabelSuffix() const -{ - LLViewerInventoryItem* item = getItem(); - if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) ) - { - return LLItemBridge::getLabelSuffix() + " (online)"; - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -void LLCallingCardBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if(item && !item->getCreatorUUID().isNull()) - { - LLAvatarActions::showProfile(item->getCreatorUUID()); - } -*/ -} - -void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - LLInventoryItem* item = getItem(); - BOOL good_card = (item - && (LLUUID::null != item->getCreatorUUID()) - && (item->getCreatorUUID() != gAgent.getID())); - BOOL user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID())); - items.push_back(std::string("Send Instant Message Separator")); - items.push_back(std::string("Send Instant Message")); - items.push_back(std::string("Offer Teleport...")); - items.push_back(std::string("Conference Chat")); - - if (!good_card) - { - disabled_items.push_back(std::string("Send Instant Message")); - } - if (!good_card || !user_online) - { - disabled_items.push_back(std::string("Offer Teleport...")); - disabled_items.push_back(std::string("Conference Chat")); - } - } - hide_context_entries(menu, items, disabled_items); -} - -BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) -{ - LLViewerInventoryItem* item = getItem(); - BOOL rv = FALSE; - if(item) - { - // check the type - switch(cargo_type) - { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_CLOTHING: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - { - LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - const LLPermissions& perm = inv_item->getPermissions(); - if(gInventory.getItem(inv_item->getUUID()) - && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID())) - { - rv = TRUE; - if(drop) - { - LLToolDragAndDrop::giveInventory(item->getCreatorUUID(), - (LLInventoryItem*)cargo_data); - } - } - else - { - // It's not in the user's inventory (it's probably in - // an object's contents), so disallow dragging it here. - // You can't give something you don't yet have. - rv = FALSE; - } - break; - } - case DAD_CATEGORY: - { - LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data; - if( gInventory.getCategory( inv_cat->getUUID() ) ) - { - rv = TRUE; - if(drop) - { - LLToolDragAndDrop::giveInventoryCategory( - item->getCreatorUUID(), - inv_cat); - } - } - else - { - // It's not in the user's inventory (it's probably in - // an object's contents), so disallow dragging it here. - // You can't give something you don't yet have. - rv = FALSE; - } - break; - } - default: - break; - } - } - return rv; -} - -BOOL LLCallingCardBridge::removeItem() -{ - if (LLFriendCardsManager::instance().isItemInAnyFriendsList(getItem())) - { - LLAvatarActions::removeFriendDialog(getItem()->getCreatorUUID()); - return FALSE; - } - else - { - return LLItemBridge::removeItem(); - } -} -// +=================================================+ -// | LLNotecardBridge | -// +=================================================+ - -LLUIImagePtr LLNotecardBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); -} - -void LLNotecardBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } - -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); - } -*/ -} - - -// +=================================================+ -// | LLGestureBridge | -// +=================================================+ - -LLUIImagePtr LLGestureBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); -} - -LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const -{ - if( LLGestureManager::instance().isGestureActive(mUUID) ) - { - return LLFontGL::BOLD; - } - else - { - return LLFontGL::NORMAL; - } -} - -std::string LLGestureBridge::getLabelSuffix() const -{ - if( LLGestureManager::instance().isGestureActive(mUUID) ) - { - return LLItemBridge::getLabelSuffix() + " (active)"; - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -// virtual -void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("activate" == action) - { - LLGestureManager::instance().activateGesture(mUUID); - - LLViewerInventoryItem* item = gInventory.getItem(mUUID); - if (!item) return; - - // Since we just changed the suffix to indicate (active) - // the server doesn't need to know, just the viewer. - gInventory.updateItem(item); - gInventory.notifyObservers(); - } - else if ("deactivate" == action) - { - LLGestureManager::instance().deactivateGesture(mUUID); - - LLViewerInventoryItem* item = gInventory.getItem(mUUID); - if (!item) return; - - // Since we just changed the suffix to indicate (active) - // the server doesn't need to know, just the viewer. - gInventory.updateItem(item); - gInventory.notifyObservers(); - } - else LLItemBridge::performAction(folder, model, action); -} - -void LLGestureBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); - preview->setFocus(TRUE); - } -*/ -} - -BOOL LLGestureBridge::removeItem() -{ - // Force close the preview window, if it exists - LLGestureManager::instance().deactivateGesture(mUUID); - return LLItemBridge::removeItem(); -} - -void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - LLInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) - { - items.push_back(std::string("Find Original")); - } - items.push_back(std::string("Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back(std::string("Gesture Separator")); - items.push_back(std::string("Activate")); - items.push_back(std::string("Deactivate")); - } - hide_context_entries(menu, items, disabled_items); -} - -// +=================================================+ -// | LLAnimationBridge | -// +=================================================+ - -LLUIImagePtr LLAnimationBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); -} - -void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - std::vector items; - std::vector disabled_items; - - lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Animation Open")); - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - } - - items.push_back(std::string("Animation Separator")); - items.push_back(std::string("Animation Play")); - items.push_back(std::string("Animation Audition")); - - hide_context_entries(menu, items, disabled_items); - -} - -// virtual -void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ((action == "playworld") || (action == "playlocal")) - { - if (getItem()) - { - LLPreviewAnim::e_activation_type activate = LLPreviewAnim::NONE; - if ("playworld" == action) activate = LLPreviewAnim::PLAY; - if ("playlocal" == action) activate = LLPreviewAnim::AUDITION; - - LLPreviewAnim* preview = LLFloaterReg::showTypedInstance("preview_anim", LLSD(mUUID)); - if (preview) - { - preview->activate(activate); - } - } - } - else - { - LLItemBridge::performAction(folder, model, action); - } -} - -void LLAnimationBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } -/* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); - } -*/ -} - -// +=================================================+ -// | LLObjectBridge | -// +=================================================+ - -// static -LLUUID LLObjectBridge::sContextMenuItemID; - -LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : -LLItemBridge(inventory, uuid), mInvType(type) -{ - mAttachPt = (flags & 0xff); // low bye of inventory flags - - mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; -} - -BOOL LLObjectBridge::isItemRemovable() -{ - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if(!avatar) return FALSE; - if(avatar->isWearingAttachment(mUUID)) return FALSE; - return LLInvFVBridge::isItemRemovable(); -} - -LLUIImagePtr LLObjectBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); -} - -LLInventoryObject* LLObjectBridge::getObject() const -{ - LLInventoryObject* object = NULL; - LLInventoryModel* model = getInventoryModel(); - if(model) - { - object = (LLInventoryObject*)model->getObject(mUUID); - } - return object; -} - -// virtual -void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("attach" == action) - { - LLUUID object_id = mUUID; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(object_id); - if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) - { - rez_attachment(item, NULL); - } - else if(item && item->isComplete()) - { - // must be in library. copy it to our inventory and put it on. - LLPointer cb = new RezAttachmentCallback(0); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - gFocusMgr.setKeyboardFocus(NULL); - } - else if ("detach" == action) - { - LLInventoryItem* item = gInventory.getItem(mUUID); - if(item) - { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); - gMessageSystem->sendReliable( gAgent.getRegion()->getHost()); - } - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject(item->getLinkedUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } - } - else LLItemBridge::performAction(folder, model, action); -} - -void LLObjectBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } - - LLSD key; - key["id"] = mUUID; - LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); - - // Disable old properties floater; this is replaced by the sidepanel. - /* - LLFloaterReg::showInstance("properties", mUUID); - */ -} - -LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const -{ - U8 font = LLFontGL::NORMAL; - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if( avatar && avatar->isWearingAttachment( mUUID ) ) - { - font |= LLFontGL::BOLD; - } - - LLInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) - { - font |= LLFontGL::ITALIC; - } - - return (LLFontGL::StyleFlags)font; -} - -std::string LLObjectBridge::getLabelSuffix() const -{ - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if( avatar && avatar->isWearingAttachment( mUUID ) ) - { - std::string attachment_point_name = avatar->getAttachedPointName(mUUID); - - // e.g. "(worn on ...)" / "(attached to ...)" - LLStringUtil::format_map_t args; - args["[ATTACHMENT_POINT]"] = attachment_point_name.c_str(); - return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) -{ - LLSD payload; - payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. - - S32 attach_pt = 0; - if (gAgent.getAvatarObject() && attachment) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgent.getAvatarObject()->mAttachmentPoints.begin(); - iter != gAgent.getAvatarObject()->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attach_pt = iter->first; - break; - } - } - } - - payload["attachment_point"] = attach_pt; - -#if !ENABLE_MULTIATTACHMENTS - if (attachment && attachment->getNumObjects() > 0) - { - LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); - } - else -#endif - { - LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); - } -} - -bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) -{ - LLVOAvatar *avatarp = gAgent.getAvatarObject(); - - if (!avatarp->canAttachMoreObjects()) - { - LLSD args; - args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); - LLNotifications::instance().add("MaxAttachmentsOnOutfit", args); - return false; - } - - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0/*YES*/) - { - LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - - if (itemp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); - U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); -#if ENABLE_MULTIATTACHMENTS - attachment_pt |= ATTACHMENT_ADD; -#endif - msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); - pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); - msg->addStringFast(_PREHASH_Name, itemp->getName()); - msg->addStringFast(_PREHASH_Description, itemp->getDescription()); - msg->sendReliable(gAgent.getRegion()->getHost()); - } - } - return false; -} -static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez); - -void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - std::vector items; - std::vector disabled_items; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - LLInventoryItem* item = getItem(); - if (item && item->getIsLinkType()) - { - items.push_back(std::string("Find Original")); - } - - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - LLObjectBridge::sContextMenuItemID = mUUID; - - if(item) - { - LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); - if( !avatarp ) - { - return; - } - - if( avatarp->isWearingAttachment( mUUID ) ) - { - items.push_back(std::string("Detach From Yourself")); - } - else - if( !isInTrash() && !isLinkedObjectInTrash() ) - { - items.push_back(std::string("Attach Separator")); - items.push_back(std::string("Object Wear")); - items.push_back(std::string("Attach To")); - items.push_back(std::string("Attach To HUD")); - // commented out for DEV-32347 - //items.push_back(std::string("Restore to Last Position")); - - if (!avatarp->canAttachMoreObjects()) - { - disabled_items.push_back(std::string("Object Wear")); - disabled_items.push_back(std::string("Attach To")); - disabled_items.push_back(std::string("Attach To HUD")); - } - LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); - LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); - LLVOAvatar *avatarp = gAgent.getAvatarObject(); - if (attach_menu - && (attach_menu->getChildCount() == 0) - && attach_hud_menu - && (attach_hud_menu->getChildCount() == 0) - && avatarp) - { - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - LLMenuItemCallGL::Params p; - std::string submenu_name = attachment->getName(); - if (LLTrans::getString(submenu_name) != "") - { - p.name = (" ")+LLTrans::getString(submenu_name)+" "; - } - else - { - p.name = submenu_name; - } - LLSD cbparams; - cbparams["index"] = curiter->first; - cbparams["label"] = attachment->getName(); - p.on_click.function_name = "Inventory.AttachObject"; - p.on_click.parameter = LLSD(attachment->getName()); - p.on_enable.function_name = "Attachment.Label"; - p.on_enable.parameter = cbparams; - LLView* parent = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu; - LLUICtrlFactory::create(p, parent); - } - } - } - } - } - hide_context_entries(menu, items, disabled_items); -} - -BOOL LLObjectBridge::renameItem(const std::string& new_name) -{ - if(!isItemRenameable()) - return FALSE; - LLPreview::dirty(mUUID); - LLInventoryModel* model = getInventoryModel(); - if(!model) - return FALSE; - LLViewerInventoryItem* item = getItem(); - if(item && (item->getName() != new_name)) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - buildDisplayName(new_item, mDisplayName); - new_item->updateServer(FALSE); - model->updateItem(new_item); - - model->notifyObservers(); - - LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if( avatar ) - { - LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() ); - if( obj ) - { - LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->addAsIndividual( obj, SELECT_ALL_TES, FALSE ); - LLSelectMgr::getInstance()->selectionSetObjectName( new_name ); - LLSelectMgr::getInstance()->deselectAll(); - } - } - } - // return FALSE because we either notified observers (& therefore - // rebuilt) or we didn't update. - return FALSE; -} - -// +=================================================+ -// | LLLSLTextBridge | -// +=================================================+ - -LLUIImagePtr LLLSLTextBridge::getIcon() const -{ - return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); -} - -void LLLSLTextBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } - /* - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); - } - */ -} - -// +=================================================+ -// | LLWearableBridge | -// +=================================================+ - -// *NOTE: hack to get from avatar inventory to avatar -void wear_inventory_item_on_avatar( LLInventoryItem* item ) -{ - if(item) - { - lldebugs << "wear_inventory_item_on_avatar( " << item->getName() - << " )" << llendl; - - LLAppearanceManager::instance().addCOFItemLink(item); - } -} - -void wear_add_inventory_item_on_avatar( LLInventoryItem* item ) -{ - if(item) - { - lldebugs << "wear_add_inventory_item_on_avatar( " << item->getName() - << " )" << llendl; - - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onWearAddOnAvatarArrived, - new LLUUID(item->getUUID())); - } -} - -void remove_inventory_category_from_avatar( LLInventoryCategory* category ) -{ - if(!category) return; - lldebugs << "remove_inventory_category_from_avatar( " << category->getName() - << " )" << llendl; - - - if( gFloaterCustomize ) - { - gFloaterCustomize->askToSaveIfDirty( - boost::bind(remove_inventory_category_from_avatar_step2, _1, category->getUUID())); - } - else - { - remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); - } -} - -struct OnRemoveStruct -{ - LLUUID mUUID; - OnRemoveStruct(const LLUUID& uuid): - mUUID(uuid) - { - } -}; - -void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id) -{ - - // Find all the wearables that are in the category's subtree. - lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl; - if(proceed) - { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(category_id, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); - S32 i; - S32 wearable_count = item_array.count(); - - LLInventoryModel::cat_array_t obj_cat_array; - LLInventoryModel::item_array_t obj_item_array; - LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(category_id, - obj_cat_array, - obj_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_object); - S32 obj_count = obj_item_array.count(); - - // Find all gestures in this folder - LLInventoryModel::cat_array_t gest_cat_array; - LLInventoryModel::item_array_t gest_item_array; - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(category_id, - gest_cat_array, - gest_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_gesture); - S32 gest_count = gest_item_array.count(); - - if (wearable_count > 0) //Loop through wearables. If worn, remove. - { - for(i = 0; i < wearable_count; ++i) - { - if( gAgentWearables.isWearingItem (item_array.get(i)->getUUID()) ) - { - LLWearableList::instance().getAsset(item_array.get(i)->getAssetUUID(), - item_array.get(i)->getName(), - item_array.get(i)->getType(), - LLWearableBridge::onRemoveFromAvatarArrived, - new OnRemoveStruct(item_array.get(i)->getUUID())); - - } - } - } - - - if (obj_count > 0) - { - for(i = 0; i < obj_count; ++i) - { - gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData ); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item_array.get(i)->getUUID() ); - - gMessageSystem->sendReliable( gAgent.getRegion()->getHost() ); - - // this object might have been selected, so let the selection manager know it's gone now - LLViewerObject *found_obj = gObjectList.findObject( obj_item_array.get(i)->getUUID()); - if (found_obj) - { - LLSelectMgr::getInstance()->remove(found_obj); - } - } - } - - if (gest_count > 0) - { - for(i = 0; i < gest_count; ++i) - { - if ( LLGestureManager::instance().isGestureActive( gest_item_array.get(i)->getUUID()) ) - { - LLGestureManager::instance().deactivateGesture( gest_item_array.get(i)->getUUID() ); - gInventory.updateItem( gest_item_array.get(i) ); - gInventory.notifyObservers(); - } - - } - } - } -} - -BOOL LLWearableBridge::renameItem(const std::string& new_name) -{ - if( gAgentWearables.isWearingItem( mUUID ) ) - { - gAgentWearables.setWearableName( mUUID, new_name ); - } - return LLItemBridge::renameItem(new_name); -} - -BOOL LLWearableBridge::isItemRemovable() -{ - if (gAgentWearables.isWearingItem(mUUID)) return FALSE; - return LLInvFVBridge::isItemRemovable(); -} - -std::string LLWearableBridge::getLabelSuffix() const -{ - if( gAgentWearables.isWearingItem( mUUID ) ) - { - // e.g. "(worn)" - return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); - } - else - { - return LLItemBridge::getLabelSuffix(); - } -} - -LLUIImagePtr LLWearableBridge::getIcon() const -{ - return get_item_icon(mAssetType, mInvType, mWearableType, FALSE); -} - -// virtual -void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("wear" == action) - { - wearOnAvatar(); - } - else if ("wear_add" == action) - { - wearAddOnAvatar(); - } - else if ("edit" == action) - { - editOnAvatar(); - return; - } - else if ("take_off" == action) - { - if(gAgentWearables.isWearingItem(mUUID)) - { - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - LLWearableBridge::onRemoveFromAvatarArrived, - new OnRemoveStruct(mUUID)); - } - } - } - else LLItemBridge::performAction(folder, model, action); -} - -void LLWearableBridge::openItem() -{ - LLViewerInventoryItem* item = getItem(); - - if (item) - { - LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } - /* - if( isInTrash() ) - { - LLNotifications::instance().add("CannotWearTrash"); - } - else if(isAgentInventory()) - { - if( !gAgentWearables.isWearingItem( mUUID ) ) - { - wearOnAvatar(); - } - } - else - { - // must be in the inventory library. copy it to our inventory - // and put it on right away. - LLViewerInventoryItem* item = getItem(); - if(item && item->isComplete()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else if(item) - { - // *TODO: We should fetch the item details, and then do - // the operation above. - LLNotifications::instance().add("CannotWearInfoNotComplete"); - } - } - */ -} - -void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere - BOOL no_open = ((flags & SUPPRESS_OPEN_ITEM) == SUPPRESS_OPEN_ITEM); - - // If we have clothing, don't add "Open" as it's the same action as "Wear" SL-18976 - LLViewerInventoryItem* item = getItem(); - if( !no_open && item ) - { - no_open = (item->getType() == LLAssetType::AT_CLOTHING) || - (item->getType() == LLAssetType::AT_BODYPART); - } - if (!no_open) - { - items.push_back(std::string("Open")); - } - - if (item && item->getIsLinkType()) - { - items.push_back(std::string("Find Original")); - } - - items.push_back(std::string("Properties")); - - getClipboardEntries(true, items, disabled_items, flags); - - items.push_back(std::string("Wearable Separator")); - - items.push_back(std::string("Wearable Wear")); - items.push_back(std::string("Wearable Add")); - items.push_back(std::string("Wearable Edit")); - - if ((flags & FIRST_SELECTED_ITEM) == 0) - { - disabled_items.push_back(std::string("Wearable Edit")); - } - // Don't allow items to be worn if their baseobj is in the trash. - if (isLinkedObjectInTrash()) - { - disabled_items.push_back(std::string("Wearable Wear")); - disabled_items.push_back(std::string("Wearable Add")); - disabled_items.push_back(std::string("Wearable Edit")); - } - - // Disable wear and take off based on whether the item is worn. - if(item) - { - switch (item->getType()) - { - case LLAssetType::AT_CLOTHING: - items.push_back(std::string("Take Off")); - case LLAssetType::AT_BODYPART: - if (gAgentWearables.isWearingItem(item->getUUID())) - { - disabled_items.push_back(std::string("Wearable Wear")); - disabled_items.push_back(std::string("Wearable Add")); - } - else - { - disabled_items.push_back(std::string("Take Off")); - } - break; - default: - break; - } - } - } - hide_context_entries(menu, items, disabled_items); -} - -// Called from menus -// static -BOOL LLWearableBridge::canWearOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return FALSE; - if(!self->isAgentInventory()) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(!item || !item->isComplete()) return FALSE; - } - return (!gAgentWearables.isWearingItem(self->mUUID)); -} - -// Called from menus -// static -void LLWearableBridge::onWearOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return; - self->wearOnAvatar(); -} - -void LLWearableBridge::wearOnAvatar() -{ - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); - return; - } - - LLViewerInventoryItem* item = getItem(); - if(item) - { - if(!isAgentInventory()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar(item); - } - } -} - -void LLWearableBridge::wearAddOnAvatar() -{ - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); - return; - } - - LLViewerInventoryItem* item = getItem(); - if(item) - { - if(!isAgentInventory()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_add_inventory_item_on_avatar(item); - } - } -} - -// static -void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - gAgentWearables.setWearableItem(item, wearable); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; - } - } - } - delete item_id; -} - -// static -// BAP remove the "add" code path once everything is fully COF-ified. -void LLWearableBridge::onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ) -{ - LLUUID* item_id = (LLUUID*) userdata; - if(wearable) - { - LLViewerInventoryItem* item = NULL; - item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); - if(item) - { - if(item->getAssetUUID() == wearable->getAssetID()) - { - bool do_append = true; - gAgentWearables.setWearableItem(item, wearable, do_append); - gInventory.notifyObservers(); - //self->getFolderItem()->refreshFromRoot(); - } - else - { - llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; - } - } - } - delete item_id; -} - -// static -BOOL LLWearableBridge::canEditOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return FALSE; - - return (gAgentWearables.isWearingItem(self->mUUID)); -} - -// static -void LLWearableBridge::onEditOnAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(self) - { - self->editOnAvatar(); - } -} - -void LLWearableBridge::editOnAvatar() -{ - const LLWearable* wearable = gAgentWearables.getWearableFromItemID(mUUID); - if( wearable ) - { - // Set the tab to the right wearable. - if (gFloaterCustomize) - gFloaterCustomize->setCurrentWearableType( wearable->getType() ); - - if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() ) - { - // Start Avatar Customization - gAgent.changeCameraToCustomizeAvatar(); - } - } -} - -// static -BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if( self && (LLAssetType::AT_BODYPART != self->mAssetType) ) - { - return gAgentWearables.isWearingItem( self->mUUID ); - } - return FALSE; -} - -// static -void LLWearableBridge::onRemoveFromAvatar(void* user_data) -{ - LLWearableBridge* self = (LLWearableBridge*)user_data; - if(!self) return; - if(gAgentWearables.isWearingItem(self->mUUID)) - { - LLViewerInventoryItem* item = self->getItem(); - if (item) - { - LLUUID parent_id = item->getParentUUID(); - LLWearableList::instance().getAsset(item->getAssetUUID(), - item->getName(), - item->getType(), - onRemoveFromAvatarArrived, - new OnRemoveStruct(LLUUID(self->mUUID))); - } - } -} - -// static -void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, - void* userdata) -{ - OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata; - const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID); - if(wearable) - { - if( gAgentWearables.isWearingItem( item_id ) ) - { - EWearableType type = wearable->getType(); - - if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&& - //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) - { - // MULTI_WEARABLE: FIXME HACK - always remove all - bool do_remove_all = false; - gAgentWearables.removeWearable( type, do_remove_all, 0 ); - } - } - } - - // Find and remove this item from the COF. - LLInventoryModel::item_array_t items = gInventory.collectLinkedItems(item_id, LLAppearanceManager::instance().getCOF()); - llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. - for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); - iter != items.end(); - ++iter) - { - const LLViewerInventoryItem *linked_item = (*iter); - const LLUUID &item_id = linked_item->getUUID(); - gInventory.purgeObject(item_id); - } - gInventory.notifyObservers(); - - delete on_remove_struct; -} - -LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, - const LLUUID& uuid,LLInventoryModel* model) -{ - LLInvFVBridgeAction* action = NULL; - switch(asset_type) - { - case LLAssetType::AT_TEXTURE: - action = new LLTextureBridgeAction(uuid,model); - break; - - case LLAssetType::AT_SOUND: - action = new LLSoundBridgeAction(uuid,model); - break; - - case LLAssetType::AT_LANDMARK: - action = new LLLandmarkBridgeAction(uuid,model); - break; - - case LLAssetType::AT_CALLINGCARD: - action = new LLCallingCardBridgeAction(uuid,model); - break; - - case LLAssetType::AT_OBJECT: - action = new LLObjectBridgeAction(uuid,model); - break; - - case LLAssetType::AT_NOTECARD: - action = new LLNotecardBridgeAction(uuid,model); - break; - - case LLAssetType::AT_ANIMATION: - action = new LLAnimationBridgeAction(uuid,model); - break; - - case LLAssetType::AT_GESTURE: - action = new LLGestureBridgeAction(uuid,model); - break; - - case LLAssetType::AT_LSL_TEXT: - action = new LLLSLTextBridgeAction(uuid,model); - break; - - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - action = new LLWearableBridgeAction(uuid,model); - - break; - - default: - break; - } - return action; -} - -//static -void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type, - const LLUUID& uuid,LLInventoryModel* model) -{ - LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); - if(action) - { - action->doIt(); - delete action; - } -} - -//static -void LLInvFVBridgeAction::doAction(const LLUUID& uuid, LLInventoryModel* model) -{ - LLAssetType::EType asset_type = model->getItem(uuid)->getType(); - LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); - if(action) - { - action->doIt(); - delete action; - } -} - -LLViewerInventoryItem* LLInvFVBridgeAction::getItem() const -{ - if(mModel) - return (LLViewerInventoryItem*)mModel->getItem(mUUID); - return NULL; -} - -//virtual -void LLTextureBridgeAction::doIt() -{ - if (getItem()) - { - LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); - } - - LLInvFVBridgeAction::doIt(); -} - -//virtual -void LLSoundBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - LLFloaterReg::showInstance("preview_sound", LLSD(mUUID), TAKE_FOCUS_YES); - } - - LLInvFVBridgeAction::doIt(); -} - - -//virtual -void LLLandmarkBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if( item ) - { - // Opening (double-clicking) a landmark immediately teleports, - // but warns you the first time. - LLSD payload; - payload["asset_id"] = item->getAssetUUID(); - LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); - } - - LLInvFVBridgeAction::doIt(); -} - - -//virtual -void LLCallingCardBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if(item && item->getCreatorUUID().notNull()) - { - LLAvatarActions::showProfile(item->getCreatorUUID()); - } - - LLInvFVBridgeAction::doIt(); -} - -//virtual -void -LLNotecardBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); - } - - LLInvFVBridgeAction::doIt(); -} - -//virtual -void LLGestureBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); - preview->setFocus(TRUE); - } - - LLInvFVBridgeAction::doIt(); -} - -//virtual -void LLAnimationBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); - } - - LLInvFVBridgeAction::doIt(); -} - - -//virtual -void LLObjectBridgeAction::doIt() -{ - LLFloaterReg::showInstance("properties", mUUID); - - LLInvFVBridgeAction::doIt(); -} - - -//virtual -void LLLSLTextBridgeAction::doIt() -{ - LLViewerInventoryItem* item = getItem(); - if (item) - { - LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); - } - - LLInvFVBridgeAction::doIt(); -} - - -BOOL LLWearableBridgeAction::isInTrash() const -{ - if(!mModel) return FALSE; - const LLUUID trash_id = mModel->findCategoryUUIDForType(LLFolderType::FT_TRASH); - return mModel->isObjectDescendentOf(mUUID, trash_id); -} - -BOOL LLWearableBridgeAction::isAgentInventory() const -{ - if(!mModel) return FALSE; - if(gInventory.getRootFolderID() == mUUID) return TRUE; - return mModel->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); -} - -void LLWearableBridgeAction::wearOnAvatar() -{ - // Don't wear anything until initial wearables are loaded, can - // destroy clothing items. - if (!gAgentWearables.areWearablesLoaded()) - { - LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); - return; - } - - LLViewerInventoryItem* item = getItem(); - if(item) - { - if(!isAgentInventory()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else - { - wear_inventory_item_on_avatar(item); - } - } -} - -//virtual -void LLWearableBridgeAction::doIt() -{ - if(isInTrash()) - { - LLNotifications::instance().add("CannotWearTrash"); - } - else if(isAgentInventory()) - { - if(!gAgentWearables.isWearingItem(mUUID)) - { - wearOnAvatar(); - } - } - else - { - // must be in the inventory library. copy it to our inventory - // and put it on right away. - LLViewerInventoryItem* item = getItem(); - if(item && item->isComplete()) - { - LLPointer cb = new WearOnAvatarCallback(); - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - else if(item) - { - // *TODO: We should fetch the item details, and then do - // the operation above. - LLNotifications::instance().add("CannotWearInfoNotComplete"); - } - } - - LLInvFVBridgeAction::doIt(); -} - -// +=================================================+ -// | LLLinkItemBridge | -// +=================================================+ -// For broken links - -std::string LLLinkItemBridge::sPrefix("Link: "); - - -LLUIImagePtr LLLinkItemBridge::getIcon() const -{ - if (LLViewerInventoryItem *item = getItem()) - { - return get_item_icon(item->getActualType(), LLInventoryType::IT_NONE, 0, FALSE); - } - return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); -} - -void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - // *TODO: Translate - lldebugs << "LLLink::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Delete")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } - } - hide_context_entries(menu, items, disabled_items); -} - - -// +=================================================+ -// | LLLinkBridge | -// +=================================================+ -// For broken links. - -std::string LLLinkFolderBridge::sPrefix("Link: "); - - -LLUIImagePtr LLLinkFolderBridge::getIcon() const -{ - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - if (LLViewerInventoryItem *item = getItem()) - { - if (const LLViewerInventoryCategory* cat = item->getLinkedCategory()) - { - preferred_type = cat->getPreferredType(); - } - } - return LLFolderBridge::getIcon(preferred_type); -} - -void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - // *TODO: Translate - lldebugs << "LLLink::buildContextMenu()" << llendl; - std::vector items; - std::vector disabled_items; - - if(isInTrash()) - { - items.push_back(std::string("Purge Item")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Purge Item")); - } - - items.push_back(std::string("Restore Item")); - } - else - { - items.push_back(std::string("Find Original")); - items.push_back(std::string("Delete")); - if (!isItemRemovable()) - { - disabled_items.push_back(std::string("Delete")); - } - } - hide_context_entries(menu, items, disabled_items); -} - -void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) -{ - if ("goto" == action) - { - gotoItem(folder); - return; - } - LLItemBridge::performAction(folder,model,action); -} - -void LLLinkFolderBridge::gotoItem(LLFolderView *folder) -{ - const LLUUID &cat_uuid = getFolderID(); - if (!cat_uuid.isNull()) - { - if (LLFolderViewItem *base_folder = folder->getItemByID(cat_uuid)) - { - if (LLInventoryModel* model = getInventoryModel()) - { - model->fetchDescendentsOf(cat_uuid); - } - base_folder->setOpen(TRUE); - folder->setSelectionFromRoot(base_folder,TRUE); - folder->scrollToShowSelection(); - } - } -} - -const LLUUID &LLLinkFolderBridge::getFolderID() const -{ - if (LLViewerInventoryItem *link_item = getItem()) - { - if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) - { - const LLUUID& cat_uuid = cat->getUUID(); - return cat_uuid; - } - } - return LLUUID::null; -} +/** + * @file llinventorybridge.cpp + * @brief Implementation of the Inventory-Folder-View-Bridge classes. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llinventorybridge.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llavataractions.h" +#include "llfloatercustomize.h" +#include "llfloaterinventory.h" +#include "llfloateropenobject.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" +#include "llfriendcard.h" +#include "llgesturemgr.h" +#include "llimfloater.h" +#include "llimview.h" +#include "llinventoryclipboard.h" +#include "llinventoryfunctions.h" +#include "llinventorymodel.h" +#include "llinventorypanel.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewtexture.h" +#include "llselectmgr.h" +#include "llsidetray.h" +#include "lltrans.h" +#include "llviewerassettype.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwearablelist.h" + +using namespace LLOldEvents; + +// Helpers +// bug in busy count inc/dec right now, logic is complex... do we really need it? +void inc_busy_count() +{ +// gViewerWindow->getWindow()->incBusyCount(); +// check balance of these calls if this code is changed to ever actually +// *do* something! +} +void dec_busy_count() +{ +// gViewerWindow->getWindow()->decBusyCount(); +// check balance of these calls if this code is changed to ever actually +// *do* something! +} + +// Function declarations +void wear_add_inventory_item_on_avatar(LLInventoryItem* item); +void remove_inventory_category_from_avatar(LLInventoryCategory* category); +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); +bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); + +std::string ICON_NAME[ICON_NAME_COUNT] = +{ + "Inv_Texture", + "Inv_Sound", + "Inv_CallingCard", + "Inv_CallingCard", + "Inv_Landmark", + "Inv_Landmark", + "Inv_Script", + "Inv_Clothing", + "Inv_Object", + "Inv_Object", + "Inv_Notecard", + "Inv_Skin", + "Inv_Snapshot", + + "Inv_BodyShape", + "Inv_Skin", + "Inv_Hair", + "Inv_Eye", + "Inv_Shirt", + "Inv_Pants", + "Inv_Shoe", + "Inv_Socks", + "Inv_Jacket", + "Inv_Gloves", + "Inv_Undershirt", + "Inv_Underpants", + "Inv_Skirt", + "Inv_Alpha", + "Inv_Tattoo", + + "Inv_Animation", + "Inv_Gesture", + + "inv_item_linkitem.tga", + "inv_item_linkfolder.tga" +}; + +// +=================================================+ +// | LLInvFVBridge | +// +=================================================+ + +LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : +mUUID(uuid), mInvType(LLInventoryType::IT_NONE) +{ + mInventoryPanel = inventory->getHandle(); +} + +const std::string& LLInvFVBridge::getName() const +{ + LLInventoryObject* obj = getInventoryObject(); + if(obj) + { + return obj->getName(); + } + return LLStringUtil::null; +} + +const std::string& LLInvFVBridge::getDisplayName() const +{ + return getName(); +} + +// Folders have full perms +PermissionMask LLInvFVBridge::getPermissionMask() const +{ + + return PERM_ALL; +} + +// virtual +LLFolderType::EType LLInvFVBridge::getPreferredType() const +{ + return LLFolderType::FT_NONE; +} + + +// Folders don't have creation dates. +time_t LLInvFVBridge::getCreationDate() const +{ + return 0; +} + +// Can be destoryed (or moved to trash) +BOOL LLInvFVBridge::isItemRemovable() +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + if(model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) + { + return TRUE; + } + return FALSE; +} + +// Can be moved to another folder +BOOL LLInvFVBridge::isItemMovable() const +{ + return TRUE; +} + +/*virtual*/ +/** + * @brief Adds this item into clipboard storage + */ +void LLInvFVBridge::cutToClipboard() +{ + if(isItemMovable()) + { + LLInventoryClipboard::instance().cut(mUUID); + } +} +// *TODO: make sure this does the right thing +void LLInvFVBridge::showProperties() +{ + LLSD key; + key["id"] = mUUID; + LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + + // Disable old properties floater; this is replaced by the sidepanel. + /* + LLFloaterReg::showInstance("properties", mUUID); + */ +} + +void LLInvFVBridge::removeBatch(LLDynamicArray& batch) +{ + // Deactivate gestures when moving them into Trash + LLInvFVBridge* bridge; + LLInventoryModel* model = getInventoryModel(); + LLViewerInventoryItem* item = NULL; + LLViewerInventoryCategory* cat = NULL; + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + S32 count = batch.count(); + S32 i,j; + for(i = 0; i < count; ++i) + { + bridge = (LLInvFVBridge*)(batch.get(i)); + if(!bridge || !bridge->isItemRemovable()) continue; + item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); + if (item) + { + if(LLAssetType::AT_GESTURE == item->getType()) + { + LLGestureManager::instance().deactivateGesture(item->getUUID()); + } + } + } + for(i = 0; i < count; ++i) + { + bridge = (LLInvFVBridge*)(batch.get(i)); + if(!bridge || !bridge->isItemRemovable()) continue; + cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); + if (cat) + { + gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE ); + for (j=0; jgetType()) + { + LLGestureManager::instance().deactivateGesture(descendent_items[j]->getUUID()); + } + } + } + } + removeBatchNoCheck(batch); +} + +void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray& batch) +{ + // this method moves a bunch of items and folders to the trash. As + // per design guidelines for the inventory model, the message is + // built and the accounting is performed first. After all of that, + // we call LLInventoryModel::moveObject() to move everything + // around. + LLInvFVBridge* bridge; + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + LLMessageSystem* msg = gMessageSystem; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + LLViewerInventoryItem* item = NULL; + LLViewerInventoryCategory* cat = NULL; + std::vector move_ids; + LLInventoryModel::update_map_t update; + bool start_new_message = true; + S32 count = batch.count(); + S32 i; + for(i = 0; i < count; ++i) + { + bridge = (LLInvFVBridge*)(batch.get(i)); + if(!bridge || !bridge->isItemRemovable()) continue; + item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); + if(item) + { + if(item->getParentUUID() == trash_id) continue; + move_ids.push_back(item->getUUID()); + LLPreview::hide(item->getUUID()); + --update[item->getParentUUID()]; + ++update[trash_id]; + if(start_new_message) + { + start_new_message = false; + msg->newMessageFast(_PREHASH_MoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addBOOLFast(_PREHASH_Stamp, TRUE); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, item->getUUID()); + msg->addUUIDFast(_PREHASH_FolderID, trash_id); + msg->addString("NewName", NULL); + if(msg->isSendFullFast(_PREHASH_InventoryData)) + { + start_new_message = true; + gAgent.sendReliableMessage(); + gInventory.accountForUpdate(update); + update.clear(); + } + } + } + if(!start_new_message) + { + start_new_message = true; + gAgent.sendReliableMessage(); + gInventory.accountForUpdate(update); + update.clear(); + } + for(i = 0; i < count; ++i) + { + bridge = (LLInvFVBridge*)(batch.get(i)); + if(!bridge || !bridge->isItemRemovable()) continue; + cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); + if(cat) + { + if(cat->getParentUUID() == trash_id) continue; + move_ids.push_back(cat->getUUID()); + --update[cat->getParentUUID()]; + ++update[trash_id]; + if(start_new_message) + { + start_new_message = false; + msg->newMessageFast(_PREHASH_MoveInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addBOOL("Stamp", TRUE); + } + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID()); + msg->addUUIDFast(_PREHASH_ParentID, trash_id); + if(msg->isSendFullFast(_PREHASH_InventoryData)) + { + start_new_message = true; + gAgent.sendReliableMessage(); + gInventory.accountForUpdate(update); + update.clear(); + } + } + } + if(!start_new_message) + { + gAgent.sendReliableMessage(); + gInventory.accountForUpdate(update); + } + + // move everything. + std::vector::iterator it = move_ids.begin(); + std::vector::iterator end = move_ids.end(); + for(; it != end; ++it) + { + gInventory.moveObject((*it), trash_id); + } + + // notify inventory observers. + model->notifyObservers(); +} + +BOOL LLInvFVBridge::isClipboardPasteable() const +{ + if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) + { + return FALSE; + } + LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return FALSE; + } + + const LLUUID &agent_id = gAgent.getID(); + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.get(i); + + // Can't paste folders + const LLInventoryCategory *cat = model->getCategory(item_id); + if (cat) + { + return FALSE; + } + + const LLInventoryItem *item = model->getItem(item_id); + if (item) + { + if (!item->getPermissions().allowCopyBy(agent_id)) + { + return FALSE; + } + } + } + return TRUE; +} + +BOOL LLInvFVBridge::isClipboardPasteableAsLink() const +{ + if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) + { + return FALSE; + } + const LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLInventoryItem *item = model->getItem(objects.get(i)); + if (item) + { + if (!LLAssetType::lookupCanLink(item->getActualType())) + { + return FALSE; + } + } + const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i)); + if (cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + return FALSE; + } + } + return TRUE; +} + +void hide_context_entries(LLMenuGL& menu, + const std::vector &entries_to_show, + const std::vector &disabled_entries) +{ + const LLView::child_list_t *list = menu.getChildList(); + + LLView::child_list_t::const_iterator itor; + for (itor = list->begin(); itor != list->end(); ++itor) + { + std::string name = (*itor)->getName(); + + // descend into split menus: + LLMenuItemBranchGL* branchp = dynamic_cast(*itor); + if ((name == "More") && branchp) + { + hide_context_entries(*branchp->getBranch(), entries_to_show, disabled_entries); + } + + + bool found = false; + std::vector::const_iterator itor2; + for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2) + { + if (*itor2 == name) + { + found = true; + } + } + if (!found) + { + (*itor)->setVisible(FALSE); + } + else + { + for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) + { + if (*itor2 == name) + { + (*itor)->setEnabled(FALSE); + } + } + } + } +} + +// Helper for commonly-used entries +void LLInvFVBridge::getClipboardEntries(bool show_asset_id, + std::vector &items, + std::vector &disabled_items, U32 flags) +{ + items.push_back(std::string("Rename")); + if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Rename")); + } + + if (show_asset_id) + { + items.push_back(std::string("Copy Asset UUID")); + if ( (! ( isItemPermissive() || gAgent.isGodlike() ) ) + || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Copy Asset UUID")); + } + } + + items.push_back(std::string("Copy Separator")); + + items.push_back(std::string("Copy")); + if (!isItemCopyable()) + { + disabled_items.push_back(std::string("Copy")); + } + + items.push_back(std::string("Paste")); + if (!isClipboardPasteable() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Paste")); + } + + items.push_back(std::string("Paste As Link")); + if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Paste As Link")); + } + items.push_back(std::string("Paste Separator")); + + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + + // If multiple items are selected, disable properties (if it exists). + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Properties")); + } +} + +void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + if(isInTrash()) + { + items.push_back(std::string("PurgeItem")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("PurgeItem")); + } + items.push_back(std::string("RestoreItem")); + } + else + { + items.push_back(std::string("Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + hide_context_entries(menu, items, disabled_items); +} + +// *TODO: remove this +BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const +{ + BOOL rv = FALSE; + + const LLInventoryObject* obj = getInventoryObject(); + + if(obj) + { + *type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); + if(*type == DAD_NONE) + { + return FALSE; + } + + *id = obj->getUUID(); + //object_ids.put(obj->getUUID()); + + if (*type == DAD_CATEGORY) + { + gInventory.startBackgroundFetch(obj->getUUID()); + } + + rv = TRUE; + } + + return rv; +} + +LLInventoryObject* LLInvFVBridge::getInventoryObject() const +{ + LLInventoryObject* obj = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + obj = (LLInventoryObject*)model->getObject(mUUID); + } + return obj; +} + +LLInventoryModel* LLInvFVBridge::getInventoryModel() const +{ + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + return panel ? panel->getModel() : NULL; +} + +BOOL LLInvFVBridge::isInTrash() const +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + return model->isObjectDescendentOf(mUUID, trash_id); +} + +BOOL LLInvFVBridge::isLinkedObjectInTrash() const +{ + if (isInTrash()) return TRUE; + + const LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); + } + return FALSE; +} + +BOOL LLInvFVBridge::isAgentInventory() const +{ + const LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + if(gInventory.getRootFolderID() == mUUID) return TRUE; + return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); +} + +BOOL LLInvFVBridge::isCOFFolder() const +{ + const LLInventoryModel* model = getInventoryModel(); + if(!model) return TRUE; + const LLUUID cof_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + if (mUUID == cof_id || model->isObjectDescendentOf(mUUID, cof_id)) + { + return TRUE; + } + return FALSE; +} + +BOOL LLInvFVBridge::isItemPermissive() const +{ + return FALSE; +} + +// static +void LLInvFVBridge::changeItemParent(LLInventoryModel* model, + LLViewerInventoryItem* item, + const LLUUID& new_parent, + BOOL restamp) +{ + if(item->getParentUUID() != new_parent) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent); + new_item->updateParentOnServer(restamp); + model->updateItem(new_item); + model->notifyObservers(); + } +} + +// static +void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, + LLViewerInventoryCategory* cat, + const LLUUID& new_parent, + BOOL restamp) +{ + if(cat->getParentUUID() != new_parent) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent); + new_cat->updateParentOnServer(restamp); + model->updateCategory(new_cat); + model->notifyObservers(); + } +} + + +const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type) +{ + const std::string rv= LLInventoryType::lookup(inv_type); + if(rv.empty()) + { + return std::string(""); + } + return rv; +} + +LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + const LLUUID& uuid, + U32 flags) +{ + LLInvFVBridge* new_listener = NULL; + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLTextureBridge(inventory, uuid, inv_type); + break; + + case LLAssetType::AT_SOUND: + if(!(inv_type == LLInventoryType::IT_SOUND)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLSoundBridge(inventory, uuid); + break; + + case LLAssetType::AT_LANDMARK: + if(!(inv_type == LLInventoryType::IT_LANDMARK)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLLandmarkBridge(inventory, uuid, flags); + break; + + case LLAssetType::AT_CALLINGCARD: + if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLCallingCardBridge(inventory, uuid); + break; + + case LLAssetType::AT_SCRIPT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLScriptBridge(inventory, uuid); + break; + + case LLAssetType::AT_OBJECT: + if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); + break; + + case LLAssetType::AT_NOTECARD: + if(!(inv_type == LLInventoryType::IT_NOTECARD)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLNotecardBridge(inventory, uuid); + break; + + case LLAssetType::AT_ANIMATION: + if(!(inv_type == LLInventoryType::IT_ANIMATION)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLAnimationBridge(inventory, uuid); + break; + + case LLAssetType::AT_GESTURE: + if(!(inv_type == LLInventoryType::IT_GESTURE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLGestureBridge(inventory, uuid); + break; + + case LLAssetType::AT_LSL_TEXT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLLSLTextBridge(inventory, uuid); + break; + + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + if(!(inv_type == LLInventoryType::IT_WEARABLE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); + break; + case LLAssetType::AT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // Create a link folder handler instead. + new_listener = new LLLinkFolderBridge(inventory, uuid); + break; + } + new_listener = new LLFolderBridge(inventory, uuid); + break; + case LLAssetType::AT_LINK: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; + case LLAssetType::AT_LINK_FOLDER: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; + default: + llinfos << "Unhandled asset type (llassetstorage.h): " + << (S32)asset_type << llendl; + break; + } + + if (new_listener) + { + new_listener->mInvType = inv_type; + } + + return new_listener; +} + +void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) +{ + LLInventoryCategory* cat = model->getCategory(uuid); + if (cat) + { + model->purgeDescendentsOf(uuid); + model->notifyObservers(); + } + LLInventoryObject* obj = model->getObject(uuid); + if (obj) + { + model->purgeObject(uuid); + model->notifyObservers(); + } +} + +// +=================================================+ +// | InventoryFVBridgeBuilder | +// +=================================================+ +LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + const LLUUID& uuid, + U32 flags /* = 0x00 */) const +{ + return LLInvFVBridge::createBridge(asset_type, + actual_asset_type, + inv_type, + inventory, + uuid, + flags); +} + +// +=================================================+ +// | LLItemBridge | +// +=================================================+ + +void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("goto" == action) + { + gotoItem(folder); + } + if ("open" == action) + { + openItem(); + return; + } + else if ("properties" == action) + { + showProperties(); + return; + } + else if ("purge" == action) + { + purgeItem(model, mUUID); + return; + } + else if ("restoreToWorld" == action) + { + restoreToWorld(); + return; + } + else if ("restore" == action) + { + restoreItem(); + return; + } + else if ("copy_uuid" == action) + { + // Single item only + LLInventoryItem* item = model->getItem(mUUID); + if(!item) return; + LLUUID asset_id = item->getAssetUUID(); + std::string buffer; + asset_id.toString(buffer); + + gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer)); + return; + } + else if ("copy" == action) + { + copyToClipboard(); + return; + } + else if ("paste" == action) + { + // Single item only + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + if (!folder_view_itemp) return; + + folder_view_itemp->getListener()->pasteFromClipboard(); + return; + } + else if ("paste_link" == action) + { + // Single item only + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + if (!folder_view_itemp) return; + + folder_view_itemp->getListener()->pasteLinkFromClipboard(); + return; + } +} + +void LLItemBridge::selectItem() +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); + if(item && !item->isComplete()) + { + item->fetchFromServer(); + } +} + +void LLItemBridge::restoreItem() +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); + if(item) + { + LLInventoryModel* model = getInventoryModel(); + const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); + // do not restamp on restore. + LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE); + } +} + +void LLItemBridge::restoreToWorld() +{ + LLViewerInventoryItem* itemp = (LLViewerInventoryItem*)getItem(); + if (itemp) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("RezRestoreToWorld"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_InventoryData); + itemp->packMessage(msg); + msg->sendReliable(gAgent.getRegion()->getHost()); + } + + //Similar functionality to the drag and drop rez logic + BOOL remove_from_inventory = FALSE; + + //remove local inventory copy, sim will deal with permissions and removing the item + //from the actual inventory if its a no-copy etc + if(!itemp->getPermissions().allowCopyBy(gAgent.getID())) + { + remove_from_inventory = TRUE; + } + + // Check if it's in the trash. (again similar to the normal rez logic) + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id)) + { + remove_from_inventory = TRUE; + } + + if(remove_from_inventory) + { + gInventory.deleteObject(itemp->getUUID()); + gInventory.notifyObservers(); + } +} + +void LLItemBridge::gotoItem(LLFolderView *folder) +{ + LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); + if (active_panel) + { + active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } + } +} + +LLUIImagePtr LLItemBridge::getIcon() const +{ + return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); +} + +PermissionMask LLItemBridge::getPermissionMask() const +{ + LLViewerInventoryItem* item = getItem(); + PermissionMask perm_mask = 0; + if(item) + { + BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); + BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); + BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, + gAgent.getID()); + + if (copy) perm_mask |= PERM_COPY; + if (mod) perm_mask |= PERM_MODIFY; + if (xfer) perm_mask |= PERM_TRANSFER; + + } + return perm_mask; +} + +const std::string& LLItemBridge::getDisplayName() const +{ + if(mDisplayName.empty()) + { + buildDisplayName(getItem(), mDisplayName); + } + return mDisplayName; +} + +void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name) +{ + if(item) + { + name.assign(item->getName()); + } + else + { + name.assign(LLStringUtil::null); + } +} + +LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const +{ + U8 font = LLFontGL::NORMAL; + + if( gAgentWearables.isWearingItem( mUUID ) ) + { + // llinfos << "BOLD" << llendl; + font |= LLFontGL::BOLD; + } + + const LLViewerInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + font |= LLFontGL::ITALIC; + } + return (LLFontGL::StyleFlags)font; +} + +std::string LLItemBridge::getLabelSuffix() const +{ + // String table is loaded before login screen and inventory items are + // loaded after login, so LLTrans should be ready. + static std::string NO_COPY =LLTrans::getString("no_copy"); + static std::string NO_MOD = LLTrans::getString("no_modify"); + static std::string NO_XFER = LLTrans::getString("no_transfer"); + static std::string LINK = LLTrans::getString("link"); + static std::string BROKEN_LINK = LLTrans::getString("broken_link"); + std::string suffix; + LLInventoryItem* item = getItem(); + if(item) + { + // it's a bit confusing to put nocopy/nomod/etc on calling cards. + if(LLAssetType::AT_CALLINGCARD != item->getType() + && item->getPermissions().getOwner() == gAgent.getID()) + { + BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); + if (broken_link) return BROKEN_LINK; + + BOOL link = item->getIsLinkType(); + if (link) return LINK; + + BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); + if (!copy) + { + suffix += NO_COPY; + } + BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); + if (!mod) + { + suffix += NO_MOD; + } + BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, + gAgent.getID()); + if (!xfer) + { + suffix += NO_XFER; + } + } + } + return suffix; +} + +time_t LLItemBridge::getCreationDate() const +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + return item->getCreationDate(); + } + return 0; +} + + +BOOL LLItemBridge::isItemRenameable() const +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + // (For now) Don't allow calling card rename since that may confuse users as to + // what the calling card points to. + if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + return FALSE; + } + return (item->getPermissions().allowModifyBy(gAgent.getID())); + } + return FALSE; +} + +BOOL LLItemBridge::renameItem(const std::string& new_name) +{ + if(!isItemRenameable()) + return FALSE; + LLPreview::dirty(mUUID); + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; + LLViewerInventoryItem* item = getItem(); + if(item && (item->getName() != new_name)) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->rename(new_name); + buildDisplayName(new_item, mDisplayName); + new_item->updateServer(FALSE); + model->updateItem(new_item); + + model->notifyObservers(); + } + // return FALSE because we either notified observers (& therefore + // rebuilt) or we didn't update. + return FALSE; +} + + +BOOL LLItemBridge::removeItem() +{ + if(!isItemRemovable()) + { + return FALSE; + } + // move it to the trash + LLPreview::hide(mUUID, TRUE); + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + LLViewerInventoryItem* item = getItem(); + + // if item is not already in trash + if(item && !model->isObjectDescendentOf(mUUID, trash_id)) + { + // move to trash, and restamp + LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE); + // delete was successful + return TRUE; + } + else + { + // tried to delete already item in trash (should purge?) + return FALSE; + } +} + +BOOL LLItemBridge::isItemCopyable() const +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + // can't copy worn objects. DEV-15183 + LLVOAvatarSelf *avatarp = gAgent.getAvatarObject(); + if( !avatarp ) + { + return FALSE; + } + + if(avatarp->isWearingAttachment(mUUID)) + { + return FALSE; + } + + // All items can be copied, not all can be pasted. + // The only time an item can't be copied is if it's a link + // return (item->getPermissions().allowCopyBy(gAgent.getID())); + if (item->getIsLinkType()) + { + return FALSE; + } + return TRUE; + } + return FALSE; +} +BOOL LLItemBridge::copyToClipboard() const +{ + if(isItemCopyable()) + { + LLInventoryClipboard::instance().add(mUUID); + return TRUE; + } + return FALSE; +} + +LLViewerInventoryItem* LLItemBridge::getItem() const +{ + LLViewerInventoryItem* item = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + item = (LLViewerInventoryItem*)model->getItem(mUUID); + } + return item; +} + +BOOL LLItemBridge::isItemPermissive() const +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + U32 mask = item->getPermissions().getMaskBase(); + if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) + { + return TRUE; + } + } + return FALSE; +} + +// +=================================================+ +// | LLFolderBridge | +// +=================================================+ + +LLFolderBridge* LLFolderBridge::sSelf=NULL; + +// Can be moved to another folder +BOOL LLFolderBridge::isItemMovable() const +{ + LLInventoryObject* obj = getInventoryObject(); + if(obj) + { + return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())); + } + return FALSE; +} + +void LLFolderBridge::selectItem() +{ +} + + +// Can be destroyed (or moved to trash) +BOOL LLFolderBridge::isItemRemovable() +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) + { + return FALSE; + } + + if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) + { + return FALSE; + } + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if( !avatar ) + { + return FALSE; + } + + LLInventoryCategory* category = model->getCategory(mUUID); + if( !category ) + { + return FALSE; + } + + if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + { + return FALSE; + } + + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); + + S32 i; + for( i = 0; i < descendent_categories.count(); i++ ) + { + LLInventoryCategory* category = descendent_categories[i]; + if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + { + return FALSE; + } + } + + for( i = 0; i < descendent_items.count(); i++ ) + { + LLInventoryItem* item = descendent_items[i]; + if( (item->getType() == LLAssetType::AT_CLOTHING) || + (item->getType() == LLAssetType::AT_BODYPART) ) + { + if(gAgentWearables.isWearingItem(item->getUUID())) + { + return FALSE; + } + } + else + if( item->getType() == LLAssetType::AT_OBJECT ) + { + if(avatar->isWearingAttachment(item->getUUID())) + { + return FALSE; + } + } + } + + return TRUE; +} + +BOOL LLFolderBridge::isUpToDate() const +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); + if( !category ) + { + return FALSE; + } + + return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; +} + +BOOL LLFolderBridge::isItemCopyable() const +{ + return TRUE; +} + +BOOL LLFolderBridge::copyToClipboard() const +{ + if(isItemCopyable()) + { + LLInventoryClipboard::instance().add(mUUID); + return TRUE; + } + return FALSE; +} + +BOOL LLFolderBridge::isClipboardPasteable() const +{ + if ( ! LLInvFVBridge::isClipboardPasteable() ) + return FALSE; + + // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 + if ( LLFriendCardsManager::instance().isCategoryInFriendFolder( getCategory() ) ) + { + LLInventoryModel* model = getInventoryModel(); + if ( !model ) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + const LLViewerInventoryCategory *current_cat = getCategory(); + + // Search for the direct descendent of current Friends subfolder among all pasted items, + // and return false if is found. + for(S32 i = objects.count() - 1; i >= 0; --i) + { + const LLUUID &obj_id = objects.get(i); + if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) + { + return FALSE; + } + } + + } + return TRUE; +} + +BOOL LLFolderBridge::isClipboardPasteableAsLink() const +{ + // Check normal paste-as-link permissions + if (!LLInvFVBridge::isClipboardPasteableAsLink()) + { + return FALSE; + } + + const LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return FALSE; + } + + const LLViewerInventoryCategory *current_cat = getCategory(); + if (current_cat) + { + const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder( current_cat ); + const LLUUID ¤t_cat_id = current_cat->getUUID(); + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &obj_id = objects.get(i); + const LLInventoryCategory *cat = model->getCategory(obj_id); + if (cat) + { + const LLUUID &cat_id = cat->getUUID(); + // Don't allow recursive pasting + if ((cat_id == current_cat_id) || + model->isObjectDescendentOf(current_cat_id, cat_id)) + { + return FALSE; + } + } + // Don't allow pasting duplicates to the Calling Card/Friends subfolders, see bug EXT-1599 + if ( is_in_friend_folder ) + { + // If object is direct descendent of current Friends subfolder than return false. + // Note: We can't use 'const LLInventoryCategory *cat', because it may be null + // in case type of obj_id is LLInventoryItem. + if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) + { + return FALSE; + } + } + } + } + return TRUE; + +} + +BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, + BOOL drop) +{ + // This should never happen, but if an inventory item is incorrectly parented, + // the UI will get confused and pass in a NULL. + if(!inv_cat) return FALSE; + + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if(!avatar) return FALSE; + + // cannot drag categories into library + if(!isAgentInventory()) + { + return FALSE; + } + + // check to make sure source is agent inventory, and is represented there. + LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); + BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) + && (LLToolDragAndDrop::SOURCE_AGENT == source); + + BOOL accept = FALSE; + S32 i; + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + if(is_agent_inventory) + { + const LLUUID& cat_id = inv_cat->getUUID(); + + // Is the destination the trash? + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + BOOL move_is_into_trash = (mUUID == trash_id) + || model->isObjectDescendentOf(mUUID, trash_id); + BOOL is_movable = (!LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())); + const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + if (move_is_into_current_outfit || move_is_into_outfit) + { + // BAP - restrictions? + is_movable = true; + } + + if (mUUID == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)) + { + is_movable = FALSE; // It's generally movable but not into Favorites folder. EXT-1604 + } + + if( is_movable ) + { + gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); + + for( i = 0; i < descendent_categories.count(); i++ ) + { + LLInventoryCategory* category = descendent_categories[i]; + if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) + { + // ...can't move "special folders" like Textures + is_movable = FALSE; + break; + } + } + + if( is_movable ) + { + if( move_is_into_trash ) + { + for( i = 0; i < descendent_items.count(); i++ ) + { + LLInventoryItem* item = descendent_items[i]; + if( (item->getType() == LLAssetType::AT_CLOTHING) || + (item->getType() == LLAssetType::AT_BODYPART) ) + { + if( gAgentWearables.isWearingItem( item->getUUID() ) ) + { + is_movable = FALSE; // It's generally movable, but not into the trash! + break; + } + } + else + if( item->getType() == LLAssetType::AT_OBJECT ) + { + if( avatar->isWearingAttachment( item->getUUID() ) ) + { + is_movable = FALSE; // It's generally movable, but not into the trash! + break; + } + } + } + } + } + } + + + accept = is_movable + && (mUUID != cat_id) // Can't move a folder into itself + && (mUUID != inv_cat->getParentUUID()) // Avoid moves that would change nothing + && !(model->isObjectDescendentOf(mUUID, cat_id)); // Avoid circularity + if(accept && drop) + { + // Look for any gestures and deactivate them + if (move_is_into_trash) + { + for (i = 0; i < descendent_items.count(); i++) + { + LLInventoryItem* item = descendent_items[i]; + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureManager::instance().isGestureActive(item->getUUID())) + { + LLGestureManager::instance().deactivateGesture(item->getUUID()); + } + } + } + // if target is an outfit or current outfit folder we use link + if (move_is_into_current_outfit || move_is_into_outfit) + { + if (inv_cat->getPreferredType() == LLFolderType::FT_NONE) + { + if (move_is_into_current_outfit) + { + // traverse category and add all contents to currently worn. + BOOL append = true; + LLAppearanceManager::instance().wearInventoryCategory(inv_cat, false, append); + } + else + { + // Recursively create links in target outfit. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(inv_cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH); + LLAppearanceManager::instance().linkAll(mUUID,items,NULL); + } + } + else + { +#if SUPPORT_ENSEMBLES + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceManager::instance().addEnsembleLink(inv_cat); + } + else + { + LLPointer cb = NULL; + link_inventory_item( + gAgent.getID(), + inv_cat->getUUID(), + mUUID, + inv_cat->getName(), + LLAssetType::AT_LINK_FOLDER, + cb); + } +#endif + } + } + else + { + + // Reparent the folder and restamp children if it's moving + // into trash. + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + move_is_into_trash); + } + } + } + else if(LLToolDragAndDrop::SOURCE_WORLD == source) + { + // content category has same ID as object itself + LLUUID object_id = inv_cat->getUUID(); + LLUUID category_id = mUUID; + accept = move_inv_category_world_to_agent(object_id, category_id, drop); + } + return accept; +} + +void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv) +{ + const char* dialog = NULL; + if (object->flagScripted()) + { + dialog = "MoveInventoryFromScriptedObject"; + } + else + { + dialog = "MoveInventoryFromObject"; + } + LLNotifications::instance().add(dialog, LLSD(), LLSD(), boost::bind(move_task_inventory_callback, _1, _2, move_inv)); +} + +// Move/copy all inventory items from the Contents folder of an in-world +// object to the agent's inventory, inside a given category. +BOOL move_inv_category_world_to_agent(const LLUUID& object_id, + const LLUUID& category_id, + BOOL drop, + void (*callback)(S32, void*), + void* user_data) +{ + // Make sure the object exists. If we allowed dragging from + // anonymous objects, it would be possible to bypass + // permissions. + // content category has same ID as object itself + LLViewerObject* object = gObjectList.findObject(object_id); + if(!object) + { + llinfos << "Object not found for drop." << llendl; + return FALSE; + } + + // this folder is coming from an object, as there is only one folder in an object, the root, + // we need to collect the entire contents and handle them as a group + InventoryObjectList inventory_objects; + object->getInventoryContents(inventory_objects); + + if (inventory_objects.empty()) + { + llinfos << "Object contents not found for drop." << llendl; + return FALSE; + } + + BOOL accept = TRUE; + BOOL is_move = FALSE; + + // coming from a task. Need to figure out if the person can + // move/copy this item. + InventoryObjectList::iterator it = inventory_objects.begin(); + InventoryObjectList::iterator end = inventory_objects.end(); + for ( ; it != end; ++it) + { + // coming from a task. Need to figure out if the person can + // move/copy this item. + LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions()); + if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) + && perm.allowTransferTo(gAgent.getID()))) +// || gAgent.isGodlike()) + { + accept = TRUE; + } + else if(object->permYouOwner()) + { + // If the object cannot be copied, but the object the + // inventory is owned by the agent, then the item can be + // moved from the task to agent inventory. + is_move = TRUE; + accept = TRUE; + } + else + { + accept = FALSE; + break; + } + } + + if(drop && accept) + { + it = inventory_objects.begin(); + InventoryObjectList::iterator first_it = inventory_objects.begin(); + LLMoveInv* move_inv = new LLMoveInv; + move_inv->mObjectID = object_id; + move_inv->mCategoryID = category_id; + move_inv->mCallback = callback; + move_inv->mUserData = user_data; + + for ( ; it != end; ++it) + { + two_uuids_t two(category_id, (*it)->getUUID()); + move_inv->mMoveList.push_back(two); + } + + if(is_move) + { + // Callback called from within here. + warn_move_inventory(object, move_inv); + } + else + { + LLNotification::Params params("MoveInventoryFromObject"); + params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + LLNotifications::instance().forceResponse(params, 0); + } + } + return accept; +} + +bool LLFindCOFValidItems::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + // Valid COF items are: + // - links to wearables (body parts or clothing) + // - links to attachments + // - links to gestures + // - links to ensemble folders + LLViewerInventoryItem *linked_item = ((LLViewerInventoryItem*)item)->getLinkedItem(); // BAP - safe? + if (linked_item) + { + LLAssetType::EType type = linked_item->getType(); + return (type == LLAssetType::AT_CLOTHING || + type == LLAssetType::AT_BODYPART || + type == LLAssetType::AT_GESTURE || + type == LLAssetType::AT_OBJECT); + } + else + { + LLViewerInventoryCategory *linked_category = ((LLViewerInventoryItem*)item)->getLinkedCategory(); // BAP - safe? + // BAP remove AT_NONE support after ensembles are fully working? + return (linked_category && + ((linked_category->getPreferredType() == LLFolderType::FT_NONE) || + (LLFolderType::lookupIsEnsembleType(linked_category->getPreferredType())))); + } +} + + +bool LLFindWearables::operator()(LLInventoryCategory* cat, + LLInventoryItem* item) +{ + if(item) + { + if((item->getType() == LLAssetType::AT_CLOTHING) + || (item->getType() == LLAssetType::AT_BODYPART)) + { + return TRUE; + } + } + return FALSE; +} + + + +//Used by LLFolderBridge as callback for directory recursion. +class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver +{ +public: + LLRightClickInventoryFetchObserver() : + mCopyItems(false) + { }; + LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) : + mCatID(cat_id), + mCopyItems(copy_items) + { }; + virtual void done() + { + // we've downloaded all the items, so repaint the dialog + LLFolderBridge::staticFolderOptionsMenu(); + + gInventory.removeObserver(this); + delete this; + } + + +protected: + LLUUID mCatID; + bool mCopyItems; + +}; + +//Used by LLFolderBridge as callback for directory recursion. +class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver +{ +public: + LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {} + ~LLRightClickInventoryFetchDescendentsObserver() {} + virtual void done(); +protected: + bool mCopyItems; +}; + +void LLRightClickInventoryFetchDescendentsObserver::done() +{ + // Avoid passing a NULL-ref as mCompleteFolders.front() down to + // gInventory.collectDescendents() + if( mCompleteFolders.empty() ) + { + llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; + dec_busy_count(); + gInventory.removeObserver(this); + delete this; + return; + } + + // What we do here is get the complete information on the items in + // the library, and set up an observer that will wait for that to + // happen. + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(mCompleteFolders.front(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + S32 count = item_array.count(); +#if 0 // HACK/TODO: Why? + // This early causes a giant menu to get produced, and doesn't seem to be needed. + if(!count) + { + llwarns << "Nothing fetched in category " << mCompleteFolders.front() + << llendl; + dec_busy_count(); + gInventory.removeObserver(this); + delete this; + return; + } +#endif + + LLRightClickInventoryFetchObserver* outfit; + outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems); + LLInventoryFetchObserver::item_ref_t ids; + for(S32 i = 0; i < count; ++i) + { + ids.push_back(item_array.get(i)->getUUID()); + } + + // clean up, and remove this as an observer since the call to the + // outfit could notify observers and throw us into an infinite + // loop. + dec_busy_count(); + gInventory.removeObserver(this); + delete this; + + // increment busy count and either tell the inventory to check & + // call done, or add this object to the inventory for observation. + inc_busy_count(); + + // do the fetch + outfit->fetchItems(ids); + outfit->done(); //Not interested in waiting and this will be right 99% of the time. +//Uncomment the following code for laggy Inventory UI. +/* if(outfit->isEverythingComplete()) + { + // everything is already here - call done. + outfit->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(outfit); + }*/ +} + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryWearObserver +// +// Observer for "copy and wear" operation to support knowing +// when the all of the contents have been added to inventory. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryCopyAndWearObserver : public LLInventoryObserver +{ +public: + LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {} + virtual ~LLInventoryCopyAndWearObserver() {} + virtual void changed(U32 mask); + +protected: + LLUUID mCatID; + int mContentsCount; + BOOL mFolderAdded; +}; + + + +void LLInventoryCopyAndWearObserver::changed(U32 mask) +{ + if((mask & (LLInventoryObserver::ADD)) != 0) + { + if (!mFolderAdded) + { + const std::set& changed_items = gInventory.getChangedIDs(); + + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + if ((*id_it) == mCatID) + { + mFolderAdded = TRUE; + break; + } + } + } + + if (mFolderAdded) + { + LLViewerInventoryCategory* category = gInventory.getCategory(mCatID); + + if (NULL == category) + { + llwarns << "gInventory.getCategory(" << mCatID + << ") was NULL" << llendl; + } + else + { + if (category->getDescendentCount() == + mContentsCount) + { + gInventory.removeObserver(this); + LLAppearanceManager::instance().wearInventoryCategory(category, FALSE, TRUE); + delete this; + } + } + } + + } +} + + + +void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("open" == action) + { + openItem(); + return; + } + else if ("paste" == action) + { + pasteFromClipboard(); + return; + } + else if ("paste_link" == action) + { + pasteLinkFromClipboard(); + return; + } + else if ("properties" == action) + { + showProperties(); + return; + } + else if ("replaceoutfit" == action) + { + modifyOutfit(FALSE); + return; + } +#if SUPPORT_ENSEMBLES + else if ("wearasensemble" == action) + { + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + LLViewerInventoryCategory* cat = getCategory(); + if(!cat) return; + LLAppearanceManager::instance().addEnsembleLink(cat,true); + return; + } +#endif + else if ("addtooutfit" == action) + { + modifyOutfit(TRUE); + return; + } + else if ("copy" == action) + { + copyToClipboard(); + return; + } + else if ("removefromoutfit" == action) + { + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + LLViewerInventoryCategory* cat = getCategory(); + if(!cat) return; + + remove_inventory_category_from_avatar ( cat ); + return; + } + else if ("purge" == action) + { + purgeItem(model, mUUID); + return; + } + else if ("restore" == action) + { + restoreItem(); + return; + } +} + +void LLFolderBridge::openItem() +{ + lldebugs << "LLFolderBridge::openItem()" << llendl; + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + if(mUUID.isNull()) return; + bool fetching_inventory = model->fetchDescendentsOf(mUUID); + // Only change folder type if we have the folder contents. + if (!fetching_inventory) + { + // Disabling this for now, it's causing crash when new items are added to folders + // since folder type may change before new item item has finished processing. + // determineFolderType(); + } +} + +void LLFolderBridge::closeItem() +{ + determineFolderType(); +} + +void LLFolderBridge::determineFolderType() +{ + if (isUpToDate()) + { + LLInventoryModel* model = getInventoryModel(); + LLViewerInventoryCategory* category = model->getCategory(mUUID); + category->determineFolderType(); + } +} + +BOOL LLFolderBridge::isItemRenameable() const +{ + LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); + if(cat && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) + && (cat->getOwnerID() == gAgent.getID())) + { + return TRUE; + } + return FALSE; +} + +void LLFolderBridge::restoreItem() +{ + LLViewerInventoryCategory* cat; + cat = (LLViewerInventoryCategory*)getCategory(); + if(cat) + { + LLInventoryModel* model = getInventoryModel(); + const LLUUID new_parent = model->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType())); + // do not restamp children on restore + LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE); + } +} + +LLFolderType::EType LLFolderBridge::getPreferredType() const +{ + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + LLViewerInventoryCategory* cat = getCategory(); + if(cat) + { + preferred_type = cat->getPreferredType(); + } + + return preferred_type; +} + +// Icons for folders are based on the preferred type +LLUIImagePtr LLFolderBridge::getIcon() const +{ + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + LLViewerInventoryCategory* cat = getCategory(); + if(cat) + { + preferred_type = cat->getPreferredType(); + } + return getIcon(preferred_type); +} + +LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) +{ + // we only have one folder image now + return LLUI::getUIImage("Inv_FolderClosed"); +} + +BOOL LLFolderBridge::renameItem(const std::string& new_name) +{ + if(!isItemRenameable()) + return FALSE; + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; + LLViewerInventoryCategory* cat = getCategory(); + if(cat && (cat->getName() != new_name)) + { + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->rename(new_name); + new_cat->updateServer(FALSE); + model->updateCategory(new_cat); + + model->notifyObservers(); + } + // return FALSE because we either notified observers (& therefore + // rebuilt) or we didn't update. + return FALSE; +} + +BOOL LLFolderBridge::removeItem() +{ + if(!isItemRemovable()) + { + return FALSE; + } + // move it to the trash + LLPreview::hide(mUUID); + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE ); + + S32 i; + for (i = 0; i < descendent_items.count(); i++) + { + LLInventoryItem* item = descendent_items[i]; + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureManager::instance().isGestureActive(item->getUUID())) + { + LLGestureManager::instance().deactivateGesture(item->getUUID()); + } + } + + // go ahead and do the normal remove if no 'last calling + // cards' are being removed. + LLViewerInventoryCategory* cat = getCategory(); + if(cat) + { + LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE); + } + + return TRUE; +} + +void LLFolderBridge::pasteFromClipboard() +{ + LLInventoryModel* model = getInventoryModel(); + if(model && isClipboardPasteable()) + { + LLInventoryItem* item = NULL; + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + const LLUUID parent_id(mUUID); + for(S32 i = 0; i < count; i++) + { + item = model->getItem(objects.get(i)); + if (item) + { + if(LLInventoryClipboard::instance().isCutMode()) + { + // move_inventory_item() is not enough, + //we have to update inventory locally too + changeItemParent(model, dynamic_cast(item), parent_id, FALSE); + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer(NULL)); + } + } + } + } +} + +void LLFolderBridge::pasteLinkFromClipboard() +{ + const LLInventoryModel* model = getInventoryModel(); + if(model) + { + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + LLUUID parent_id(mUUID); + for(S32 i = 0; i < count; i++) + { + const LLUUID &object_id = objects.get(i); +#if SUPPORT_ENSEMBLES + if (LLInventoryCategory *cat = model->getCategory(object_id)) + { + link_inventory_item( + gAgent.getID(), + cat->getUUID(), + parent_id, + cat->getName(), + LLAssetType::AT_LINK_FOLDER, + LLPointer(NULL)); + } + else +#endif + if (LLInventoryItem *item = model->getItem(object_id)) + { + link_inventory_item( + gAgent.getID(), + item->getLinkedUUID(), + parent_id, + item->getName(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } + } + } +} + +void LLFolderBridge::staticFolderOptionsMenu() +{ + if (!sSelf) return; + sSelf->folderOptionsMenu(); +} + +void LLFolderBridge::folderOptionsMenu() +{ + std::vector disabled_items; + + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + + const LLInventoryCategory* category = model->getCategory(mUUID); + LLFolderType::EType type = category->getPreferredType(); + const bool is_default_folder = category && LLFolderType::lookupIsProtectedType(type); + // BAP change once we're no longer treating regular categories as ensembles. + const bool is_ensemble = category && (type == LLFolderType::FT_NONE || + LLFolderType::lookupIsEnsembleType(type)); + + // calling card related functionality for folders. + + // Only enable calling-card related options for non-default folders. + if (!is_default_folder) + { + LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); + if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) + { + mItems.push_back(std::string("Calling Card Separator")); + mItems.push_back(std::string("Conference Chat Folder")); + mItems.push_back(std::string("IM All Contacts In Folder")); + } + } + + // wearables related functionality for folders. + //is_wearable + LLFindWearables is_wearable; + LLIsType is_object( LLAssetType::AT_OBJECT ); + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + + if (mWearables || + checkFolderForContentsOfType(model, is_wearable) || + checkFolderForContentsOfType(model, is_object) || + checkFolderForContentsOfType(model, is_gesture) ) + { + mItems.push_back(std::string("Folder Wearables Separator")); + + // Only enable add/replace outfit for non-default folders. + if (!is_default_folder) + { + mItems.push_back(std::string("Add To Outfit")); + mItems.push_back(std::string("Replace Outfit")); + } + if (is_ensemble) + { + mItems.push_back(std::string("Wear As Ensemble")); + } + mItems.push_back(std::string("Remove From Outfit")); + } + hide_context_entries(*mMenu, mItems, disabled_items); +} + +BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + model->collectDescendentsIf(mUUID, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_type); + return ((item_array.count() > 0) ? TRUE : FALSE ); +} + +// Flags unused +void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + mItems.clear(); + mDisabledItems.clear(); + + lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; +// std::vector disabled_items; + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + + mItems.clear(); //adding code to clear out member Items (which means Items should not have other data here at this point) + mDisabledItems.clear(); //adding code to clear out disabled members from previous + if (lost_and_found_id == mUUID) + { + // This is the lost+found folder. + mItems.push_back(std::string("Empty Lost And Found")); + } + + if(trash_id == mUUID) + { + // This is the trash. + mItems.push_back(std::string("Empty Trash")); + } + else if(model->isObjectDescendentOf(mUUID, trash_id)) + { + // This is a folder in the trash. + mItems.clear(); // clear any items that used to exist + mItems.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + mDisabledItems.push_back(std::string("Purge Item")); + } + + mItems.push_back(std::string("Restore Item")); + } + else if(isAgentInventory()) // do not allow creating in library + { + LLViewerInventoryCategory *cat = getCategory(); + // BAP removed protected check to re-enable standard ops in untyped folders. + // Not sure what the right thing is to do here. + if (!isCOFFolder() && cat /*&& + LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())*/) + { + // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. + if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) + mItems.push_back(std::string("New Folder")); + mItems.push_back(std::string("New Script")); + mItems.push_back(std::string("New Note")); + mItems.push_back(std::string("New Gesture")); + mItems.push_back(std::string("New Clothes")); + mItems.push_back(std::string("New Body Parts")); + mItems.push_back(std::string("Change Type")); + + LLViewerInventoryCategory *cat = getCategory(); + if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) + { + mDisabledItems.push_back(std::string("Change Type")); + } + + getClipboardEntries(false, mItems, mDisabledItems, flags); + } + else + { + // Want some but not all of the items from getClipboardEntries for outfits. + if (cat && cat->getPreferredType()==LLFolderType::FT_OUTFIT) + { + mItems.push_back(std::string("Rename")); + mItems.push_back(std::string("Delete")); + } + } + + //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 + mCallingCards = mWearables = FALSE; + + LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); + if (checkFolderForContentsOfType(model, is_callingcard)) + { + mCallingCards=TRUE; + } + + LLFindWearables is_wearable; + LLIsType is_object( LLAssetType::AT_OBJECT ); + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + + if (checkFolderForContentsOfType(model, is_wearable) || + checkFolderForContentsOfType(model, is_object) || + checkFolderForContentsOfType(model, is_gesture) ) + { + mWearables=TRUE; + } + + mMenu = &menu; + sSelf = this; + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE); + + LLInventoryFetchDescendentsObserver::folder_ref_t folders; + LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); + if (category) + { + folders.push_back(category->getUUID()); + } + fetch->fetchDescendents(folders); + inc_busy_count(); + if(fetch->isEverythingComplete()) + { + // everything is already here - call done. + fetch->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(fetch); + } + } + else + { + mItems.push_back(std::string("--no options--")); + mDisabledItems.push_back(std::string("--no options--")); + } + hide_context_entries(menu, mItems, mDisabledItems); +} + +BOOL LLFolderBridge::hasChildren() const +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + LLInventoryModel::EHasChildren has_children; + has_children = gInventory.categoryHasChildren(mUUID); + return has_children != LLInventoryModel::CHILDREN_NO; +} + +BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) +{ + //llinfos << "LLFolderBridge::dragOrDrop()" << llendl; + BOOL accept = FALSE; + switch(cargo_type) + { + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_CALLINGCARD: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_CLOTHING: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_LINK: + accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, + drop); + break; + case DAD_CATEGORY: + if (LLFriendCardsManager::instance().isAnyFriendCategory(mUUID)) + { + accept = FALSE; + } + else + { + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, drop); + } + break; + default: + break; + } + return accept; +} + +LLViewerInventoryCategory* LLFolderBridge::getCategory() const +{ + LLViewerInventoryCategory* cat = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + cat = (LLViewerInventoryCategory*)model->getCategory(mUUID); + } + return cat; +} + + +// static +void LLFolderBridge::pasteClipboard(void* user_data) +{ + LLFolderBridge* self = (LLFolderBridge*)user_data; + if(self) self->pasteFromClipboard(); +} + +void LLFolderBridge::createNewCategory(void* user_data) +{ + LLFolderBridge* bridge = (LLFolderBridge*)user_data; + if(!bridge) return; + LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel.get()); + if (!panel) return; + LLInventoryModel* model = panel->getModel(); + if(!model) return; + LLUUID id; + id = model->createNewCategory(bridge->getUUID(), + LLFolderType::FT_NONE, + LLStringUtil::null); + model->notifyObservers(); + + // At this point, the bridge has probably been deleted, but the + // view is still there. + panel->setSelection(id, TAKE_FOCUS_YES); +} + +void LLFolderBridge::createNewShirt(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT); +} + +void LLFolderBridge::createNewPants(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS); +} + +void LLFolderBridge::createNewShoes(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES); +} + +void LLFolderBridge::createNewSocks(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS); +} + +void LLFolderBridge::createNewJacket(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET); +} + +void LLFolderBridge::createNewSkirt(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT); +} + +void LLFolderBridge::createNewGloves(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES); +} + +void LLFolderBridge::createNewUndershirt(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT); +} + +void LLFolderBridge::createNewUnderpants(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS); +} + +void LLFolderBridge::createNewShape(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE); +} + +void LLFolderBridge::createNewSkin(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN); +} + +void LLFolderBridge::createNewHair(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR); +} + +void LLFolderBridge::createNewEyes(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); +} + +// static +void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) +{ + if(!bridge) return; + LLUUID parent_id = bridge->getUUID(); + createWearable(parent_id, type); +} + +// Separate function so can be called by global menu as well as right-click +// menu. +// static +void LLFolderBridge::createWearable(const LLUUID &parent_id, EWearableType type) +{ + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); + LLAssetType::EType asset_type = wearable->getAssetType(); + LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent_id, wearable->getTransactionID(), wearable->getName(), + wearable->getDescription(), asset_type, inv_type, wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + LLPointer(NULL)); +} + +void LLFolderBridge::modifyOutfit(BOOL append) +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + LLViewerInventoryCategory* cat = getCategory(); + if(!cat) return; + + // BAP - was: + // wear_inventory_category_on_avatar( cat, append ); + LLAppearanceManager::instance().wearInventoryCategory( cat, FALSE, append ); +} + +// helper stuff +bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv* move_inv) +{ + LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData; + LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID); + S32 option = LLNotification::getSelectedOption(notification, response); + + if(option == 0 && object) + { + if (cat_and_wear && cat_and_wear->mWear) + { + InventoryObjectList inventory_objects; + object->getInventoryContents(inventory_objects); + int contents_count = inventory_objects.size()-1; //subtract one for containing folder + + LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count); + gInventory.addObserver(inventoryObserver); + } + + two_uuids_list_t::iterator move_it; + for (move_it = move_inv->mMoveList.begin(); + move_it != move_inv->mMoveList.end(); + ++move_it) + { + object->moveInventory(move_it->first, move_it->second); + } + + // update the UI. + dialog_refresh_all(); + } + + if (move_inv->mCallback) + { + move_inv->mCallback(option, move_inv->mUserData); + } + + delete move_inv; + return false; +} + +/* +Next functions intended to reorder items in the inventory folder and save order on server +Is now used for Favorites folder. + +*TODO: refactoring is needed with Favorites Bar functionality. Probably should be moved in LLInventoryModel +*/ +void saveItemsOrder(LLInventoryModel::item_array_t& items) +{ + int sortField = 0; + + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + item->setSortField(++sortField); + item->setComplete(TRUE); + item->updateServer(FALSE); + + gInventory.updateItem(item); + } + + gInventory.notifyObservers(); +} + +LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id) +{ + LLInventoryModel::item_array_t::iterator result = items.end(); + + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + if ((*i)->getUUID() == id) + { + result = i; + break; + } + } + + return result; +} + +void updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& srcItemId, const LLUUID& destItemId) +{ + LLViewerInventoryItem* srcItem = gInventory.getItem(srcItemId); + LLViewerInventoryItem* destItem = gInventory.getItem(destItemId); + + items.erase(findItemByUUID(items, srcItem->getUUID())); + items.insert(findItemByUUID(items, destItem->getUUID()), srcItem); +} + +BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, + BOOL drop) +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + + // cannot drag into library + if(!isAgentInventory()) + { + return FALSE; + } + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if(!avatar) return FALSE; + + LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); + BOOL accept = FALSE; + LLViewerObject* object = NULL; + if(LLToolDragAndDrop::SOURCE_AGENT == source) + { + + BOOL is_movable = TRUE; + switch( inv_item->getActualType() ) + { + case LLAssetType::AT_CATEGORY: + is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); + break; + default: + break; + } + + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); + const LLUUID current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + + if(is_movable && move_is_into_trash) + { + switch(inv_item->getType()) + { + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + is_movable = !gAgentWearables.isWearingItem(inv_item->getUUID()); + break; + + case LLAssetType::AT_OBJECT: + is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); + break; + default: + break; + } + } + + if ( is_movable ) + { + // Don't allow creating duplicates in the Calling Card/Friends + // subfolders, see bug EXT-1599. Check is item direct descendent + // of target folder and forbid item's movement if it so. + // Note: isItemDirectDescendentOfCategory checks if + // passed category is in the Calling Card/Friends folder + is_movable = ! LLFriendCardsManager::instance() + .isObjDirectDescendentOfCategory (inv_item, getCategory()); + } + + const LLUUID& favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + const LLUUID& landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + const BOOL folder_allows_reorder = ((mUUID == landmarks_id) || (mUUID == favorites_id)); + + // we can move item inside a folder only if this folder is Favorites. See EXT-719 + accept = is_movable && ((mUUID != inv_item->getParentUUID()) || folder_allows_reorder); + if(accept && drop) + { + if (inv_item->getType() == LLAssetType::AT_GESTURE + && LLGestureManager::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash) + { + LLGestureManager::instance().deactivateGesture(inv_item->getUUID()); + } + // If an item is being dragged between windows, unselect + // everything in the active window so that we don't follow + // the selection to its new location (which is very + // annoying). + if (LLFloaterInventory::getActiveInventory()) + { + LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + if (active_panel && (panel != active_panel)) + { + active_panel->unSelectAll(); + } + } + + // if dragging from/into favorites folder only reorder items + if ((mUUID == inv_item->getParentUUID()) && folder_allows_reorder) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_type(LLAssetType::AT_LANDMARK); + model->collectDescendentsIf(mUUID, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; + if (itemp) + { + LLUUID srcItemId = inv_item->getUUID(); + LLUUID destItemId = itemp->getListener()->getUUID(); + + // update order + updateItemsOrder(items, srcItemId, destItemId); + + saveItemsOrder(items); + } + } + else if (favorites_id == mUUID) // if target is the favorites folder we use copy + { + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + LLPointer(NULL)); + } + else if (move_is_into_current_outfit || move_is_into_outfit) + { + // BAP - should skip if dup. + if (move_is_into_current_outfit) + { + LLAppearanceManager::instance().addCOFItemLink(inv_item); + } + else + { + LLPointer cb = NULL; + link_inventory_item( + gAgent.getID(), + inv_item->getLinkedUUID(), + mUUID, + inv_item->getName(), + LLAssetType::AT_LINK, + cb); + } + } + else + { + // restamp if the move is into the trash. + LLInvFVBridge::changeItemParent( + model, + (LLViewerInventoryItem*)inv_item, + mUUID, + move_is_into_trash); + } + } + } + else if(LLToolDragAndDrop::SOURCE_WORLD == source) + { + // Make sure the object exists. If we allowed dragging from + // anonymous objects, it would be possible to bypass + // permissions. + object = gObjectList.findObject(inv_item->getParentUUID()); + if(!object) + { + llinfos << "Object not found for drop." << llendl; + return FALSE; + } + + // coming from a task. Need to figure out if the person can + // move/copy this item. + LLPermissions perm(inv_item->getPermissions()); + BOOL is_move = FALSE; + if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) + && perm.allowTransferTo(gAgent.getID()))) +// || gAgent.isGodlike()) + + { + accept = TRUE; + } + else if(object->permYouOwner()) + { + // If the object cannot be copied, but the object the + // inventory is owned by the agent, then the item can be + // moved from the task to agent inventory. + is_move = TRUE; + accept = TRUE; + } + if(drop && accept) + { + LLMoveInv* move_inv = new LLMoveInv; + move_inv->mObjectID = inv_item->getParentUUID(); + two_uuids_t item_pair(mUUID, inv_item->getUUID()); + move_inv->mMoveList.push_back(item_pair); + move_inv->mCallback = NULL; + move_inv->mUserData = NULL; + if(is_move) + { + warn_move_inventory(object, move_inv); + } + else + { + LLNotification::Params params("MoveInventoryFromObject"); + params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + LLNotifications::instance().forceResponse(params, 0); + } + } + + } + else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) + { + accept = TRUE; + if(drop) + { + copy_inventory_from_notecard(LLToolDragAndDrop::getInstance()->getObjectID(), + LLToolDragAndDrop::getInstance()->getSourceID(), inv_item); + } + } + else if(LLToolDragAndDrop::SOURCE_LIBRARY == source) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item; + if(item && item->isComplete()) + { + accept = TRUE; + if(drop) + { + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + LLPointer(NULL)); + } + } + } + else + { + llwarns << "unhandled drag source" << llendl; + } + return accept; +} + +// +=================================================+ +// | LLScriptBridge (DEPRECTED) | +// +=================================================+ + +LLUIImagePtr LLScriptBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); +} + +// +=================================================+ +// | LLTextureBridge | +// +=================================================+ + +LLUIImagePtr LLTextureBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE); +} + +void LLTextureBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +} + +void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + + items.push_back(std::string("Texture Separator")); + items.push_back(std::string("Save As")); + } + hide_context_entries(menu, items, disabled_items); +} + +// virtual +void LLTextureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("save_as" == action) + { + LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); + LLPreviewTexture* preview_texture = LLFloaterReg::findTypedInstance("preview_texture", mUUID); + if (preview_texture) + { + preview_texture->openToSave(); + } + } + else LLItemBridge::performAction(folder, model, action); +} + +// +=================================================+ +// | LLSoundBridge | +// +=================================================+ + +LLUIImagePtr LLSoundBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); +} + +void LLSoundBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* +// Changed this back to the way it USED to work: +// only open the preview dialog through the contextual right-click menu +// double-click just plays the sound + + LLViewerInventoryItem* item = getItem(); + if(item) + { + openSoundPreview((void*)this); + //send_uuid_sound_trigger(item->getAssetUUID(), 1.0); + } +*/ +} + +void LLSoundBridge::previewItem() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + send_sound_trigger(item->getAssetUUID(), 1.0); + } +} + +void LLSoundBridge::openSoundPreview(void* which) +{ + LLSoundBridge *me = (LLSoundBridge *)which; + LLFloaterReg::showInstance("preview_sound", LLSD(me->mUUID), TAKE_FOCUS_YES); +} + +void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLSoundBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Sound Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + + items.push_back(std::string("Sound Separator")); + items.push_back(std::string("Sound Play")); + + hide_context_entries(menu, items, disabled_items); +} + +// +=================================================+ +// | LLLandmarkBridge | +// +=================================================+ + +LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags/* = 0x00*/) : +LLItemBridge(inventory, uuid) +{ + mVisited = FALSE; + if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) + { + mVisited = TRUE; + } +} + +LLUIImagePtr LLLandmarkBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE); +} + +void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + std::vector items; + std::vector disabled_items; + + lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Landmark Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + + items.push_back(std::string("Landmark Separator")); + items.push_back(std::string("About Landmark")); + + // Disable "About Landmark" menu item for + // multiple landmarks selected. Only one landmark + // info panel can be shown at a time. + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("About Landmark")); + } + + hide_context_entries(menu, items, disabled_items); +} + +// Convenience function for the two functions below. +void teleport_via_landmark(const LLUUID& asset_id) +{ + gAgent.teleportViaLandmark( asset_id ); + + // we now automatically track the landmark you're teleporting to + // because you'll probably arrive at a telehub instead + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if( floater_world_map ) + { + floater_world_map->trackLandmark( asset_id ); + } +} + +// virtual +void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("teleport" == action) + { + LLViewerInventoryItem* item = getItem(); + if(item) + { + teleport_via_landmark(item->getAssetUUID()); + } + } + else if ("about" == action) + { + LLViewerInventoryItem* item = getItem(); + if(item) + { + LLSD key; + key["type"] = "landmark"; + key["id"] = item->getUUID(); + + LLSideTray::getInstance()->showPanel("panel_places", key); + } + } + else + { + LLItemBridge::performAction(folder, model, action); + } +} + +static bool open_landmark_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + LLUUID asset_id = notification["payload"]["asset_id"].asUUID(); + if (option == 0) + { + teleport_via_landmark(asset_id); + } + + return false; +} +static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFromLandmark", open_landmark_callback); + + +void LLLandmarkBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); + if( item ) + { + // Opening (double-clicking) a landmark immediately teleports, + // but warns you the first time. + // open_landmark(item); + LLSD payload; + payload["asset_id"] = item->getAssetUUID(); + LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); + } +*/ +} + + +// +=================================================+ +// | LLCallingCardObserver | +// +=================================================+ +void LLCallingCardObserver::changed(U32 mask) +{ + mBridgep->refreshFolderViewItem(); +} + +// +=================================================+ +// | LLCallingCardBridge | +// +=================================================+ + +LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) : + LLItemBridge(inventory, uuid) +{ + mObserver = new LLCallingCardObserver(this); + LLAvatarTracker::instance().addObserver(mObserver); +} + +LLCallingCardBridge::~LLCallingCardBridge() +{ + LLAvatarTracker::instance().removeObserver(mObserver); + delete mObserver; +} + +void LLCallingCardBridge::refreshFolderViewItem() +{ + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; + if (itemp) + { + itemp->refresh(); + } +} + +// virtual +void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("begin_im" == action) + { + LLViewerInventoryItem *item = getItem(); + if (item && (item->getCreatorUUID() != gAgent.getID()) && + (!item->getCreatorUUID().isNull())) + { + std::string callingcard_name; + gCacheName->getFullName(item->getCreatorUUID(), callingcard_name); + LLUUID session_id = gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + } + } + else if ("lure" == action) + { + LLViewerInventoryItem *item = getItem(); + if (item && (item->getCreatorUUID() != gAgent.getID()) && + (!item->getCreatorUUID().isNull())) + { + LLAvatarActions::offerTeleport(item->getCreatorUUID()); + } + } + else LLItemBridge::performAction(folder, model, action); +} + +LLUIImagePtr LLCallingCardBridge::getIcon() const +{ + BOOL online = FALSE; + LLViewerInventoryItem* item = getItem(); + if(item) + { + online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); + } + return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE); +} + +std::string LLCallingCardBridge::getLabelSuffix() const +{ + LLViewerInventoryItem* item = getItem(); + if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) ) + { + return LLItemBridge::getLabelSuffix() + " (online)"; + } + else + { + return LLItemBridge::getLabelSuffix(); + } +} + +void LLCallingCardBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); + if(item && !item->getCreatorUUID().isNull()) + { + LLAvatarActions::showProfile(item->getCreatorUUID()); + } +*/ +} + +void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + + LLInventoryItem* item = getItem(); + BOOL good_card = (item + && (LLUUID::null != item->getCreatorUUID()) + && (item->getCreatorUUID() != gAgent.getID())); + BOOL user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID())); + items.push_back(std::string("Send Instant Message Separator")); + items.push_back(std::string("Send Instant Message")); + items.push_back(std::string("Offer Teleport...")); + items.push_back(std::string("Conference Chat")); + + if (!good_card) + { + disabled_items.push_back(std::string("Send Instant Message")); + } + if (!good_card || !user_online) + { + disabled_items.push_back(std::string("Offer Teleport...")); + disabled_items.push_back(std::string("Conference Chat")); + } + } + hide_context_entries(menu, items, disabled_items); +} + +BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) +{ + LLViewerInventoryItem* item = getItem(); + BOOL rv = FALSE; + if(item) + { + // check the type + switch(cargo_type) + { + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_CLOTHING: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + { + LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; + const LLPermissions& perm = inv_item->getPermissions(); + if(gInventory.getItem(inv_item->getUUID()) + && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID())) + { + rv = TRUE; + if(drop) + { + LLToolDragAndDrop::giveInventory(item->getCreatorUUID(), + (LLInventoryItem*)cargo_data); + } + } + else + { + // It's not in the user's inventory (it's probably in + // an object's contents), so disallow dragging it here. + // You can't give something you don't yet have. + rv = FALSE; + } + break; + } + case DAD_CATEGORY: + { + LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data; + if( gInventory.getCategory( inv_cat->getUUID() ) ) + { + rv = TRUE; + if(drop) + { + LLToolDragAndDrop::giveInventoryCategory( + item->getCreatorUUID(), + inv_cat); + } + } + else + { + // It's not in the user's inventory (it's probably in + // an object's contents), so disallow dragging it here. + // You can't give something you don't yet have. + rv = FALSE; + } + break; + } + default: + break; + } + } + return rv; +} + +BOOL LLCallingCardBridge::removeItem() +{ + if (LLFriendCardsManager::instance().isItemInAnyFriendsList(getItem())) + { + LLAvatarActions::removeFriendDialog(getItem()->getCreatorUUID()); + return FALSE; + } + else + { + return LLItemBridge::removeItem(); + } +} +// +=================================================+ +// | LLNotecardBridge | +// +=================================================+ + +LLUIImagePtr LLNotecardBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); +} + +void LLNotecardBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); + } +*/ +} + + +// +=================================================+ +// | LLGestureBridge | +// +=================================================+ + +LLUIImagePtr LLGestureBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); +} + +LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const +{ + if( LLGestureManager::instance().isGestureActive(mUUID) ) + { + return LLFontGL::BOLD; + } + else + { + return LLFontGL::NORMAL; + } +} + +std::string LLGestureBridge::getLabelSuffix() const +{ + if( LLGestureManager::instance().isGestureActive(mUUID) ) + { + return LLItemBridge::getLabelSuffix() + " (active)"; + } + else + { + return LLItemBridge::getLabelSuffix(); + } +} + +// virtual +void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("activate" == action) + { + LLGestureManager::instance().activateGesture(mUUID); + + LLViewerInventoryItem* item = gInventory.getItem(mUUID); + if (!item) return; + + // Since we just changed the suffix to indicate (active) + // the server doesn't need to know, just the viewer. + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + else if ("deactivate" == action) + { + LLGestureManager::instance().deactivateGesture(mUUID); + + LLViewerInventoryItem* item = gInventory.getItem(mUUID); + if (!item) return; + + // Since we just changed the suffix to indicate (active) + // the server doesn't need to know, just the viewer. + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + else LLItemBridge::performAction(folder, model, action); +} + +void LLGestureBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); + preview->setFocus(TRUE); + } +*/ +} + +BOOL LLGestureBridge::removeItem() +{ + // Force close the preview window, if it exists + LLGestureManager::instance().deactivateGesture(mUUID); + return LLItemBridge::removeItem(); +} + +void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + LLInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + } + items.push_back(std::string("Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + + items.push_back(std::string("Gesture Separator")); + items.push_back(std::string("Activate")); + items.push_back(std::string("Deactivate")); + } + hide_context_entries(menu, items, disabled_items); +} + +// +=================================================+ +// | LLAnimationBridge | +// +=================================================+ + +LLUIImagePtr LLAnimationBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); +} + +void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + std::vector items; + std::vector disabled_items; + + lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Animation Open")); + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + } + + items.push_back(std::string("Animation Separator")); + items.push_back(std::string("Animation Play")); + items.push_back(std::string("Animation Audition")); + + hide_context_entries(menu, items, disabled_items); + +} + +// virtual +void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ((action == "playworld") || (action == "playlocal")) + { + if (getItem()) + { + LLPreviewAnim::e_activation_type activate = LLPreviewAnim::NONE; + if ("playworld" == action) activate = LLPreviewAnim::PLAY; + if ("playlocal" == action) activate = LLPreviewAnim::AUDITION; + + LLPreviewAnim* preview = LLFloaterReg::showTypedInstance("preview_anim", LLSD(mUUID)); + if (preview) + { + preview->activate(activate); + } + } + } + else + { + LLItemBridge::performAction(folder, model, action); + } +} + +void LLAnimationBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); + } +*/ +} + +// +=================================================+ +// | LLObjectBridge | +// +=================================================+ + +// static +LLUUID LLObjectBridge::sContextMenuItemID; + +LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : +LLItemBridge(inventory, uuid), mInvType(type) +{ + mAttachPt = (flags & 0xff); // low bye of inventory flags + + mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; +} + +BOOL LLObjectBridge::isItemRemovable() +{ + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if(!avatar) return FALSE; + if(avatar->isWearingAttachment(mUUID)) return FALSE; + return LLInvFVBridge::isItemRemovable(); +} + +LLUIImagePtr LLObjectBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); +} + +LLInventoryObject* LLObjectBridge::getObject() const +{ + LLInventoryObject* object = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + object = (LLInventoryObject*)model->getObject(mUUID); + } + return object; +} + +// virtual +void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("attach" == action) + { + LLUUID object_id = mUUID; + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(object_id); + if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) + { + rez_attachment(item, NULL); + } + else if(item && item->isComplete()) + { + // must be in library. copy it to our inventory and put it on. + LLPointer cb = new RezAttachmentCallback(0); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + gFocusMgr.setKeyboardFocus(NULL); + } + else if ("detach" == action) + { + LLInventoryItem* item = gInventory.getItem(mUUID); + if(item) + { + gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); + gMessageSystem->sendReliable( gAgent.getRegion()->getHost()); + } + // this object might have been selected, so let the selection manager know it's gone now + LLViewerObject *found_obj = gObjectList.findObject(item->getLinkedUUID()); + if (found_obj) + { + LLSelectMgr::getInstance()->remove(found_obj); + } + } + else LLItemBridge::performAction(folder, model, action); +} + +void LLObjectBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + + LLSD key; + key["id"] = mUUID; + LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); + + // Disable old properties floater; this is replaced by the sidepanel. + /* + LLFloaterReg::showInstance("properties", mUUID); + */ +} + +LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const +{ + U8 font = LLFontGL::NORMAL; + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if( avatar && avatar->isWearingAttachment( mUUID ) ) + { + font |= LLFontGL::BOLD; + } + + LLInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + font |= LLFontGL::ITALIC; + } + + return (LLFontGL::StyleFlags)font; +} + +std::string LLObjectBridge::getLabelSuffix() const +{ + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if( avatar && avatar->isWearingAttachment( mUUID ) ) + { + std::string attachment_point_name = avatar->getAttachedPointName(mUUID); + + // e.g. "(worn on ...)" / "(attached to ...)" + LLStringUtil::format_map_t args; + args["[ATTACHMENT_POINT]"] = attachment_point_name.c_str(); + return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); + } + else + { + return LLItemBridge::getLabelSuffix(); + } +} + +void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) +{ + LLSD payload; + payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. + + S32 attach_pt = 0; + if (gAgent.getAvatarObject() && attachment) + { + for (LLVOAvatar::attachment_map_t::iterator iter = gAgent.getAvatarObject()->mAttachmentPoints.begin(); + iter != gAgent.getAvatarObject()->mAttachmentPoints.end(); ++iter) + { + if (iter->second == attachment) + { + attach_pt = iter->first; + break; + } + } + } + + payload["attachment_point"] = attach_pt; + +#if !ENABLE_MULTIATTACHMENTS + if (attachment && attachment->getNumObjects() > 0) + { + LLNotifications::instance().add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez); + } + else +#endif + { + LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); + } +} + +bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response) +{ + LLVOAvatar *avatarp = gAgent.getAvatarObject(); + + if (!avatarp->canAttachMoreObjects()) + { + LLSD args; + args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); + LLNotifications::instance().add("MaxAttachmentsOnOutfit", args); + return false; + } + + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0/*YES*/) + { + LLViewerInventoryItem* itemp = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + + if (itemp) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); + U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); +#if ENABLE_MULTIATTACHMENTS + attachment_pt |= ATTACHMENT_ADD; +#endif + msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); + pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); + msg->addStringFast(_PREHASH_Name, itemp->getName()); + msg->addStringFast(_PREHASH_Description, itemp->getDescription()); + msg->sendReliable(gAgent.getRegion()->getHost()); + } + } + return false; +} +static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez); + +void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + std::vector items; + std::vector disabled_items; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + LLInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + } + + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + + LLObjectBridge::sContextMenuItemID = mUUID; + + if(item) + { + LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); + if( !avatarp ) + { + return; + } + + if( avatarp->isWearingAttachment( mUUID ) ) + { + items.push_back(std::string("Detach From Yourself")); + } + else + if( !isInTrash() && !isLinkedObjectInTrash() ) + { + items.push_back(std::string("Attach Separator")); + items.push_back(std::string("Object Wear")); + items.push_back(std::string("Attach To")); + items.push_back(std::string("Attach To HUD")); + // commented out for DEV-32347 + //items.push_back(std::string("Restore to Last Position")); + + if (!avatarp->canAttachMoreObjects()) + { + disabled_items.push_back(std::string("Object Wear")); + disabled_items.push_back(std::string("Attach To")); + disabled_items.push_back(std::string("Attach To HUD")); + } + LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); + LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); + LLVOAvatar *avatarp = gAgent.getAvatarObject(); + if (attach_menu + && (attach_menu->getChildCount() == 0) + && attach_hud_menu + && (attach_hud_menu->getChildCount() == 0) + && avatarp) + { + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + LLMenuItemCallGL::Params p; + std::string submenu_name = attachment->getName(); + if (LLTrans::getString(submenu_name) != "") + { + p.name = (" ")+LLTrans::getString(submenu_name)+" "; + } + else + { + p.name = submenu_name; + } + LLSD cbparams; + cbparams["index"] = curiter->first; + cbparams["label"] = attachment->getName(); + p.on_click.function_name = "Inventory.AttachObject"; + p.on_click.parameter = LLSD(attachment->getName()); + p.on_enable.function_name = "Attachment.Label"; + p.on_enable.parameter = cbparams; + LLView* parent = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu; + LLUICtrlFactory::create(p, parent); + } + } + } + } + } + hide_context_entries(menu, items, disabled_items); +} + +BOOL LLObjectBridge::renameItem(const std::string& new_name) +{ + if(!isItemRenameable()) + return FALSE; + LLPreview::dirty(mUUID); + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; + LLViewerInventoryItem* item = getItem(); + if(item && (item->getName() != new_name)) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->rename(new_name); + buildDisplayName(new_item, mDisplayName); + new_item->updateServer(FALSE); + model->updateItem(new_item); + + model->notifyObservers(); + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if( avatar ) + { + LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() ); + if( obj ) + { + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->addAsIndividual( obj, SELECT_ALL_TES, FALSE ); + LLSelectMgr::getInstance()->selectionSetObjectName( new_name ); + LLSelectMgr::getInstance()->deselectAll(); + } + } + } + // return FALSE because we either notified observers (& therefore + // rebuilt) or we didn't update. + return FALSE; +} + +// +=================================================+ +// | LLLSLTextBridge | +// +=================================================+ + +LLUIImagePtr LLLSLTextBridge::getIcon() const +{ + return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); +} + +void LLLSLTextBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + /* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); + } + */ +} + +// +=================================================+ +// | LLWearableBridge | +// +=================================================+ + +// *NOTE: hack to get from avatar inventory to avatar +void wear_inventory_item_on_avatar( LLInventoryItem* item ) +{ + if(item) + { + lldebugs << "wear_inventory_item_on_avatar( " << item->getName() + << " )" << llendl; + + LLAppearanceManager::instance().addCOFItemLink(item); + } +} + +void wear_add_inventory_item_on_avatar( LLInventoryItem* item ) +{ + if(item) + { + lldebugs << "wear_add_inventory_item_on_avatar( " << item->getName() + << " )" << llendl; + + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + LLWearableBridge::onWearAddOnAvatarArrived, + new LLUUID(item->getUUID())); + } +} + +void remove_inventory_category_from_avatar( LLInventoryCategory* category ) +{ + if(!category) return; + lldebugs << "remove_inventory_category_from_avatar( " << category->getName() + << " )" << llendl; + + + if( gFloaterCustomize ) + { + gFloaterCustomize->askToSaveIfDirty( + boost::bind(remove_inventory_category_from_avatar_step2, _1, category->getUUID())); + } + else + { + remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); + } +} + +struct OnRemoveStruct +{ + LLUUID mUUID; + OnRemoveStruct(const LLUUID& uuid): + mUUID(uuid) + { + } +}; + +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id) +{ + + // Find all the wearables that are in the category's subtree. + lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl; + if(proceed) + { + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(category_id, + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); + S32 i; + S32 wearable_count = item_array.count(); + + LLInventoryModel::cat_array_t obj_cat_array; + LLInventoryModel::item_array_t obj_item_array; + LLIsType is_object( LLAssetType::AT_OBJECT ); + gInventory.collectDescendentsIf(category_id, + obj_cat_array, + obj_item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_object); + S32 obj_count = obj_item_array.count(); + + // Find all gestures in this folder + LLInventoryModel::cat_array_t gest_cat_array; + LLInventoryModel::item_array_t gest_item_array; + LLIsType is_gesture( LLAssetType::AT_GESTURE ); + gInventory.collectDescendentsIf(category_id, + gest_cat_array, + gest_item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_gesture); + S32 gest_count = gest_item_array.count(); + + if (wearable_count > 0) //Loop through wearables. If worn, remove. + { + for(i = 0; i < wearable_count; ++i) + { + if( gAgentWearables.isWearingItem (item_array.get(i)->getUUID()) ) + { + LLWearableList::instance().getAsset(item_array.get(i)->getAssetUUID(), + item_array.get(i)->getName(), + item_array.get(i)->getType(), + LLWearableBridge::onRemoveFromAvatarArrived, + new OnRemoveStruct(item_array.get(i)->getUUID())); + + } + } + } + + + if (obj_count > 0) + { + for(i = 0; i < obj_count; ++i) + { + gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData ); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item_array.get(i)->getUUID() ); + + gMessageSystem->sendReliable( gAgent.getRegion()->getHost() ); + + // this object might have been selected, so let the selection manager know it's gone now + LLViewerObject *found_obj = gObjectList.findObject( obj_item_array.get(i)->getUUID()); + if (found_obj) + { + LLSelectMgr::getInstance()->remove(found_obj); + } + } + } + + if (gest_count > 0) + { + for(i = 0; i < gest_count; ++i) + { + if ( LLGestureManager::instance().isGestureActive( gest_item_array.get(i)->getUUID()) ) + { + LLGestureManager::instance().deactivateGesture( gest_item_array.get(i)->getUUID() ); + gInventory.updateItem( gest_item_array.get(i) ); + gInventory.notifyObservers(); + } + + } + } + } +} + +BOOL LLWearableBridge::renameItem(const std::string& new_name) +{ + if( gAgentWearables.isWearingItem( mUUID ) ) + { + gAgentWearables.setWearableName( mUUID, new_name ); + } + return LLItemBridge::renameItem(new_name); +} + +BOOL LLWearableBridge::isItemRemovable() +{ + if (gAgentWearables.isWearingItem(mUUID)) return FALSE; + return LLInvFVBridge::isItemRemovable(); +} + +std::string LLWearableBridge::getLabelSuffix() const +{ + if( gAgentWearables.isWearingItem( mUUID ) ) + { + // e.g. "(worn)" + return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); + } + else + { + return LLItemBridge::getLabelSuffix(); + } +} + +LLUIImagePtr LLWearableBridge::getIcon() const +{ + return get_item_icon(mAssetType, mInvType, mWearableType, FALSE); +} + +// virtual +void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("wear" == action) + { + wearOnAvatar(); + } + else if ("wear_add" == action) + { + wearAddOnAvatar(); + } + else if ("edit" == action) + { + editOnAvatar(); + return; + } + else if ("take_off" == action) + { + if(gAgentWearables.isWearingItem(mUUID)) + { + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + LLWearableBridge::onRemoveFromAvatarArrived, + new OnRemoveStruct(mUUID)); + } + } + } + else LLItemBridge::performAction(folder, model, action); +} + +void LLWearableBridge::openItem() +{ + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + /* + if( isInTrash() ) + { + LLNotifications::instance().add("CannotWearTrash"); + } + else if(isAgentInventory()) + { + if( !gAgentWearables.isWearingItem( mUUID ) ) + { + wearOnAvatar(); + } + } + else + { + // must be in the inventory library. copy it to our inventory + // and put it on right away. + LLViewerInventoryItem* item = getItem(); + if(item && item->isComplete()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else if(item) + { + // *TODO: We should fetch the item details, and then do + // the operation above. + LLNotifications::instance().add("CannotWearInfoNotComplete"); + } + } + */ +} + +void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere + BOOL no_open = ((flags & SUPPRESS_OPEN_ITEM) == SUPPRESS_OPEN_ITEM); + + // If we have clothing, don't add "Open" as it's the same action as "Wear" SL-18976 + LLViewerInventoryItem* item = getItem(); + if( !no_open && item ) + { + no_open = (item->getType() == LLAssetType::AT_CLOTHING) || + (item->getType() == LLAssetType::AT_BODYPART); + } + if (!no_open) + { + items.push_back(std::string("Open")); + } + + if (item && item->getIsLinkType()) + { + items.push_back(std::string("Find Original")); + } + + items.push_back(std::string("Properties")); + + getClipboardEntries(true, items, disabled_items, flags); + + items.push_back(std::string("Wearable Separator")); + + items.push_back(std::string("Wearable Wear")); + items.push_back(std::string("Wearable Add")); + items.push_back(std::string("Wearable Edit")); + + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + disabled_items.push_back(std::string("Wearable Edit")); + } + // Don't allow items to be worn if their baseobj is in the trash. + if (isLinkedObjectInTrash()) + { + disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable Add")); + disabled_items.push_back(std::string("Wearable Edit")); + } + + // Disable wear and take off based on whether the item is worn. + if(item) + { + switch (item->getType()) + { + case LLAssetType::AT_CLOTHING: + items.push_back(std::string("Take Off")); + case LLAssetType::AT_BODYPART: + if (gAgentWearables.isWearingItem(item->getUUID())) + { + disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable Add")); + } + else + { + disabled_items.push_back(std::string("Take Off")); + } + break; + default: + break; + } + } + } + hide_context_entries(menu, items, disabled_items); +} + +// Called from menus +// static +BOOL LLWearableBridge::canWearOnAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if(!self) return FALSE; + if(!self->isAgentInventory()) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); + if(!item || !item->isComplete()) return FALSE; + } + return (!gAgentWearables.isWearingItem(self->mUUID)); +} + +// Called from menus +// static +void LLWearableBridge::onWearOnAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if(!self) return; + self->wearOnAvatar(); +} + +void LLWearableBridge::wearOnAvatar() +{ + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + + LLViewerInventoryItem* item = getItem(); + if(item) + { + if(!isAgentInventory()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else + { + wear_inventory_item_on_avatar(item); + } + } +} + +void LLWearableBridge::wearAddOnAvatar() +{ + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + + LLViewerInventoryItem* item = getItem(); + if(item) + { + if(!isAgentInventory()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else + { + wear_add_inventory_item_on_avatar(item); + } + } +} + +// static +void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userdata ) +{ + LLUUID* item_id = (LLUUID*) userdata; + if(wearable) + { + LLViewerInventoryItem* item = NULL; + item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); + if(item) + { + if(item->getAssetUUID() == wearable->getAssetID()) + { + gAgentWearables.setWearableItem(item, wearable); + gInventory.notifyObservers(); + //self->getFolderItem()->refreshFromRoot(); + } + else + { + llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; + } + } + } + delete item_id; +} + +// static +// BAP remove the "add" code path once everything is fully COF-ified. +void LLWearableBridge::onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ) +{ + LLUUID* item_id = (LLUUID*) userdata; + if(wearable) + { + LLViewerInventoryItem* item = NULL; + item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); + if(item) + { + if(item->getAssetUUID() == wearable->getAssetID()) + { + bool do_append = true; + gAgentWearables.setWearableItem(item, wearable, do_append); + gInventory.notifyObservers(); + //self->getFolderItem()->refreshFromRoot(); + } + else + { + llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; + } + } + } + delete item_id; +} + +// static +BOOL LLWearableBridge::canEditOnAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if(!self) return FALSE; + + return (gAgentWearables.isWearingItem(self->mUUID)); +} + +// static +void LLWearableBridge::onEditOnAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if(self) + { + self->editOnAvatar(); + } +} + +void LLWearableBridge::editOnAvatar() +{ + const LLWearable* wearable = gAgentWearables.getWearableFromItemID(mUUID); + if( wearable ) + { + // Set the tab to the right wearable. + if (gFloaterCustomize) + gFloaterCustomize->setCurrentWearableType( wearable->getType() ); + + if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() ) + { + // Start Avatar Customization + gAgent.changeCameraToCustomizeAvatar(); + } + } +} + +// static +BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if( self && (LLAssetType::AT_BODYPART != self->mAssetType) ) + { + return gAgentWearables.isWearingItem( self->mUUID ); + } + return FALSE; +} + +// static +void LLWearableBridge::onRemoveFromAvatar(void* user_data) +{ + LLWearableBridge* self = (LLWearableBridge*)user_data; + if(!self) return; + if(gAgentWearables.isWearingItem(self->mUUID)) + { + LLViewerInventoryItem* item = self->getItem(); + if (item) + { + LLUUID parent_id = item->getParentUUID(); + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + onRemoveFromAvatarArrived, + new OnRemoveStruct(LLUUID(self->mUUID))); + } + } +} + +// static +void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, + void* userdata) +{ + OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata; + const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID); + if(wearable) + { + if( gAgentWearables.isWearingItem( item_id ) ) + { + EWearableType type = wearable->getType(); + + if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&& + //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) + { + // MULTI_WEARABLE: FIXME HACK - always remove all + bool do_remove_all = false; + gAgentWearables.removeWearable( type, do_remove_all, 0 ); + } + } + } + + // Find and remove this item from the COF. + LLInventoryModel::item_array_t items = gInventory.collectLinkedItems(item_id, LLAppearanceManager::instance().getCOF()); + llassert(items.size() == 1); // Should always have one and only one item linked to this in the COF. + for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); + iter != items.end(); + ++iter) + { + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + gInventory.purgeObject(item_id); + } + gInventory.notifyObservers(); + + delete on_remove_struct; +} + +LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, + const LLUUID& uuid,LLInventoryModel* model) +{ + LLInvFVBridgeAction* action = NULL; + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + action = new LLTextureBridgeAction(uuid,model); + break; + + case LLAssetType::AT_SOUND: + action = new LLSoundBridgeAction(uuid,model); + break; + + case LLAssetType::AT_LANDMARK: + action = new LLLandmarkBridgeAction(uuid,model); + break; + + case LLAssetType::AT_CALLINGCARD: + action = new LLCallingCardBridgeAction(uuid,model); + break; + + case LLAssetType::AT_OBJECT: + action = new LLObjectBridgeAction(uuid,model); + break; + + case LLAssetType::AT_NOTECARD: + action = new LLNotecardBridgeAction(uuid,model); + break; + + case LLAssetType::AT_ANIMATION: + action = new LLAnimationBridgeAction(uuid,model); + break; + + case LLAssetType::AT_GESTURE: + action = new LLGestureBridgeAction(uuid,model); + break; + + case LLAssetType::AT_LSL_TEXT: + action = new LLLSLTextBridgeAction(uuid,model); + break; + + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + action = new LLWearableBridgeAction(uuid,model); + + break; + + default: + break; + } + return action; +} + +//static +void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type, + const LLUUID& uuid,LLInventoryModel* model) +{ + LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); + if(action) + { + action->doIt(); + delete action; + } +} + +//static +void LLInvFVBridgeAction::doAction(const LLUUID& uuid, LLInventoryModel* model) +{ + LLAssetType::EType asset_type = model->getItem(uuid)->getType(); + LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); + if(action) + { + action->doIt(); + delete action; + } +} + +LLViewerInventoryItem* LLInvFVBridgeAction::getItem() const +{ + if(mModel) + return (LLViewerInventoryItem*)mModel->getItem(mUUID); + return NULL; +} + +//virtual +void LLTextureBridgeAction::doIt() +{ + if (getItem()) + { + LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLSoundBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + LLFloaterReg::showInstance("preview_sound", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLLandmarkBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if( item ) + { + // Opening (double-clicking) a landmark immediately teleports, + // but warns you the first time. + LLSD payload; + payload["asset_id"] = item->getAssetUUID(); + LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLCallingCardBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if(item && item->getCreatorUUID().notNull()) + { + LLAvatarActions::showProfile(item->getCreatorUUID()); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void +LLNotecardBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLGestureBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); + preview->setFocus(TRUE); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLAnimationBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLObjectBridgeAction::doIt() +{ + LLFloaterReg::showInstance("properties", mUUID); + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLLSLTextBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +BOOL LLWearableBridgeAction::isInTrash() const +{ + if(!mModel) return FALSE; + const LLUUID trash_id = mModel->findCategoryUUIDForType(LLFolderType::FT_TRASH); + return mModel->isObjectDescendentOf(mUUID, trash_id); +} + +BOOL LLWearableBridgeAction::isAgentInventory() const +{ + if(!mModel) return FALSE; + if(gInventory.getRootFolderID() == mUUID) return TRUE; + return mModel->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); +} + +void LLWearableBridgeAction::wearOnAvatar() +{ + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + + LLViewerInventoryItem* item = getItem(); + if(item) + { + if(!isAgentInventory()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else + { + wear_inventory_item_on_avatar(item); + } + } +} + +//virtual +void LLWearableBridgeAction::doIt() +{ + if(isInTrash()) + { + LLNotifications::instance().add("CannotWearTrash"); + } + else if(isAgentInventory()) + { + if(!gAgentWearables.isWearingItem(mUUID)) + { + wearOnAvatar(); + } + } + else + { + // must be in the inventory library. copy it to our inventory + // and put it on right away. + LLViewerInventoryItem* item = getItem(); + if(item && item->isComplete()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else if(item) + { + // *TODO: We should fetch the item details, and then do + // the operation above. + LLNotifications::instance().add("CannotWearInfoNotComplete"); + } + } + + LLInvFVBridgeAction::doIt(); +} + +// +=================================================+ +// | LLLinkItemBridge | +// +=================================================+ +// For broken links + +std::string LLLinkItemBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkItemBridge::getIcon() const +{ + if (LLViewerInventoryItem *item = getItem()) + { + return get_item_icon(item->getActualType(), LLInventoryType::IT_NONE, 0, FALSE); + } + return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); +} + +void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + } + hide_context_entries(menu, items, disabled_items); +} + + +// +=================================================+ +// | LLLinkBridge | +// +=================================================+ +// For broken links. + +std::string LLLinkFolderBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkFolderBridge::getIcon() const +{ + LLFolderType::EType preferred_type = LLFolderType::FT_NONE; + if (LLViewerInventoryItem *item = getItem()) + { + if (const LLViewerInventoryCategory* cat = item->getLinkedCategory()) + { + preferred_type = cat->getPreferredType(); + } + } + return LLFolderBridge::getIcon(preferred_type); +} + +void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Find Original")); + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + } + hide_context_entries(menu, items, disabled_items); +} + +void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("goto" == action) + { + gotoItem(folder); + return; + } + LLItemBridge::performAction(folder,model,action); +} + +void LLLinkFolderBridge::gotoItem(LLFolderView *folder) +{ + const LLUUID &cat_uuid = getFolderID(); + if (!cat_uuid.isNull()) + { + if (LLFolderViewItem *base_folder = folder->getItemByID(cat_uuid)) + { + if (LLInventoryModel* model = getInventoryModel()) + { + model->fetchDescendentsOf(cat_uuid); + } + base_folder->setOpen(TRUE); + folder->setSelectionFromRoot(base_folder,TRUE); + folder->scrollToShowSelection(); + } + } +} + +const LLUUID &LLLinkFolderBridge::getFolderID() const +{ + if (LLViewerInventoryItem *link_item = getItem()) + { + if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) + { + const LLUUID& cat_uuid = cat->getUUID(); + return cat_uuid; + } + } + return LLUUID::null; +} diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index efd40576a7..95cc68ddbe 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -1,136 +1,136 @@ -/** - * @file llinventoryfunctions.h - * @brief Miscellaneous inventory-related functions and classes - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLINVENTORYFUNCTIONS_H -#define LL_LLINVENTORYFUNCTIONS_H - -#include "llassetstorage.h" -#include "lldarray.h" -#include "llfloater.h" -#include "llinventory.h" -#include "llinventoryfilter.h" -#include "llfolderview.h" -#include "llinventorymodel.h" -#include "lluictrlfactory.h" -#include - - -class LLFolderViewItem; -class LLInventoryFilter; -class LLInventoryModel; -class LLInventoryPanel; -class LLInvFVBridge; -class LLInventoryFVBridgeBuilder; -class LLMenuBarGL; -class LLCheckBoxCtrl; -class LLSpinCtrl; -class LLScrollContainer; -class LLTextBox; -class LLIconCtrl; -class LLSaveFolderState; -class LLFilterEditor; -class LLTabContainer; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// This is a collection of miscellaneous functions and classes -// that don't fit cleanly into any other class header. -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLInventoryState -{ -public: - // HACK: Until we can route this info through the instant message hierarchy - static BOOL sWearNewClothing; - static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction -}; - -class LLSelectFirstFilteredItem : public LLFolderViewFunctor -{ -public: - LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} - virtual ~LLSelectFirstFilteredItem() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); - BOOL wasItemSelected() { return mItemSelected; } -protected: - BOOL mItemSelected; -}; - -class LLOpenFilteredFolders : public LLFolderViewFunctor -{ -public: - LLOpenFilteredFolders() {} - virtual ~LLOpenFilteredFolders() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - -class LLSaveFolderState : public LLFolderViewFunctor -{ -public: - LLSaveFolderState() : mApply(FALSE) {} - virtual ~LLSaveFolderState() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item) {} - void setApply(BOOL apply); - void clearOpenFolders() { mOpenFolders.clear(); } -protected: - std::set mOpenFolders; - BOOL mApply; -}; - -class LLOpenFoldersWithSelection : public LLFolderViewFunctor -{ -public: - LLOpenFoldersWithSelection() {} - virtual ~LLOpenFoldersWithSelection() {} - virtual void doFolder(LLFolderViewFolder* folder); - virtual void doItem(LLFolderViewItem* item); -}; - -const std::string& get_item_icon_name(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi ); - -LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, - LLInventoryType::EType inventory_type, - U32 attachment_point, - BOOL item_is_multi ); - -#endif // LL_LLINVENTORYFUNCTIONS_H - - - +/** + * @file llinventoryfunctions.h + * @brief Miscellaneous inventory-related functions and classes + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYFUNCTIONS_H +#define LL_LLINVENTORYFUNCTIONS_H + +#include "llassetstorage.h" +#include "lldarray.h" +#include "llfloater.h" +#include "llinventory.h" +#include "llinventoryfilter.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "lluictrlfactory.h" +#include + + +class LLFolderViewItem; +class LLInventoryFilter; +class LLInventoryModel; +class LLInventoryPanel; +class LLInvFVBridge; +class LLInventoryFVBridgeBuilder; +class LLMenuBarGL; +class LLCheckBoxCtrl; +class LLSpinCtrl; +class LLScrollContainer; +class LLTextBox; +class LLIconCtrl; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// This is a collection of miscellaneous functions and classes +// that don't fit cleanly into any other class header. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLInventoryState +{ +public: + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction +}; + +class LLSelectFirstFilteredItem : public LLFolderViewFunctor +{ +public: + LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} + virtual ~LLSelectFirstFilteredItem() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + BOOL wasItemSelected() { return mItemSelected; } +protected: + BOOL mItemSelected; +}; + +class LLOpenFilteredFolders : public LLFolderViewFunctor +{ +public: + LLOpenFilteredFolders() {} + virtual ~LLOpenFilteredFolders() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +class LLSaveFolderState : public LLFolderViewFunctor +{ +public: + LLSaveFolderState() : mApply(FALSE) {} + virtual ~LLSaveFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + void setApply(BOOL apply); + void clearOpenFolders() { mOpenFolders.clear(); } +protected: + std::set mOpenFolders; + BOOL mApply; +}; + +class LLOpenFoldersWithSelection : public LLFolderViewFunctor +{ +public: + LLOpenFoldersWithSelection() {} + virtual ~LLOpenFoldersWithSelection() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +const std::string& get_item_icon_name(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +#endif // LL_LLINVENTORYFUNCTIONS_H + + + diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 99591dea57..327a735f78 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1,890 +1,890 @@ -/* - * @file llinventorypanel.cpp - * @brief Implementation of the inventory panel and associated stuff. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include // for std::pair<> - -#include "llinventorypanel.h" - -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llfloaterreg.h" -#include "llimview.h" -#include "llinventorybridge.h" -#include "llscrollcontainer.h" -#include "llviewerfoldertype.h" -#include "llimfloater.h" -#include "llvoavatarself.h" - -static LLDefaultChildRegistry::Register r("inventory_panel"); - -const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); -const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); -const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); -static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryPanelObserver -// -// Bridge to support knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryPanelObserver : public LLInventoryObserver -{ -public: - LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} - virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask); -protected: - LLInventoryPanel* mIP; -}; - -LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : - LLPanel(p), - mInventoryObserver(NULL), - mFolders(NULL), - mScroller(NULL), - mSortOrderSetting(p.sort_order_setting), - mInventory(p.inventory), - mAllowMultiSelect(p.allow_multi_select), - mHasInventoryConnection(false), - mStartFolderString(p.start_folder), - mBuildDefaultHierarchy(true), - mInvFVBridgeBuilder(NULL) -{ - mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; - - // contex menu callbacks - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); - mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); - - setBackgroundColor(LLUIColorTable::instance().getColor("InventoryBackgroundColor")); - setBackgroundVisible(TRUE); - setBackgroundOpaque(TRUE); -} - -BOOL LLInventoryPanel::postBuild() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); - - mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves - - // create root folder - { - LLRect folder_rect(0, - 0, - getRect().getWidth(), - 0); - LLFolderView::Params p; - p.name = getName(); - p.rect = folder_rect; - p.parent_panel = this; - p.tool_tip = p.name; - mFolders = LLUICtrlFactory::create(p); - mFolders->setAllowMultiSelect(mAllowMultiSelect); - } - - mCommitCallbackRegistrar.popScope(); - - mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); - - // scroller - { - LLRect scroller_view_rect = getRect(); - scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); - LLScrollContainer::Params p; - p.name("Inventory Scroller"); - p.rect(scroller_view_rect); - p.follows.flags(FOLLOWS_ALL); - p.reserve_scroll_corner(true); - p.tab_stop(true); - mScroller = LLUICtrlFactory::create(p); - } - addChild(mScroller); - mScroller->addChild(mFolders); - - mFolders->setScrollContainer(mScroller); - - // set up the callbacks from the inventory we're viewing, and then - // build everything. - mInventoryObserver = new LLInventoryPanelObserver(this); - mInventory->addObserver(mInventoryObserver); - - // build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback - if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection) - { - rebuildViews(); - mHasInventoryConnection = true; - defaultOpenInventory(); - } - - if (mSortOrderSetting != INHERIT_SORT_ORDER) - { - setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); - } - else - { - setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); - } - mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); - - return TRUE; -} - -LLInventoryPanel::~LLInventoryPanel() -{ - // should this be a global setting? - if (mFolders) - { - U32 sort_order = mFolders->getSortOrder(); - if (mSortOrderSetting != INHERIT_SORT_ORDER) - { - gSavedSettings.setU32(mSortOrderSetting, sort_order); - } - } - - // LLView destructor will take care of the sub-views. - mInventory->removeObserver(mInventoryObserver); - delete mInventoryObserver; - mScroller = NULL; -} - -LLMemType mt(LLMemType::MTYPE_INVENTORY_FROM_XML); // ! BUG ! Should this be removed? -void LLInventoryPanel::draw() -{ - // select the desired item (in case it wasn't loaded when the selection was requested) - mFolders->updateSelection(); - LLPanel::draw(); -} - -LLInventoryFilter* LLInventoryPanel::getFilter() -{ - if (mFolders) return mFolders->getFilter(); - return NULL; -} - -void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories) -{ - mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories); -} - -void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) -{ - mFolders->getFilter()->setFilterPermissions(filter_perm_mask); -} - -void LLInventoryPanel::setFilterSubString(const std::string& string) -{ - mFolders->getFilter()->setFilterSubString(string); -} - -void LLInventoryPanel::setSortOrder(U32 order) -{ - mFolders->getFilter()->setSortOrder(order); - if (mFolders->getFilter()->isModified()) - { - mFolders->setSortOrder(order); - // try to keep selection onscreen, even if it wasn't to start with - mFolders->scrollToShowSelection(); - } -} - -void LLInventoryPanel::setSinceLogoff(BOOL sl) -{ - mFolders->getFilter()->setDateRangeLastLogoff(sl); -} - -void LLInventoryPanel::setHoursAgo(U32 hours) -{ - mFolders->getFilter()->setHoursAgo(hours); -} - -void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) -{ - mFolders->getFilter()->setShowFolderState(show); -} - -LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() -{ - return mFolders->getFilter()->getShowFolderState(); -} - -static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); - -void LLInventoryPanel::modelChanged(U32 mask) -{ - LLFastTimer t2(FTM_REFRESH); - - bool handled = false; - - // inventory just initialized, do complete build - if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) - { - rebuildViews(); - mHasInventoryConnection = true; - defaultOpenInventory(); - return; - } - - if (mask & LLInventoryObserver::LABEL) - { - handled = true; - // label change - empty out the display name for each object - // in this change set. - const std::set& changed_items = gInventory.getChangedIDs(); - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); - LLFolderViewItem* view = NULL; - LLInvFVBridge* bridge = NULL; - for (;id_it != id_end; ++id_it) - { - view = mFolders->getItemByID(*id_it); - if(view) - { - // request refresh on this item (also flags for filtering) - bridge = (LLInvFVBridge*)view->getListener(); - if(bridge) - { // Clear the display name first, so it gets properly re-built during refresh() - bridge->clearDisplayName(); - } - view->refresh(); - } - } - } - - // We don't really care which of these masks the item is actually flagged with, since the masks - // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into - // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks - // panel). What's relevant is that the item and UI are probably out of sync and thus need to be - // resynchronized. - if (mask & (LLInventoryObserver::STRUCTURE | - LLInventoryObserver::ADD | - LLInventoryObserver::REMOVE)) - { - handled = true; - // Record which folders are open by uuid. - LLInventoryModel* model = getModel(); - if (model) - { - const std::set& changed_items = gInventory.getChangedIDs(); - - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); - for (;id_it != id_end; ++id_it) - { - // sync view with model - LLInventoryObject* model_item = model->getObject(*id_it); - LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); - - // Item exists in memory but a UI element hasn't been created for it. - if (model_item && !view_item) - { - // Add the UI element for this item. - buildNewViews(*id_it); - // Select any newly created object that has the auto rename at top of folder root set. - if(mFolders->getRoot()->needsAutoRename()) - { - setSelection(*id_it, FALSE); - } - } - - // This item already exists in both memory and UI. It was probably moved - // around in the panel's directory structure (i.e. reparented). - if (model_item && view_item) - { - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); - - // Item has been moved. - if (view_item->getParentFolder() != new_parent) - { - if (new_parent != NULL) - { - // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. - view_item->getParentFolder()->extractItem(view_item); - view_item->addToFolder(new_parent, mFolders); - } - else - { - // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that - // doesn't include trash). Just remove the item's UI. - view_item->destroyView(); - } - } - } - - // This item has been removed from memory, but its associated UI element still exists. - if (!model_item && view_item) - { - // Remove the item's UI. - view_item->destroyView(); - } - } - } - } - - if (!handled) - { - // it's a small change that only requires a refresh. - // *TODO: figure out a more efficient way to do the refresh - // since it is expensive on large inventories - mFolders->refresh(); - } -} - - -void LLInventoryPanel::rebuildViews() -{ - // Determine the root folder and rebuild the views starting - // at that folder. - const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString); - - if ("LIBRARY" == mStartFolderString) - { - mStartFolderID = gInventory.getLibraryRootFolderID(); - } - else - { - mStartFolderID = (preferred_type != LLFolderType::FT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null); - } - - rebuildViewsFor(mStartFolderID); -} - -void LLInventoryPanel::rebuildViewsFor(const LLUUID& id) -{ - LLFolderViewItem* old_view = NULL; - - // get old LLFolderViewItem - old_view = mFolders->getItemByID(id); - if (old_view && id.notNull()) - { - old_view->destroyView(); - } - - buildNewViews(id); -} - -void LLInventoryPanel::buildNewViews(const LLUUID& id) -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); - LLFolderViewItem* itemp = NULL; - LLInventoryObject* objectp = gInventory.getObject(id); - if (objectp) - { - const LLUUID &parent_id = objectp->getParentUUID(); - LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(parent_id); - if (id == mStartFolderID) - parent_folder = mFolders; - - if (!parent_folder) - { - // This item exists outside the inventory's hierarchy, so don't add it. - return; - } - - if (objectp->getType() <= LLAssetType::AT_NONE || - objectp->getType() >= LLAssetType::AT_COUNT) - { - llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " << - ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << llendl; - return; - } - - if (objectp->getType() == LLAssetType::AT_CATEGORY && - objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) - { - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), - objectp->getType(), - LLInventoryType::IT_CATEGORY, - this, - objectp->getUUID()); - - if (new_listener) - { - LLFolderViewFolder::Params p; - p.name = new_listener->getDisplayName(); - p.icon = new_listener->getIcon(); - p.root = mFolders; - p.listener = new_listener; - p.tool_tip = p.name; - LLFolderViewFolder* folderp = LLUICtrlFactory::create(p); - folderp->setItemSortOrder(mFolders->getSortOrder()); - itemp = folderp; - - // Hide the root folder, so we can show the contents of a folder - // flat but still have the parent folder present for listener-related - // operations. - if (id == mStartFolderID) - { - folderp->setDontShowInHierarchy(TRUE); - } - } - } - else - { - // Build new view for item - LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), - item->getActualType(), - item->getInventoryType(), - this, - item->getUUID(), - item->getFlags()); - - if (new_listener) - { - LLFolderViewItem::Params params; - params.name(new_listener->getDisplayName()); - params.icon(new_listener->getIcon()); - params.creation_date(new_listener->getCreationDate()); - params.root(mFolders); - params.listener(new_listener); - params.rect(LLRect (0, 0, 0, 0)); - params.tool_tip = params.name; - itemp = LLUICtrlFactory::create (params); - } - } - - if (itemp) - { - itemp->addToFolder(parent_folder, mFolders); - } - } - - // If this is a folder, add the children of the folder and recursively add any - // child folders. - if ((id == mStartFolderID) || - (objectp && objectp->getType() == LLAssetType::AT_CATEGORY)) - { - LLViewerInventoryCategory::cat_array_t* categories; - LLViewerInventoryItem::item_array_t* items; - - mInventory->lockDirectDescendentArrays(id, categories, items); - if(categories) - { - S32 count = categories->count(); - for(S32 i = 0; i < count; ++i) - { - LLInventoryCategory* cat = categories->get(i); - buildNewViews(cat->getUUID()); - } - } - if(items) - { - S32 count = items->count(); - for(S32 i = 0; i < count; ++i) - { - LLInventoryItem* item = items->get(i); - buildNewViews(item->getUUID()); - } - } - mInventory->unlockDirectDescendentArrays(id); - } -} - -// bit of a hack to make sure the inventory is open. -void LLInventoryPanel::defaultOpenInventory() -{ - const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString); - if (preferred_type != LLFolderType::FT_NONE) - { - const std::string& top_level_folder_name = LLViewerFolderType::lookupNewCategoryName(preferred_type); - mFolders->openFolder(top_level_folder_name); - } - else - { - // Get the first child (it should be "My Inventory") and - // open it up by name (just to make sure the first child is actually a folder). - LLView* first_child = mFolders->getFirstChild(); - const std::string& first_child_name = first_child->getName(); - mFolders->openFolder(first_child_name); - } -} - -struct LLConfirmPurgeData -{ - LLUUID mID; - LLInventoryModel* mModel; -}; - -class LLIsNotWorn : public LLInventoryCollectFunctor -{ -public: - LLIsNotWorn() {} - virtual ~LLIsNotWorn() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return !gAgentWearables.isWearingItem(item->getUUID()); - } -}; - -class LLOpenFolderByID : public LLFolderViewFunctor -{ -public: - LLOpenFolderByID(const LLUUID& id) : mID(id) {} - virtual ~LLOpenFolderByID() {} - virtual void doFolder(LLFolderViewFolder* folder) - { - if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); - } - virtual void doItem(LLFolderViewItem* item) {} -protected: - const LLUUID& mID; -}; - - -void LLInventoryPanel::openSelected() -{ - LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); - if(!folder_item) return; - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); - if(!bridge) return; - bridge->openItem(); -} - -BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) -{ - BOOL handled = LLView::handleHover(x, y, mask); - if(handled) - { - ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) - { - // replace arrow cursor with arrow and hourglass cursor - getWindow()->setCursor(UI_CURSOR_WORKING); - } - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - } - return TRUE; -} - -BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - if (handled) - { - mFolders->setDragAndDropThisFrame(); - } - - return handled; -} - -void LLInventoryPanel::onFocusLost() -{ - // inventory no longer handles cut/copy/paste/delete - if (LLEditMenuHandler::gEditMenuHandler == mFolders) - { - LLEditMenuHandler::gEditMenuHandler = NULL; - } - - LLPanel::onFocusLost(); -} - -void LLInventoryPanel::onFocusReceived() -{ - // inventory now handles cut/copy/paste/delete - LLEditMenuHandler::gEditMenuHandler = mFolders; - - LLPanel::onFocusReceived(); -} - - -void LLInventoryPanel::openAllFolders() -{ - mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); - mFolders->arrangeAll(); -} - -void LLInventoryPanel::openDefaultFolderForType(LLFolderType::EType type) -{ - LLUUID category_id = mInventory->findCategoryUUIDForType(type); - LLOpenFolderByID opener(category_id); - mFolders->applyFunctorRecursively(opener); -} - -void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) -{ - // Don't select objects in COF (e.g. to prevent refocus when items are worn). - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (obj && obj->getParentUUID() == LLAppearanceManager::instance().getCOF()) - { - return; - } - mFolders->setSelectionByID(obj_id, take_keyboard_focus); -} - -void LLInventoryPanel::clearSelection() -{ - mFolders->clearSelection(); -} - -void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) -{ - LLFolderView* fv = getRootFolder(); - if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename - { - fv->setNeedsAutoRename(FALSE); - if (items.size()) // new asset is visible and selected - { - fv->startRenamingSelectedItem(); - } - } - // Seraph - Put determineFolderType in here for ensemble typing? -} - -//---------------------------------------------------------------------------- - -void LLInventoryPanel::doToSelected(const LLSD& userdata) -{ - mFolders->doToSelected(&gInventory, userdata); -} - -void LLInventoryPanel::doCreate(const LLSD& userdata) -{ - menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); -} - -bool LLInventoryPanel::beginIMSession() -{ - std::set selected_items; - mFolders->getSelectionList(selected_items); - - std::string name; - static int session_num = 1; - - LLDynamicArray members; - EInstantMessage type = IM_SESSION_CONFERENCE_START; - - std::set::const_iterator iter; - for (iter = selected_items.begin(); iter != selected_items.end(); iter++) - { - - LLUUID item = *iter; - LLFolderViewItem* folder_item = mFolders->getItemByID(item); - - if(folder_item) - { - LLFolderViewEventListener* fve_listener = folder_item->getListener(); - if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) - { - - LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); - if(!bridge) return true; - LLViewerInventoryCategory* cat = bridge->getCategory(); - if(!cat) return true; - name = cat->getName(); - LLUniqueBuddyCollector is_buddy; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendentsIf(bridge->getUUID(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_buddy); - S32 count = item_array.count(); - if(count > 0) - { - LLFloaterReg::showInstance("communicate"); - // create the session - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLUUID id; - for(S32 i = 0; i < count; ++i) - { - id = item_array.get(i)->getCreatorUUID(); - if(at.isBuddyOnline(id)) - { - members.put(id); - } - } - } - } - else - { - LLFolderViewItem* folder_item = mFolders->getItemByID(item); - if(!folder_item) return true; - LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); - - if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) - { - LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); - - if (inv_item) - { - LLAvatarTracker& at = LLAvatarTracker::instance(); - LLUUID id = inv_item->getCreatorUUID(); - - if(at.isBuddyOnline(id)) - { - members.put(id); - } - } - } //if IT_CALLINGCARD - } //if !IT_CATEGORY - } - } //for selected_items - - // the session_id is randomly generated UUID which will be replaced later - // with a server side generated number - - if (name.empty()) - { - name = llformat("Session %d", session_num++); - } - - LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); - if (session_id != LLUUID::null) - { - LLIMFloater::show(session_id); - } - - return true; -} - -bool LLInventoryPanel::attachObject(const LLSD& userdata) -{ - std::set selected_items; - mFolders->getSelectionList(selected_items); - - std::string joint_name = userdata.asString(); - LLVOAvatar *avatarp = static_cast(gAgent.getAvatarObject()); - LLViewerJointAttachment* attachmentp = NULL; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getName() == joint_name) - { - attachmentp = attachment; - break; - } - } - if (attachmentp == NULL) - { - return true; - } - - for (std::set::const_iterator set_iter = selected_items.begin(); - set_iter != selected_items.end(); - ++set_iter) - { - const LLUUID &id = *set_iter; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); - if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) - { - rez_attachment(item, attachmentp); - } - else if(item && item->isComplete()) - { - // must be in library. copy it to our inventory and put it on. - LLPointer cb = new RezAttachmentCallback(attachmentp); - copy_inventory_item(gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - LLUUID::null, - std::string(), - cb); - } - } - gFocusMgr.setKeyboardFocus(NULL); - - return true; -} - - -//---------------------------------------------------------------------------- - -// static DEBUG ONLY: -void LLInventoryPanel::dumpSelectionInformation(void* user_data) -{ - LLInventoryPanel* iv = (LLInventoryPanel*)user_data; - iv->mFolders->dumpSelectionInformation(); -} - -BOOL LLInventoryPanel::getSinceLogoff() -{ - return mFolders->getFilter()->isSinceLogoff(); -} - -void example_param_block_usage() -{ - LLInventoryPanel::Params param_block; - param_block.name(std::string("inventory")); - - param_block.sort_order_setting(LLInventoryPanel::RECENTITEMS_SORT_ORDER); - param_block.allow_multi_select(true); - param_block.filter(LLInventoryPanel::Filter() - .sort_order(1) - .types(0xffff0000)); - param_block.inventory(&gInventory); - param_block.has_border(true); - - LLUICtrlFactory::create(param_block); - - param_block = LLInventoryPanel::Params(); - param_block.name(std::string("inventory")); - - //LLSD param_block_sd; - //param_block_sd["sort_order_setting"] = LLInventoryPanel::RECENTITEMS_SORT_ORDER; - //param_block_sd["allow_multi_select"] = true; - //param_block_sd["filter"]["sort_order"] = 1; - //param_block_sd["filter"]["types"] = (S32)0xffff0000; - //param_block_sd["has_border"] = true; - - //LLInitParam::LLSDParser(param_block_sd).parse(param_block); - - LLUICtrlFactory::create(param_block); -} - -// +=================================================+ -// | LLInventoryPanelObserver | -// +=================================================+ -void LLInventoryPanelObserver::changed(U32 mask) -{ - mIP->modelChanged(mask); -} +/* + * @file llinventorypanel.cpp + * @brief Implementation of the inventory panel and associated stuff. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include // for std::pair<> + +#include "llinventorypanel.h" + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llfloaterreg.h" +#include "llimview.h" +#include "llinventorybridge.h" +#include "llscrollcontainer.h" +#include "llviewerfoldertype.h" +#include "llimfloater.h" +#include "llvoavatarself.h" + +static LLDefaultChildRegistry::Register r("inventory_panel"); + +const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); +const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); +const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); +static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanelObserver +// +// Bridge to support knowing when the inventory has changed. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryPanelObserver : public LLInventoryObserver +{ +public: + LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} + virtual ~LLInventoryPanelObserver() {} + virtual void changed(U32 mask); +protected: + LLInventoryPanel* mIP; +}; + +LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : + LLPanel(p), + mInventoryObserver(NULL), + mFolders(NULL), + mScroller(NULL), + mSortOrderSetting(p.sort_order_setting), + mInventory(p.inventory), + mAllowMultiSelect(p.allow_multi_select), + mHasInventoryConnection(false), + mStartFolderString(p.start_folder), + mBuildDefaultHierarchy(true), + mInvFVBridgeBuilder(NULL) +{ + mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; + + // contex menu callbacks + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); + + setBackgroundColor(LLUIColorTable::instance().getColor("InventoryBackgroundColor")); + setBackgroundVisible(TRUE); + setBackgroundOpaque(TRUE); +} + +BOOL LLInventoryPanel::postBuild() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); + + mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves + + // create root folder + { + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + LLFolderView::Params p; + p.name = getName(); + p.rect = folder_rect; + p.parent_panel = this; + p.tool_tip = p.name; + mFolders = LLUICtrlFactory::create(p); + mFolders->setAllowMultiSelect(mAllowMultiSelect); + } + + mCommitCallbackRegistrar.popScope(); + + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // scroller + { + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params p; + p.name("Inventory Scroller"); + p.rect(scroller_view_rect); + p.follows.flags(FOLLOWS_ALL); + p.reserve_scroll_corner(true); + p.tab_stop(true); + mScroller = LLUICtrlFactory::create(p); + } + addChild(mScroller); + mScroller->addChild(mFolders); + + mFolders->setScrollContainer(mScroller); + + // set up the callbacks from the inventory we're viewing, and then + // build everything. + mInventoryObserver = new LLInventoryPanelObserver(this); + mInventory->addObserver(mInventoryObserver); + + // build view of inventory if we need default full hierarchy and inventory ready, otherwise wait for modelChanged() callback + if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mHasInventoryConnection) + { + rebuildViews(); + mHasInventoryConnection = true; + defaultOpenInventory(); + } + + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); + } + else + { + setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); + } + mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); + + return TRUE; +} + +LLInventoryPanel::~LLInventoryPanel() +{ + // should this be a global setting? + if (mFolders) + { + U32 sort_order = mFolders->getSortOrder(); + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + gSavedSettings.setU32(mSortOrderSetting, sort_order); + } + } + + // LLView destructor will take care of the sub-views. + mInventory->removeObserver(mInventoryObserver); + delete mInventoryObserver; + mScroller = NULL; +} + +LLMemType mt(LLMemType::MTYPE_INVENTORY_FROM_XML); // ! BUG ! Should this be removed? +void LLInventoryPanel::draw() +{ + // select the desired item (in case it wasn't loaded when the selection was requested) + mFolders->updateSelection(); + LLPanel::draw(); +} + +LLInventoryFilter* LLInventoryPanel::getFilter() +{ + if (mFolders) return mFolders->getFilter(); + return NULL; +} + +void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories) +{ + mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories); +} + +void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) +{ + mFolders->getFilter()->setFilterPermissions(filter_perm_mask); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + mFolders->getFilter()->setFilterSubString(string); +} + +void LLInventoryPanel::setSortOrder(U32 order) +{ + mFolders->getFilter()->setSortOrder(order); + if (mFolders->getFilter()->isModified()) + { + mFolders->setSortOrder(order); + // try to keep selection onscreen, even if it wasn't to start with + mFolders->scrollToShowSelection(); + } +} + +void LLInventoryPanel::setSinceLogoff(BOOL sl) +{ + mFolders->getFilter()->setDateRangeLastLogoff(sl); +} + +void LLInventoryPanel::setHoursAgo(U32 hours) +{ + mFolders->getFilter()->setHoursAgo(hours); +} + +void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) +{ + mFolders->getFilter()->setShowFolderState(show); +} + +LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() +{ + return mFolders->getFilter()->getShowFolderState(); +} + +static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); + +void LLInventoryPanel::modelChanged(U32 mask) +{ + LLFastTimer t2(FTM_REFRESH); + + bool handled = false; + + // inventory just initialized, do complete build + if ((mask & LLInventoryObserver::ADD) && gInventory.getChangedIDs().empty() && !mHasInventoryConnection) + { + rebuildViews(); + mHasInventoryConnection = true; + defaultOpenInventory(); + return; + } + + if (mask & LLInventoryObserver::LABEL) + { + handled = true; + // label change - empty out the display name for each object + // in this change set. + const std::set& changed_items = gInventory.getChangedIDs(); + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + LLFolderViewItem* view = NULL; + LLInvFVBridge* bridge = NULL; + for (;id_it != id_end; ++id_it) + { + view = mFolders->getItemByID(*id_it); + if(view) + { + // request refresh on this item (also flags for filtering) + bridge = (LLInvFVBridge*)view->getListener(); + if(bridge) + { // Clear the display name first, so it gets properly re-built during refresh() + bridge->clearDisplayName(); + } + view->refresh(); + } + } + } + + // We don't really care which of these masks the item is actually flagged with, since the masks + // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into + // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks + // panel). What's relevant is that the item and UI are probably out of sync and thus need to be + // resynchronized. + if (mask & (LLInventoryObserver::STRUCTURE | + LLInventoryObserver::ADD | + LLInventoryObserver::REMOVE)) + { + handled = true; + // Record which folders are open by uuid. + LLInventoryModel* model = getModel(); + if (model) + { + const std::set& changed_items = gInventory.getChangedIDs(); + + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + // sync view with model + LLInventoryObject* model_item = model->getObject(*id_it); + LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); + + // Item exists in memory but a UI element hasn't been created for it. + if (model_item && !view_item) + { + // Add the UI element for this item. + buildNewViews(*id_it); + // Select any newly created object that has the auto rename at top of folder root set. + if(mFolders->getRoot()->needsAutoRename()) + { + setSelection(*id_it, FALSE); + } + } + + // This item already exists in both memory and UI. It was probably moved + // around in the panel's directory structure (i.e. reparented). + if (model_item && view_item) + { + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); + + // Item has been moved. + if (view_item->getParentFolder() != new_parent) + { + if (new_parent != NULL) + { + // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. + view_item->getParentFolder()->extractItem(view_item); + view_item->addToFolder(new_parent, mFolders); + } + else + { + // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that + // doesn't include trash). Just remove the item's UI. + view_item->destroyView(); + } + } + } + + // This item has been removed from memory, but its associated UI element still exists. + if (!model_item && view_item) + { + // Remove the item's UI. + view_item->destroyView(); + } + } + } + } + + if (!handled) + { + // it's a small change that only requires a refresh. + // *TODO: figure out a more efficient way to do the refresh + // since it is expensive on large inventories + mFolders->refresh(); + } +} + + +void LLInventoryPanel::rebuildViews() +{ + // Determine the root folder and rebuild the views starting + // at that folder. + const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString); + + if ("LIBRARY" == mStartFolderString) + { + mStartFolderID = gInventory.getLibraryRootFolderID(); + } + else + { + mStartFolderID = (preferred_type != LLFolderType::FT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null); + } + + rebuildViewsFor(mStartFolderID); +} + +void LLInventoryPanel::rebuildViewsFor(const LLUUID& id) +{ + LLFolderViewItem* old_view = NULL; + + // get old LLFolderViewItem + old_view = mFolders->getItemByID(id); + if (old_view && id.notNull()) + { + old_view->destroyView(); + } + + buildNewViews(id); +} + +void LLInventoryPanel::buildNewViews(const LLUUID& id) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); + LLFolderViewItem* itemp = NULL; + LLInventoryObject* objectp = gInventory.getObject(id); + if (objectp) + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(parent_id); + if (id == mStartFolderID) + parent_folder = mFolders; + + if (!parent_folder) + { + // This item exists outside the inventory's hierarchy, so don't add it. + return; + } + + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { + llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " << + ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << llendl; + return; + } + + if (objectp->getType() == LLAssetType::AT_CATEGORY && + objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), + objectp->getType(), + LLInventoryType::IT_CATEGORY, + this, + objectp->getUUID()); + + if (new_listener) + { + LLFolderViewFolder::Params p; + p.name = new_listener->getDisplayName(); + p.icon = new_listener->getIcon(); + p.root = mFolders; + p.listener = new_listener; + p.tool_tip = p.name; + LLFolderViewFolder* folderp = LLUICtrlFactory::create(p); + folderp->setItemSortOrder(mFolders->getSortOrder()); + itemp = folderp; + + // Hide the root folder, so we can show the contents of a folder + // flat but still have the parent folder present for listener-related + // operations. + if (id == mStartFolderID) + { + folderp->setDontShowInHierarchy(TRUE); + } + } + } + else + { + // Build new view for item + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + item->getUUID(), + item->getFlags()); + + if (new_listener) + { + LLFolderViewItem::Params params; + params.name(new_listener->getDisplayName()); + params.icon(new_listener->getIcon()); + params.creation_date(new_listener->getCreationDate()); + params.root(mFolders); + params.listener(new_listener); + params.rect(LLRect (0, 0, 0, 0)); + params.tool_tip = params.name; + itemp = LLUICtrlFactory::create (params); + } + } + + if (itemp) + { + itemp->addToFolder(parent_folder, mFolders); + } + } + + // If this is a folder, add the children of the folder and recursively add any + // child folders. + if ((id == mStartFolderID) || + (objectp && objectp->getType() == LLAssetType::AT_CATEGORY)) + { + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + + mInventory->lockDirectDescendentArrays(id, categories, items); + if(categories) + { + S32 count = categories->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryCategory* cat = categories->get(i); + buildNewViews(cat->getUUID()); + } + } + if(items) + { + S32 count = items->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryItem* item = items->get(i); + buildNewViews(item->getUUID()); + } + } + mInventory->unlockDirectDescendentArrays(id); + } +} + +// bit of a hack to make sure the inventory is open. +void LLInventoryPanel::defaultOpenInventory() +{ + const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString); + if (preferred_type != LLFolderType::FT_NONE) + { + const std::string& top_level_folder_name = LLViewerFolderType::lookupNewCategoryName(preferred_type); + mFolders->openFolder(top_level_folder_name); + } + else + { + // Get the first child (it should be "My Inventory") and + // open it up by name (just to make sure the first child is actually a folder). + LLView* first_child = mFolders->getFirstChild(); + const std::string& first_child_name = first_child->getName(); + mFolders->openFolder(first_child_name); + } +} + +struct LLConfirmPurgeData +{ + LLUUID mID; + LLInventoryModel* mModel; +}; + +class LLIsNotWorn : public LLInventoryCollectFunctor +{ +public: + LLIsNotWorn() {} + virtual ~LLIsNotWorn() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return !gAgentWearables.isWearingItem(item->getUUID()); + } +}; + +class LLOpenFolderByID : public LLFolderViewFunctor +{ +public: + LLOpenFolderByID(const LLUUID& id) : mID(id) {} + virtual ~LLOpenFolderByID() {} + virtual void doFolder(LLFolderViewFolder* folder) + { + if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + virtual void doItem(LLFolderViewItem* item) {} +protected: + const LLUUID& mID; +}; + + +void LLInventoryPanel::openSelected() +{ + LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); + if(!folder_item) return; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); + if(!bridge) return; + bridge->openItem(); +} + +BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x, y, mask); + if(handled) + { + ECursorType cursor = getWindow()->getCursor(); + if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + { + // replace arrow cursor with arrow and hourglass cursor + getWindow()->setCursor(UI_CURSOR_WORKING); + } + } + else + { + getWindow()->setCursor(UI_CURSOR_ARROW); + } + return TRUE; +} + +BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + + BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + if (handled) + { + mFolders->setDragAndDropThisFrame(); + } + + return handled; +} + +void LLInventoryPanel::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLInventoryPanel::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolders; + + LLPanel::onFocusReceived(); +} + + +void LLInventoryPanel::openAllFolders() +{ + mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolders->arrangeAll(); +} + +void LLInventoryPanel::openDefaultFolderForType(LLFolderType::EType type) +{ + LLUUID category_id = mInventory->findCategoryUUIDForType(type); + LLOpenFolderByID opener(category_id); + mFolders->applyFunctorRecursively(opener); +} + +void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + // Don't select objects in COF (e.g. to prevent refocus when items are worn). + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == LLAppearanceManager::instance().getCOF()) + { + return; + } + mFolders->setSelectionByID(obj_id, take_keyboard_focus); +} + +void LLInventoryPanel::clearSelection() +{ + mFolders->clearSelection(); +} + +void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) +{ + LLFolderView* fv = getRootFolder(); + if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename + { + fv->setNeedsAutoRename(FALSE); + if (items.size()) // new asset is visible and selected + { + fv->startRenamingSelectedItem(); + } + } + // Seraph - Put determineFolderType in here for ensemble typing? +} + +//---------------------------------------------------------------------------- + +void LLInventoryPanel::doToSelected(const LLSD& userdata) +{ + mFolders->doToSelected(&gInventory, userdata); +} + +void LLInventoryPanel::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); +} + +bool LLInventoryPanel::beginIMSession() +{ + std::set selected_items; + mFolders->getSelectionList(selected_items); + + std::string name; + static int session_num = 1; + + LLDynamicArray members; + EInstantMessage type = IM_SESSION_CONFERENCE_START; + + std::set::const_iterator iter; + for (iter = selected_items.begin(); iter != selected_items.end(); iter++) + { + + LLUUID item = *iter; + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + + if(folder_item) + { + LLFolderViewEventListener* fve_listener = folder_item->getListener(); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); + if(!bridge) return true; + LLViewerInventoryCategory* cat = bridge->getCategory(); + if(!cat) return true; + name = cat->getName(); + LLUniqueBuddyCollector is_buddy; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendentsIf(bridge->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_buddy); + S32 count = item_array.count(); + if(count > 0) + { + LLFloaterReg::showInstance("communicate"); + // create the session + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id; + for(S32 i = 0; i < count; ++i) + { + id = item_array.get(i)->getCreatorUUID(); + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } + } + else + { + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + if(!folder_item) return true; + LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); + + if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); + + if (inv_item) + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id = inv_item->getCreatorUUID(); + + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } //if IT_CALLINGCARD + } //if !IT_CATEGORY + } + } //for selected_items + + // the session_id is randomly generated UUID which will be replaced later + // with a server side generated number + + if (name.empty()) + { + name = llformat("Session %d", session_num++); + } + + LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + + return true; +} + +bool LLInventoryPanel::attachObject(const LLSD& userdata) +{ + std::set selected_items; + mFolders->getSelectionList(selected_items); + + std::string joint_name = userdata.asString(); + LLVOAvatar *avatarp = static_cast(gAgent.getAvatarObject()); + LLViewerJointAttachment* attachmentp = NULL; + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getName() == joint_name) + { + attachmentp = attachment; + break; + } + } + if (attachmentp == NULL) + { + return true; + } + + for (std::set::const_iterator set_iter = selected_items.begin(); + set_iter != selected_items.end(); + ++set_iter) + { + const LLUUID &id = *set_iter; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); + if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + rez_attachment(item, attachmentp); + } + else if(item && item->isComplete()) + { + // must be in library. copy it to our inventory and put it on. + LLPointer cb = new RezAttachmentCallback(attachmentp); + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + } + gFocusMgr.setKeyboardFocus(NULL); + + return true; +} + + +//---------------------------------------------------------------------------- + +// static DEBUG ONLY: +void LLInventoryPanel::dumpSelectionInformation(void* user_data) +{ + LLInventoryPanel* iv = (LLInventoryPanel*)user_data; + iv->mFolders->dumpSelectionInformation(); +} + +BOOL LLInventoryPanel::getSinceLogoff() +{ + return mFolders->getFilter()->isSinceLogoff(); +} + +void example_param_block_usage() +{ + LLInventoryPanel::Params param_block; + param_block.name(std::string("inventory")); + + param_block.sort_order_setting(LLInventoryPanel::RECENTITEMS_SORT_ORDER); + param_block.allow_multi_select(true); + param_block.filter(LLInventoryPanel::Filter() + .sort_order(1) + .types(0xffff0000)); + param_block.inventory(&gInventory); + param_block.has_border(true); + + LLUICtrlFactory::create(param_block); + + param_block = LLInventoryPanel::Params(); + param_block.name(std::string("inventory")); + + //LLSD param_block_sd; + //param_block_sd["sort_order_setting"] = LLInventoryPanel::RECENTITEMS_SORT_ORDER; + //param_block_sd["allow_multi_select"] = true; + //param_block_sd["filter"]["sort_order"] = 1; + //param_block_sd["filter"]["types"] = (S32)0xffff0000; + //param_block_sd["has_border"] = true; + + //LLInitParam::LLSDParser(param_block_sd).parse(param_block); + + LLUICtrlFactory::create(param_block); +} + +// +=================================================+ +// | LLInventoryPanelObserver | +// +=================================================+ +void LLInventoryPanelObserver::changed(U32 mask) +{ + mIP->modelChanged(mask); +} diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 5e23662a0b..40319d949d 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -195,7 +195,7 @@ void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id) childSetEnabled("teleport_btn", FALSE); childSetEnabled("pay_btn", FALSE); - getChild("avatar_name")->setValue(im_session->mName); + getChild("avatar_name")->setValue(im_session->mName); } else { diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 9f723169e1..74c1420cf3 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -1,1022 +1,1022 @@ -/** - * @file llsidepanelmaininventory.cpp - * @brief Implementation of llsidepanelmaininventory. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llpanelmaininventory.h" - -#include "lldndbutton.h" -#include "llfilepicker.h" -#include "llfloaterinventory.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" -#include "llinventorypanel.h" -#include "llfiltereditor.h" -#include "llfloaterreg.h" -#include "llpreviewtexture.h" -#include "llscrollcontainer.h" -#include "llsdserialize.h" -#include "llspinctrl.h" -#include "lltooldraganddrop.h" -#include "llviewermenu.h" -#include "llviewertexturelist.h" - -static LLRegisterPanelClassWrapper t_inventory("panel_main_inventory"); - -void on_file_loaded_for_save(BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* aux_src, - S32 discard_level, - BOOL final, - void* userdata); - -///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder -///---------------------------------------------------------------------------- - -class LLFloaterInventoryFinder : public LLFloater -{ -public: - LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view); - virtual void draw(); - /*virtual*/ BOOL postBuild(); - void changeFilter(LLInventoryFilter* filter); - void updateElementsFromFilter(); - BOOL getCheckShowEmpty(); - BOOL getCheckSinceLogoff(); - - static void onTimeAgo(LLUICtrl*, void *); - static void onCheckSinceLogoff(LLUICtrl*, void *); - static void onCloseBtn(void* user_data); - static void selectAllTypes(void* user_data); - static void selectNoTypes(void* user_data); -private: - LLPanelMainInventory* mPanelMainInventory; - LLSpinCtrl* mSpinSinceDays; - LLSpinCtrl* mSpinSinceHours; - LLInventoryFilter* mFilter; -}; - -///---------------------------------------------------------------------------- -/// LLPanelMainInventory -///---------------------------------------------------------------------------- - -LLPanelMainInventory::LLPanelMainInventory() - : LLPanel(), - mActivePanel(NULL), - mSavedFolderState(NULL), - mFilterText(""), - mMenuGearDefault(NULL), - mMenuAdd(NULL) -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); - // Menu Callbacks (non contex menus) - mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2)); - mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this)); - mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); - mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); - mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2)); - mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this)); - mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this)); - mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this)); - mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); - - // Controls - // *TODO: Just use persistant settings for each of these - U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); - BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); - BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); - BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ); - - gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE); - gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE); - - mSavedFolderState = new LLSaveFolderState(); - mSavedFolderState->setApply(FALSE); -} - -BOOL LLPanelMainInventory::postBuild() -{ - gInventory.addObserver(this); - - mFilterTabs = getChild("inventory filter tabs"); - mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); - - //panel->getFilter()->markDefault(); - - // Set up the default inv. panel/filter settings. - mActivePanel = getChild("All Items"); - if (mActivePanel) - { - // "All Items" is the previous only view, so it gets the InventorySortOrder - mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); - mActivePanel->getFilter()->markDefault(); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); - } - LLInventoryPanel* recent_items_panel = getChild("Recent Items"); - if (recent_items_panel) - { - recent_items_panel->setSinceLogoff(TRUE); - recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); - recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - recent_items_panel->getFilter()->markDefault(); - recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); - } - - // Now load the stored settings from disk, if available. - std::ostringstream filterSaveName; - filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); - llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName << llendl; - llifstream file(filterSaveName.str()); - LLSD savedFilterState; - if (file.is_open()) - { - LLSDSerialize::fromXML(savedFilterState, file); - file.close(); - - // Load the persistent "Recent Items" settings. - // Note that the "All Items" settings do not persist. - if(recent_items_panel) - { - if(savedFilterState.has(recent_items_panel->getFilter()->getName())) - { - LLSD recent_items = savedFilterState.get( - recent_items_panel->getFilter()->getName()); - recent_items_panel->getFilter()->fromLLSD(recent_items); - } - } - - } - - mFilterEditor = getChild("inventory search editor"); - if (mFilterEditor) - { - mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2)); - } - - // *TODO:Get the cost info from the server - const std::string upload_cost("10"); - childSetLabelArg("Upload Image", "[COST]", upload_cost); - childSetLabelArg("Upload Sound", "[COST]", upload_cost); - childSetLabelArg("Upload Animation", "[COST]", upload_cost); - childSetLabelArg("Bulk Upload", "[COST]", upload_cost); - - initListCommandsHandlers(); - return TRUE; -} - -// Destroys the object -LLPanelMainInventory::~LLPanelMainInventory( void ) -{ - // Save the filters state. - LLSD filterRoot; - LLInventoryPanel* all_items_panel = getChild("All Items"); - if (all_items_panel) - { - LLInventoryFilter* filter = all_items_panel->getFilter(); - if (filter) - { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; - } - } - - LLInventoryPanel* recent_items_panel = getChild("Recent Items"); - if (recent_items_panel) - { - LLInventoryFilter* filter = recent_items_panel->getFilter(); - if (filter) - { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; - } - } - - std::ostringstream filterSaveName; - filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); - llofstream filtersFile(filterSaveName.str()); - if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) - { - llwarns << "Could not write to filters save file " << filterSaveName << llendl; - } - else - filtersFile.close(); - - gInventory.removeObserver(this); - delete mSavedFolderState; -} - -void LLPanelMainInventory::startSearch() -{ - // this forces focus to line editor portion of search editor - if (mFilterEditor) - { - mFilterEditor->focusFirstItem(TRUE); - } -} - -BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask) -{ - LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; - if (root_folder) - { - // first check for user accepting current search results - if (mFilterEditor - && mFilterEditor->hasFocus() - && (key == KEY_RETURN - || key == KEY_DOWN) - && mask == MASK_NONE) - { - // move focus to inventory proper - mActivePanel->setFocus(TRUE); - root_folder->scrollToShowSelection(); - return TRUE; - } - - if (mActivePanel->hasFocus() && key == KEY_UP) - { - startSearch(); - } - } - - return LLPanel::handleKeyHere(key, mask); - -} - -//---------------------------------------------------------------------------- -// menu callbacks - -void LLPanelMainInventory::doToSelected(const LLSD& userdata) -{ - getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); -} - -void LLPanelMainInventory::closeAllFolders() -{ - getPanel()->getRootFolder()->closeAllFolders(); -} - -void LLPanelMainInventory::newWindow() -{ - LLFloaterInventory::showAgentInventory(); -} - -void LLPanelMainInventory::doCreate(const LLSD& userdata) -{ - menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); -} - -void LLPanelMainInventory::resetFilters() -{ - LLFloaterInventoryFinder *finder = getFinder(); - getActivePanel()->getFilter()->resetDefault(); - if (finder) - { - finder->updateElementsFromFilter(); - } - - setFilterTextFromFilter(); -} - -void LLPanelMainInventory::setSortBy(const LLSD& userdata) -{ - std::string sort_field = userdata.asString(); - if (sort_field == "name") - { - U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); - - gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); - gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); - } - else if (sort_field == "date") - { - U32 order = getActivePanel()->getSortOrder(); - getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); - - gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); - gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); - } - else if (sort_field == "foldersalwaysbyname") - { - U32 order = getActivePanel()->getSortOrder(); - if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME ) - { - order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME; - - gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE ); - } - else - { - order |= LLInventoryFilter::SO_FOLDERS_BY_NAME; - - gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE ); - } - getActivePanel()->setSortOrder( order ); - } - else if (sort_field == "systemfolderstotop") - { - U32 order = getActivePanel()->getSortOrder(); - if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ) - { - order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; - - gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE ); - } - else - { - order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; - - gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); - } - getActivePanel()->setSortOrder( order ); - } -} - -// static -BOOL LLPanelMainInventory::filtersVisible(void* user_data) -{ - LLPanelMainInventory* self = (LLPanelMainInventory*)user_data; - if(!self) return FALSE; - - return self->getFinder() != NULL; -} - -void LLPanelMainInventory::onClearSearch() -{ - LLFloater *finder = getFinder(); - if (mActivePanel) - { - mActivePanel->setFilterSubString(LLStringUtil::null); - mActivePanel->setFilterTypes(0xffffffff); - } - - if (finder) - { - LLFloaterInventoryFinder::selectAllTypes(finder); - } - - // re-open folders that were initially open - if (mActivePanel) - { - mSavedFolderState->setApply(TRUE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - LLOpenFoldersWithSelection opener; - mActivePanel->getRootFolder()->applyFunctorRecursively(opener); - mActivePanel->getRootFolder()->scrollToShowSelection(); - } -} - -void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) -{ - if (search_string == "") - { - onClearSearch(); - } - if (!mActivePanel) - { - return; - } - - gInventory.startBackgroundFetch(); - - std::string uppercase_search_string = search_string; - LLStringUtil::toUpper(uppercase_search_string); - if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) - { - // current filter and new filter empty, do nothing - return; - } - - // save current folder open state if no filter currently applied - if (!mActivePanel->getRootFolder()->isFilterModified()) - { - mSavedFolderState->setApply(FALSE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } - - // set new filter string - mActivePanel->setFilterSubString(uppercase_search_string); -} - - - //static - BOOL LLPanelMainInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) - { - LLPanelMainInventory* active_view = NULL; - - LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); - for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) - { - LLPanelMainInventory* iv = dynamic_cast(*iter); - if (iv) - { - if (gFocusMgr.childHasKeyboardFocus(iv)) - { - active_view = iv; - break; - } - } - } - - if (!active_view) - { - return FALSE; - } - - std::string search_string(find_text); - - if (search_string.empty()) - { - return FALSE; - } - - if (active_view->getPanel() && - active_view->getPanel()->getRootFolder()->search(first_item, search_string, backward)) - { - return TRUE; - } - - return FALSE; - } - -void LLPanelMainInventory::onFilterSelected() -{ - // Find my index - mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); - - if (!mActivePanel) - { - return; - } - LLInventoryFilter* filter = mActivePanel->getFilter(); - LLFloaterInventoryFinder *finder = getFinder(); - if (finder) - { - finder->changeFilter(filter); - } - if (filter->isActive()) - { - // If our filter is active we may be the first thing requiring a fetch so we better start it here. - gInventory.startBackgroundFetch(); - } - setFilterTextFromFilter(); -} - -const std::string LLPanelMainInventory::getFilterSubString() -{ - return mActivePanel->getFilterSubString(); -} - -void LLPanelMainInventory::setFilterSubString(const std::string& string) -{ - mActivePanel->setFilterSubString(string); -} - -BOOL LLPanelMainInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - // Check to see if we are auto scrolling from the last frame - LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); - BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); - if(mFilterTabs) - { - if(needsToScroll) - { - mFilterTabs->startDragAndDropDelayTimer(); - } - } - - BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - - return handled; -} - -void LLPanelMainInventory::changed(U32 mask) -{ -} - - -void LLPanelMainInventory::setFilterTextFromFilter() -{ - mFilterText = mActivePanel->getFilter()->getFilterText(); -} - -void LLPanelMainInventory::toggleFindOptions() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); - LLFloater *floater = getFinder(); - if (!floater) - { - LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); - mFinderHandle = finder->getHandle(); - finder->openFloater(); - - LLFloater* parent_floater = gFloaterView->getParentFloater(this); - if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel - parent_floater->addDependentFloater(mFinderHandle); - // start background fetch of folders - gInventory.startBackgroundFetch(); - } - else - { - floater->closeFloater(); - } -} - -void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) -{ - getChild("All Items")->setSelectCallback(cb); - getChild("Recent Items")->setSelectCallback(cb); -} - -void LLPanelMainInventory::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) -{ - updateListCommands(); - panel->onSelectionChange(items, user_action); -} - -///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder -///---------------------------------------------------------------------------- - -LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() -{ - return (LLFloaterInventoryFinder*)mFinderHandle.get(); -} - - -LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view) : - LLFloater(LLSD()), - mPanelMainInventory(inventory_view), - mFilter(inventory_view->getPanel()->getFilter()) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml", NULL); - updateElementsFromFilter(); -} - - -void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - - bool since_logoff= self->childGetValue("check_since_logoff"); - - if (!since_logoff && - !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) - { - self->mSpinSinceHours->set(1.0f); - } -} -BOOL LLFloaterInventoryFinder::postBuild() -{ - const LLRect& viewrect = mPanelMainInventory->getRect(); - setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); - - childSetAction("All", selectAllTypes, this); - childSetAction("None", selectNoTypes, this); - - mSpinSinceHours = getChild("spin_hours_ago"); - childSetCommitCallback("spin_hours_ago", onTimeAgo, this); - - mSpinSinceDays = getChild("spin_days_ago"); - childSetCommitCallback("spin_days_ago", onTimeAgo, this); - - // mCheckSinceLogoff = getChild("check_since_logoff"); - childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); - - childSetAction("Close", onCloseBtn, this); - - updateElementsFromFilter(); - return TRUE; -} -void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) -{ - LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; - if (!self) return; - - bool since_logoff=true; - if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) - { - since_logoff = false; - } - self->childSetValue("check_since_logoff", since_logoff); -} - -void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) -{ - mFilter = filter; - updateElementsFromFilter(); -} - -void LLFloaterInventoryFinder::updateElementsFromFilter() -{ - if (!mFilter) - return; - - // Get data needed for filter display - U32 filter_types = mFilter->getFilterTypes(); - std::string filter_string = mFilter->getFilterSubString(); - LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); - U32 hours = mFilter->getHoursAgo(); - - // update the ui elements - setTitle(mFilter->getName()); - - childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); - - childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); - childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); - childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); - childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); - childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); - childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); - childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); - childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); - childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); - childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); - childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); - childSetValue("check_since_logoff", mFilter->isSinceLogoff()); - mSpinSinceHours->set((F32)(hours % 24)); - mSpinSinceDays->set((F32)(hours / 24)); -} - -void LLFloaterInventoryFinder::draw() -{ - LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); - U32 filter = 0xffffffff; - BOOL filtered_by_all_types = TRUE; - - if (!childGetValue("check_animation")) - { - filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); - filtered_by_all_types = FALSE; - } - - - if (!childGetValue("check_calling_card")) - { - filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_clothing")) - { - filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_gesture")) - { - filter &= ~(0x1 << LLInventoryType::IT_GESTURE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_landmark")) - - - { - filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_notecard")) - { - filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_object")) - { - filter &= ~(0x1 << LLInventoryType::IT_OBJECT); - filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_script")) - { - filter &= ~(0x1 << LLInventoryType::IT_LSL); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_sound")) - { - filter &= ~(0x1 << LLInventoryType::IT_SOUND); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_texture")) - { - filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); - filtered_by_all_types = FALSE; - } - - if (!childGetValue("check_snapshot")) - { - filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); - filtered_by_all_types = FALSE; - } - - if (!filtered_by_all_types) - { - // don't include folders in filter, unless I've selected everything - filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); - } - - // update the panel, panel will update the filter - mPanelMainInventory->getPanel()->setShowFolderState(getCheckShowEmpty() ? - LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mPanelMainInventory->getPanel()->setFilterTypes(filter); - if (getCheckSinceLogoff()) - { - mSpinSinceDays->set(0); - mSpinSinceHours->set(0); - } - U32 days = (U32)mSpinSinceDays->get(); - U32 hours = (U32)mSpinSinceHours->get(); - if (hours > 24) - { - days += hours / 24; - hours = (U32)hours % 24; - mSpinSinceDays->set((F32)days); - mSpinSinceHours->set((F32)hours); - } - hours += days * 24; - mPanelMainInventory->getPanel()->setHoursAgo(hours); - mPanelMainInventory->getPanel()->setSinceLogoff(getCheckSinceLogoff()); - mPanelMainInventory->setFilterTextFromFilter(); - - LLPanel::draw(); -} - -BOOL LLFloaterInventoryFinder::getCheckShowEmpty() -{ - return childGetValue("check_show_empty"); -} - -BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() -{ - return childGetValue("check_since_logoff"); -} - -void LLFloaterInventoryFinder::onCloseBtn(void* user_data) -{ - LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; - finderp->closeFloater(); -} - -// static -void LLFloaterInventoryFinder::selectAllTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->childSetValue("check_animation", TRUE); - self->childSetValue("check_calling_card", TRUE); - self->childSetValue("check_clothing", TRUE); - self->childSetValue("check_gesture", TRUE); - self->childSetValue("check_landmark", TRUE); - self->childSetValue("check_notecard", TRUE); - self->childSetValue("check_object", TRUE); - self->childSetValue("check_script", TRUE); - self->childSetValue("check_sound", TRUE); - self->childSetValue("check_texture", TRUE); - self->childSetValue("check_snapshot", TRUE); -} - -//static -void LLFloaterInventoryFinder::selectNoTypes(void* user_data) -{ - LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; - if(!self) return; - - self->childSetValue("check_animation", FALSE); - self->childSetValue("check_calling_card", FALSE); - self->childSetValue("check_clothing", FALSE); - self->childSetValue("check_gesture", FALSE); - self->childSetValue("check_landmark", FALSE); - self->childSetValue("check_notecard", FALSE); - self->childSetValue("check_object", FALSE); - self->childSetValue("check_script", FALSE); - self->childSetValue("check_sound", FALSE); - self->childSetValue("check_texture", FALSE); - self->childSetValue("check_snapshot", FALSE); -} - -////////////////////////////////////////////////////////////////////////////////// -// List Commands // - -void LLPanelMainInventory::initListCommandsHandlers() -{ - mListCommands = getChild("bottom_panel"); - - mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this)); - mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this)); - mListCommands->childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this)); - - LLDragAndDropButton* trash_btn = mListCommands->getChild("trash_btn"); - trash_btn->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this - , _4 // BOOL drop - , _5 // EDragAndDropType cargo_type - , _7 // EAcceptance* accept - )); - - mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2)); - mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2)); - mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - -} - -void LLPanelMainInventory::updateListCommands() -{ - bool trash_enabled = isActionEnabled("delete"); - - mListCommands->childSetEnabled("trash_btn", trash_enabled); -} - -void LLPanelMainInventory::onGearButtonClick() -{ - showActionMenu(mMenuGearDefault,"options_gear_btn"); -} - -void LLPanelMainInventory::onAddButtonClick() -{ - showActionMenu(mMenuAdd,"add_btn"); -} - -void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) -{ - if (menu) - { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLView* spawning_view = getChild (spawning_view_name); - S32 menu_x, menu_y; - //show menu in co-ordinates of panel - spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); - menu_y += menu->getRect().getHeight(); - LLMenuGL::showPopup(this, menu, menu_x, menu_y); - } -} - -void LLPanelMainInventory::onTrashButtonClick() -{ - onClipboardAction("delete"); -} - -void LLPanelMainInventory::onClipboardAction(const LLSD& userdata) -{ - std::string command_name = userdata.asString(); - getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name); -} - -void LLPanelMainInventory::onCustomAction(const LLSD& userdata) -{ - if (!isActionEnabled(userdata)) - return; - - const std::string command_name = userdata.asString(); - if (command_name == "new_window") - { - newWindow(); - } - if (command_name == "sort_by_name") - { - const LLSD arg = "name"; - setSortBy(arg); - } - if (command_name == "sort_by_recent") - { - const LLSD arg = "date"; - setSortBy(arg); - } - if (command_name == "show_filters") - { - toggleFindOptions(); - } - if (command_name == "reset_filters") - { - resetFilters(); - } - if (command_name == "close_folders") - { - closeAllFolders(); - } - if (command_name == "empty_trash") - { - const std::string notification = "ConfirmEmptyTrash"; - gInventory.emptyFolderType(notification, LLFolderType::FT_TRASH); - } - if (command_name == "empty_lostnfound") - { - const std::string notification = "ConfirmEmptyLostAndFound"; - gInventory.emptyFolderType(notification, LLFolderType::FT_LOST_AND_FOUND); - } - if (command_name == "save_texture") - { - LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem(); - if (!current_item) - { - return; - } - - const LLUUID& item_id = current_item->getListener()->getUUID(); - LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance("preview_texture", LLSD(item_id), TAKE_FOCUS_YES); - if (preview_texture) - { - preview_texture->openToSave(); - } - } -} - -BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) -{ - const std::string command_name = userdata.asString(); - if (command_name == "delete") - { - BOOL can_delete = FALSE; - LLFolderView *folder = getActivePanel()->getRootFolder(); - if (folder) - { - can_delete = TRUE; - std::set selection_set; - folder->getSelectionList(selection_set); - for (std::set::iterator iter = selection_set.begin(); - iter != selection_set.end(); - ++iter) - { - const LLUUID &item_id = (*iter); - LLFolderViewItem *item = folder->getItemByID(item_id); - can_delete &= item->getListener()->isItemRemovable(); - } - return can_delete; - } - return FALSE; - } - if (command_name == "save_texture") - { - LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem(); - if (current_item) - { - return (current_item->getListener()->getInventoryType() == LLInventoryType::IT_TEXTURE); - } - return FALSE; - } - return TRUE; -} - -bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept) -{ - *accept = ACCEPT_NO; - - const bool is_enabled = isActionEnabled("delete"); - if (is_enabled) *accept = ACCEPT_YES_MULTI; - - if (is_enabled && drop) - { - onClipboardAction("delete"); - } - return true; -} - -// List Commands // -//////////////////////////////////////////////////////////////////////////////// +/** + * @file llsidepanelmaininventory.cpp + * @brief Implementation of llsidepanelmaininventory. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llpanelmaininventory.h" + +#include "lldndbutton.h" +#include "llfilepicker.h" +#include "llfloaterinventory.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" +#include "llfiltereditor.h" +#include "llfloaterreg.h" +#include "llpreviewtexture.h" +#include "llscrollcontainer.h" +#include "llsdserialize.h" +#include "llspinctrl.h" +#include "lltooldraganddrop.h" +#include "llviewermenu.h" +#include "llviewertexturelist.h" + +static LLRegisterPanelClassWrapper t_inventory("panel_main_inventory"); + +void on_file_loaded_for_save(BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + +///---------------------------------------------------------------------------- +/// LLFloaterInventoryFinder +///---------------------------------------------------------------------------- + +class LLFloaterInventoryFinder : public LLFloater +{ +public: + LLFloaterInventoryFinder( LLPanelMainInventory* inventory_view); + virtual void draw(); + /*virtual*/ BOOL postBuild(); + void changeFilter(LLInventoryFilter* filter); + void updateElementsFromFilter(); + BOOL getCheckShowEmpty(); + BOOL getCheckSinceLogoff(); + + static void onTimeAgo(LLUICtrl*, void *); + static void onCheckSinceLogoff(LLUICtrl*, void *); + static void onCloseBtn(void* user_data); + static void selectAllTypes(void* user_data); + static void selectNoTypes(void* user_data); +private: + LLPanelMainInventory* mPanelMainInventory; + LLSpinCtrl* mSpinSinceDays; + LLSpinCtrl* mSpinSinceHours; + LLInventoryFilter* mFilter; +}; + +///---------------------------------------------------------------------------- +/// LLPanelMainInventory +///---------------------------------------------------------------------------- + +LLPanelMainInventory::LLPanelMainInventory() + : LLPanel(), + mActivePanel(NULL), + mSavedFolderState(NULL), + mFilterText(""), + mMenuGearDefault(NULL), + mMenuAdd(NULL) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); + // Menu Callbacks (non contex menus) + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelMainInventory::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLPanelMainInventory::closeAllFolders, this)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLPanelMainInventory::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLPanelMainInventory::newWindow, this)); + mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, this)); + mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLPanelMainInventory::resetFilters, this)); + mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLPanelMainInventory::setSortBy, this, _2)); + + // Controls + // *TODO: Just use persistant settings for each of these + U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); + BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); + BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); + BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ); + + gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE); + + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); +} + +BOOL LLPanelMainInventory::postBuild() +{ + gInventory.addObserver(this); + + mFilterTabs = getChild("inventory filter tabs"); + mFilterTabs->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected, this)); + + //panel->getFilter()->markDefault(); + + // Set up the default inv. panel/filter settings. + mActivePanel = getChild("All Items"); + if (mActivePanel) + { + // "All Items" is the previous only view, so it gets the InventorySortOrder + mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); + mActivePanel->getFilter()->markDefault(); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); + } + LLInventoryPanel* recent_items_panel = getChild("Recent Items"); + if (recent_items_panel) + { + recent_items_panel->setSinceLogoff(TRUE); + recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); + recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + recent_items_panel->getFilter()->markDefault(); + recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); + } + + // Now load the stored settings from disk, if available. + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llinfos << "LLPanelMainInventory::init: reading from " << filterSaveName << llendl; + llifstream file(filterSaveName.str()); + LLSD savedFilterState; + if (file.is_open()) + { + LLSDSerialize::fromXML(savedFilterState, file); + file.close(); + + // Load the persistent "Recent Items" settings. + // Note that the "All Items" settings do not persist. + if(recent_items_panel) + { + if(savedFilterState.has(recent_items_panel->getFilter()->getName())) + { + LLSD recent_items = savedFilterState.get( + recent_items_panel->getFilter()->getName()); + recent_items_panel->getFilter()->fromLLSD(recent_items); + } + } + + } + + mFilterEditor = getChild("inventory search editor"); + if (mFilterEditor) + { + mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2)); + } + + // *TODO:Get the cost info from the server + const std::string upload_cost("10"); + childSetLabelArg("Upload Image", "[COST]", upload_cost); + childSetLabelArg("Upload Sound", "[COST]", upload_cost); + childSetLabelArg("Upload Animation", "[COST]", upload_cost); + childSetLabelArg("Bulk Upload", "[COST]", upload_cost); + + initListCommandsHandlers(); + return TRUE; +} + +// Destroys the object +LLPanelMainInventory::~LLPanelMainInventory( void ) +{ + // Save the filters state. + LLSD filterRoot; + LLInventoryPanel* all_items_panel = getChild("All Items"); + if (all_items_panel) + { + LLInventoryFilter* filter = all_items_panel->getFilter(); + if (filter) + { + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + } + + LLInventoryPanel* recent_items_panel = getChild("Recent Items"); + if (recent_items_panel) + { + LLInventoryFilter* filter = recent_items_panel->getFilter(); + if (filter) + { + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + } + + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llofstream filtersFile(filterSaveName.str()); + if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) + { + llwarns << "Could not write to filters save file " << filterSaveName << llendl; + } + else + filtersFile.close(); + + gInventory.removeObserver(this); + delete mSavedFolderState; +} + +void LLPanelMainInventory::startSearch() +{ + // this forces focus to line editor portion of search editor + if (mFilterEditor) + { + mFilterEditor->focusFirstItem(TRUE); + } +} + +BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask) +{ + LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; + if (root_folder) + { + // first check for user accepting current search results + if (mFilterEditor + && mFilterEditor->hasFocus() + && (key == KEY_RETURN + || key == KEY_DOWN) + && mask == MASK_NONE) + { + // move focus to inventory proper + mActivePanel->setFocus(TRUE); + root_folder->scrollToShowSelection(); + return TRUE; + } + + if (mActivePanel->hasFocus() && key == KEY_UP) + { + startSearch(); + } + } + + return LLPanel::handleKeyHere(key, mask); + +} + +//---------------------------------------------------------------------------- +// menu callbacks + +void LLPanelMainInventory::doToSelected(const LLSD& userdata) +{ + getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); +} + +void LLPanelMainInventory::closeAllFolders() +{ + getPanel()->getRootFolder()->closeAllFolders(); +} + +void LLPanelMainInventory::newWindow() +{ + LLFloaterInventory::showAgentInventory(); +} + +void LLPanelMainInventory::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); +} + +void LLPanelMainInventory::resetFilters() +{ + LLFloaterInventoryFinder *finder = getFinder(); + getActivePanel()->getFilter()->resetDefault(); + if (finder) + { + finder->updateElementsFromFilter(); + } + + setFilterTextFromFilter(); +} + +void LLPanelMainInventory::setSortBy(const LLSD& userdata) +{ + std::string sort_field = userdata.asString(); + if (sort_field == "name") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); + gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); + } + else if (sort_field == "date") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); + gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); + } + else if (sort_field == "foldersalwaysbyname") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME ) + { + order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } + else if (sort_field == "systemfolderstotop") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ) + { + order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } +} + +// static +BOOL LLPanelMainInventory::filtersVisible(void* user_data) +{ + LLPanelMainInventory* self = (LLPanelMainInventory*)user_data; + if(!self) return FALSE; + + return self->getFinder() != NULL; +} + +void LLPanelMainInventory::onClearSearch() +{ + LLFloater *finder = getFinder(); + if (mActivePanel) + { + mActivePanel->setFilterSubString(LLStringUtil::null); + mActivePanel->setFilterTypes(0xffffffff); + } + + if (finder) + { + LLFloaterInventoryFinder::selectAllTypes(finder); + } + + // re-open folders that were initially open + if (mActivePanel) + { + mSavedFolderState->setApply(TRUE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + mActivePanel->getRootFolder()->applyFunctorRecursively(opener); + mActivePanel->getRootFolder()->scrollToShowSelection(); + } +} + +void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) +{ + if (search_string == "") + { + onClearSearch(); + } + if (!mActivePanel) + { + return; + } + + gInventory.startBackgroundFetch(); + + std::string uppercase_search_string = search_string; + LLStringUtil::toUpper(uppercase_search_string); + if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) + { + // current filter and new filter empty, do nothing + return; + } + + // save current folder open state if no filter currently applied + if (!mActivePanel->getRootFolder()->isFilterModified()) + { + mSavedFolderState->setApply(FALSE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + } + + // set new filter string + mActivePanel->setFilterSubString(uppercase_search_string); +} + + + //static + BOOL LLPanelMainInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) + { + LLPanelMainInventory* active_view = NULL; + + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLPanelMainInventory* iv = dynamic_cast(*iter); + if (iv) + { + if (gFocusMgr.childHasKeyboardFocus(iv)) + { + active_view = iv; + break; + } + } + } + + if (!active_view) + { + return FALSE; + } + + std::string search_string(find_text); + + if (search_string.empty()) + { + return FALSE; + } + + if (active_view->getPanel() && + active_view->getPanel()->getRootFolder()->search(first_item, search_string, backward)) + { + return TRUE; + } + + return FALSE; + } + +void LLPanelMainInventory::onFilterSelected() +{ + // Find my index + mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); + + if (!mActivePanel) + { + return; + } + LLInventoryFilter* filter = mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = getFinder(); + if (finder) + { + finder->changeFilter(filter); + } + if (filter->isActive()) + { + // If our filter is active we may be the first thing requiring a fetch so we better start it here. + gInventory.startBackgroundFetch(); + } + setFilterTextFromFilter(); +} + +const std::string LLPanelMainInventory::getFilterSubString() +{ + return mActivePanel->getFilterSubString(); +} + +void LLPanelMainInventory::setFilterSubString(const std::string& string) +{ + mActivePanel->setFilterSubString(string); +} + +BOOL LLPanelMainInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // Check to see if we are auto scrolling from the last frame + LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); + BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); + if(mFilterTabs) + { + if(needsToScroll) + { + mFilterTabs->startDragAndDropDelayTimer(); + } + } + + BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + return handled; +} + +void LLPanelMainInventory::changed(U32 mask) +{ +} + + +void LLPanelMainInventory::setFilterTextFromFilter() +{ + mFilterText = mActivePanel->getFilter()->getFilterText(); +} + +void LLPanelMainInventory::toggleFindOptions() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); + LLFloater *floater = getFinder(); + if (!floater) + { + LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); + mFinderHandle = finder->getHandle(); + finder->openFloater(); + + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) // Seraph: Fix this, shouldn't be null even for sidepanel + parent_floater->addDependentFloater(mFinderHandle); + // start background fetch of folders + gInventory.startBackgroundFetch(); + } + else + { + floater->closeFloater(); + } +} + +void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) +{ + getChild("All Items")->setSelectCallback(cb); + getChild("Recent Items")->setSelectCallback(cb); +} + +void LLPanelMainInventory::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) +{ + updateListCommands(); + panel->onSelectionChange(items, user_action); +} + +///---------------------------------------------------------------------------- +/// LLFloaterInventoryFinder +///---------------------------------------------------------------------------- + +LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() +{ + return (LLFloaterInventoryFinder*)mFinderHandle.get(); +} + + +LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLPanelMainInventory* inventory_view) : + LLFloater(LLSD()), + mPanelMainInventory(inventory_view), + mFilter(inventory_view->getPanel()->getFilter()) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml", NULL); + updateElementsFromFilter(); +} + + +void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff= self->childGetValue("check_since_logoff"); + + if (!since_logoff && + !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) + { + self->mSpinSinceHours->set(1.0f); + } +} +BOOL LLFloaterInventoryFinder::postBuild() +{ + const LLRect& viewrect = mPanelMainInventory->getRect(); + setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); + + childSetAction("All", selectAllTypes, this); + childSetAction("None", selectNoTypes, this); + + mSpinSinceHours = getChild("spin_hours_ago"); + childSetCommitCallback("spin_hours_ago", onTimeAgo, this); + + mSpinSinceDays = getChild("spin_days_ago"); + childSetCommitCallback("spin_days_ago", onTimeAgo, this); + + // mCheckSinceLogoff = getChild("check_since_logoff"); + childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); + + childSetAction("Close", onCloseBtn, this); + + updateElementsFromFilter(); + return TRUE; +} +void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff=true; + if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) + { + since_logoff = false; + } + self->childSetValue("check_since_logoff", since_logoff); +} + +void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) +{ + mFilter = filter; + updateElementsFromFilter(); +} + +void LLFloaterInventoryFinder::updateElementsFromFilter() +{ + if (!mFilter) + return; + + // Get data needed for filter display + U32 filter_types = mFilter->getFilterTypes(); + std::string filter_string = mFilter->getFilterSubString(); + LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); + U32 hours = mFilter->getHoursAgo(); + + // update the ui elements + setTitle(mFilter->getName()); + + childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); + + childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); + childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); + childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); + childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); + childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); + childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); + childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); + childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); + childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); + childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); + childSetValue("check_since_logoff", mFilter->isSinceLogoff()); + mSpinSinceHours->set((F32)(hours % 24)); + mSpinSinceDays->set((F32)(hours / 24)); +} + +void LLFloaterInventoryFinder::draw() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); + U32 filter = 0xffffffff; + BOOL filtered_by_all_types = TRUE; + + if (!childGetValue("check_animation")) + { + filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); + filtered_by_all_types = FALSE; + } + + + if (!childGetValue("check_calling_card")) + { + filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_clothing")) + { + filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_gesture")) + { + filter &= ~(0x1 << LLInventoryType::IT_GESTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_landmark")) + + + { + filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_notecard")) + { + filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_object")) + { + filter &= ~(0x1 << LLInventoryType::IT_OBJECT); + filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_script")) + { + filter &= ~(0x1 << LLInventoryType::IT_LSL); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_sound")) + { + filter &= ~(0x1 << LLInventoryType::IT_SOUND); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_texture")) + { + filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_snapshot")) + { + filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); + filtered_by_all_types = FALSE; + } + + if (!filtered_by_all_types) + { + // don't include folders in filter, unless I've selected everything + filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); + } + + // update the panel, panel will update the filter + mPanelMainInventory->getPanel()->setShowFolderState(getCheckShowEmpty() ? + LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mPanelMainInventory->getPanel()->setFilterTypes(filter); + if (getCheckSinceLogoff()) + { + mSpinSinceDays->set(0); + mSpinSinceHours->set(0); + } + U32 days = (U32)mSpinSinceDays->get(); + U32 hours = (U32)mSpinSinceHours->get(); + if (hours > 24) + { + days += hours / 24; + hours = (U32)hours % 24; + mSpinSinceDays->set((F32)days); + mSpinSinceHours->set((F32)hours); + } + hours += days * 24; + mPanelMainInventory->getPanel()->setHoursAgo(hours); + mPanelMainInventory->getPanel()->setSinceLogoff(getCheckSinceLogoff()); + mPanelMainInventory->setFilterTextFromFilter(); + + LLPanel::draw(); +} + +BOOL LLFloaterInventoryFinder::getCheckShowEmpty() +{ + return childGetValue("check_show_empty"); +} + +BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() +{ + return childGetValue("check_since_logoff"); +} + +void LLFloaterInventoryFinder::onCloseBtn(void* user_data) +{ + LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; + finderp->closeFloater(); +} + +// static +void LLFloaterInventoryFinder::selectAllTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + self->childSetValue("check_animation", TRUE); + self->childSetValue("check_calling_card", TRUE); + self->childSetValue("check_clothing", TRUE); + self->childSetValue("check_gesture", TRUE); + self->childSetValue("check_landmark", TRUE); + self->childSetValue("check_notecard", TRUE); + self->childSetValue("check_object", TRUE); + self->childSetValue("check_script", TRUE); + self->childSetValue("check_sound", TRUE); + self->childSetValue("check_texture", TRUE); + self->childSetValue("check_snapshot", TRUE); +} + +//static +void LLFloaterInventoryFinder::selectNoTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + self->childSetValue("check_animation", FALSE); + self->childSetValue("check_calling_card", FALSE); + self->childSetValue("check_clothing", FALSE); + self->childSetValue("check_gesture", FALSE); + self->childSetValue("check_landmark", FALSE); + self->childSetValue("check_notecard", FALSE); + self->childSetValue("check_object", FALSE); + self->childSetValue("check_script", FALSE); + self->childSetValue("check_sound", FALSE); + self->childSetValue("check_texture", FALSE); + self->childSetValue("check_snapshot", FALSE); +} + +////////////////////////////////////////////////////////////////////////////////// +// List Commands // + +void LLPanelMainInventory::initListCommandsHandlers() +{ + mListCommands = getChild("bottom_panel"); + + mListCommands->childSetAction("options_gear_btn", boost::bind(&LLPanelMainInventory::onGearButtonClick, this)); + mListCommands->childSetAction("trash_btn", boost::bind(&LLPanelMainInventory::onTrashButtonClick, this)); + mListCommands->childSetAction("add_btn", boost::bind(&LLPanelMainInventory::onAddButtonClick, this)); + + LLDragAndDropButton* trash_btn = mListCommands->getChild("trash_btn"); + trash_btn->setDragAndDropHandler(boost::bind(&LLPanelMainInventory::handleDragAndDropToTrash, this + , _4 // BOOL drop + , _5 // EDragAndDropType cargo_type + , _7 // EAcceptance* accept + )); + + mCommitCallbackRegistrar.add("Inventory.GearDefault.Custom.Action", boost::bind(&LLPanelMainInventory::onCustomAction, this, _2)); + mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2)); + mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + +} + +void LLPanelMainInventory::updateListCommands() +{ + bool trash_enabled = isActionEnabled("delete"); + + mListCommands->childSetEnabled("trash_btn", trash_enabled); +} + +void LLPanelMainInventory::onGearButtonClick() +{ + showActionMenu(mMenuGearDefault,"options_gear_btn"); +} + +void LLPanelMainInventory::onAddButtonClick() +{ + showActionMenu(mMenuAdd,"add_btn"); +} + +void LLPanelMainInventory::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) +{ + if (menu) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLView* spawning_view = getChild (spawning_view_name); + S32 menu_x, menu_y; + //show menu in co-ordinates of panel + spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); + menu_y += menu->getRect().getHeight(); + LLMenuGL::showPopup(this, menu, menu_x, menu_y); + } +} + +void LLPanelMainInventory::onTrashButtonClick() +{ + onClipboardAction("delete"); +} + +void LLPanelMainInventory::onClipboardAction(const LLSD& userdata) +{ + std::string command_name = userdata.asString(); + getActivePanel()->getRootFolder()->doToSelected(getActivePanel()->getModel(),command_name); +} + +void LLPanelMainInventory::onCustomAction(const LLSD& userdata) +{ + if (!isActionEnabled(userdata)) + return; + + const std::string command_name = userdata.asString(); + if (command_name == "new_window") + { + newWindow(); + } + if (command_name == "sort_by_name") + { + const LLSD arg = "name"; + setSortBy(arg); + } + if (command_name == "sort_by_recent") + { + const LLSD arg = "date"; + setSortBy(arg); + } + if (command_name == "show_filters") + { + toggleFindOptions(); + } + if (command_name == "reset_filters") + { + resetFilters(); + } + if (command_name == "close_folders") + { + closeAllFolders(); + } + if (command_name == "empty_trash") + { + const std::string notification = "ConfirmEmptyTrash"; + gInventory.emptyFolderType(notification, LLFolderType::FT_TRASH); + } + if (command_name == "empty_lostnfound") + { + const std::string notification = "ConfirmEmptyLostAndFound"; + gInventory.emptyFolderType(notification, LLFolderType::FT_LOST_AND_FOUND); + } + if (command_name == "save_texture") + { + LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem(); + if (!current_item) + { + return; + } + + const LLUUID& item_id = current_item->getListener()->getUUID(); + LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance("preview_texture", LLSD(item_id), TAKE_FOCUS_YES); + if (preview_texture) + { + preview_texture->openToSave(); + } + } +} + +BOOL LLPanelMainInventory::isActionEnabled(const LLSD& userdata) +{ + const std::string command_name = userdata.asString(); + if (command_name == "delete") + { + BOOL can_delete = FALSE; + LLFolderView *folder = getActivePanel()->getRootFolder(); + if (folder) + { + can_delete = TRUE; + std::set selection_set; + folder->getSelectionList(selection_set); + for (std::set::iterator iter = selection_set.begin(); + iter != selection_set.end(); + ++iter) + { + const LLUUID &item_id = (*iter); + LLFolderViewItem *item = folder->getItemByID(item_id); + can_delete &= item->getListener()->isItemRemovable(); + } + return can_delete; + } + return FALSE; + } + if (command_name == "save_texture") + { + LLFolderViewItem* current_item = getActivePanel()->getRootFolder()->getCurSelectedItem(); + if (current_item) + { + return (current_item->getListener()->getInventoryType() == LLInventoryType::IT_TEXTURE); + } + return FALSE; + } + return TRUE; +} + +bool LLPanelMainInventory::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept) +{ + *accept = ACCEPT_NO; + + const bool is_enabled = isActionEnabled("delete"); + if (is_enabled) *accept = ACCEPT_YES_MULTI; + + if (is_enabled && drop) + { + onClipboardAction("delete"); + } + return true; +} + +// List Commands // +//////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 627be21577..ae78d3bec8 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -1,149 +1,149 @@ -/** - * @file llpanelmaininventory.h - * @brief llpanelmaininventory.h - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLPANELMAININVENTORY_H -#define LL_LLPANELMAININVENTORY_H - -#include "llpanel.h" -#include "llinventoryobserver.h" - -#include "llfolderview.h" - -class LLFolderViewItem; -class LLInventoryPanel; -class LLSaveFolderState; -class LLFilterEditor; -class LLTabContainer; -class LLFloaterInventoryFinder; -class LLMenuGL; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLPanelMainInventory -// -// This is a panel used to view and control an agent's inventory, -// including all the fixin's (e.g. AllItems/RecentItems tabs, filter floaters). -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLPanelMainInventory : public LLPanel, LLInventoryObserver -{ -public: - friend class LLFloaterInventoryFinder; - - LLPanelMainInventory(); - ~LLPanelMainInventory(); - - BOOL postBuild(); - - virtual BOOL handleKeyHere(KEY key, MASK mask); - - // Inherited functionality - /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - /*virtual*/ void changed(U32 mask); - - LLInventoryPanel* getPanel() { return mActivePanel; } - LLInventoryPanel* getActivePanel() { return mActivePanel; } - const LLInventoryPanel* getActivePanel() const { return mActivePanel; } - - const std::string& getFilterText() const { return mFilterText; } - - void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); - -protected: - // - // Misc functions - // - void setFilterTextFromFilter(); - void startSearch(); - - void toggleFindOptions(); - void onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action); - - static BOOL filtersVisible(void* user_data); - void onClearSearch(); - static void onFoldersByName(void *user_data); - static BOOL checkFoldersByName(void *user_data); - void onFilterEdit(const std::string& search_string ); - static BOOL incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward); - void onFilterSelected(); - - const std::string getFilterSubString(); - void setFilterSubString(const std::string& string); - - // menu callbacks - void doToSelected(const LLSD& userdata); - void closeAllFolders(); - void newWindow(); - void doCreate(const LLSD& userdata); - void resetFilters(); - void setSortBy(const LLSD& userdata); - -private: - LLFloaterInventoryFinder* getFinder(); - - LLFilterEditor* mFilterEditor; - LLTabContainer* mFilterTabs; - LLHandle mFinderHandle; - LLInventoryPanel* mActivePanel; - LLSaveFolderState* mSavedFolderState; - std::string mFilterText; - - - ////////////////////////////////////////////////////////////////////////////////// - // List Commands // -protected: - void initListCommandsHandlers(); - void updateListCommands(); - void onGearButtonClick(); - void onAddButtonClick(); - void showActionMenu(LLMenuGL* menu, std::string spawning_view_name); - void onTrashButtonClick(); - void onClipboardAction(const LLSD& userdata); - BOOL isActionEnabled(const LLSD& command_name); - void onCustomAction(const LLSD& command_name); - bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); -private: - LLPanel* mListCommands; - LLMenuGL* mMenuGearDefault; - LLMenuGL* mMenuAdd; - // List Commands // - //////////////////////////////////////////////////////////////////////////////// -}; - -#endif // LL_LLPANELMAININVENTORY_H - - - +/** + * @file llpanelmaininventory.h + * @brief llpanelmaininventory.h + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELMAININVENTORY_H +#define LL_LLPANELMAININVENTORY_H + +#include "llpanel.h" +#include "llinventoryobserver.h" + +#include "llfolderview.h" + +class LLFolderViewItem; +class LLInventoryPanel; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; +class LLFloaterInventoryFinder; +class LLMenuGL; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelMainInventory +// +// This is a panel used to view and control an agent's inventory, +// including all the fixin's (e.g. AllItems/RecentItems tabs, filter floaters). +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLPanelMainInventory : public LLPanel, LLInventoryObserver +{ +public: + friend class LLFloaterInventoryFinder; + + LLPanelMainInventory(); + ~LLPanelMainInventory(); + + BOOL postBuild(); + + virtual BOOL handleKeyHere(KEY key, MASK mask); + + // Inherited functionality + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + /*virtual*/ void changed(U32 mask); + + LLInventoryPanel* getPanel() { return mActivePanel; } + LLInventoryPanel* getActivePanel() { return mActivePanel; } + const LLInventoryPanel* getActivePanel() const { return mActivePanel; } + + const std::string& getFilterText() const { return mFilterText; } + + void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); + +protected: + // + // Misc functions + // + void setFilterTextFromFilter(); + void startSearch(); + + void toggleFindOptions(); + void onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action); + + static BOOL filtersVisible(void* user_data); + void onClearSearch(); + static void onFoldersByName(void *user_data); + static BOOL checkFoldersByName(void *user_data); + void onFilterEdit(const std::string& search_string ); + static BOOL incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward); + void onFilterSelected(); + + const std::string getFilterSubString(); + void setFilterSubString(const std::string& string); + + // menu callbacks + void doToSelected(const LLSD& userdata); + void closeAllFolders(); + void newWindow(); + void doCreate(const LLSD& userdata); + void resetFilters(); + void setSortBy(const LLSD& userdata); + +private: + LLFloaterInventoryFinder* getFinder(); + + LLFilterEditor* mFilterEditor; + LLTabContainer* mFilterTabs; + LLHandle mFinderHandle; + LLInventoryPanel* mActivePanel; + LLSaveFolderState* mSavedFolderState; + std::string mFilterText; + + + ////////////////////////////////////////////////////////////////////////////////// + // List Commands // +protected: + void initListCommandsHandlers(); + void updateListCommands(); + void onGearButtonClick(); + void onAddButtonClick(); + void showActionMenu(LLMenuGL* menu, std::string spawning_view_name); + void onTrashButtonClick(); + void onClipboardAction(const LLSD& userdata); + BOOL isActionEnabled(const LLSD& command_name); + void onCustomAction(const LLSD& command_name); + bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); +private: + LLPanel* mListCommands; + LLMenuGL* mMenuGearDefault; + LLMenuGL* mMenuAdd; + // List Commands // + //////////////////////////////////////////////////////////////////////////////// +}; + +#endif // LL_LLPANELMAININVENTORY_H + + + diff --git a/indra/newview/llpanelmediasettingssecurity.cpp b/indra/newview/llpanelmediasettingssecurity.cpp index bec2494eac..1a772e4eff 100644 --- a/indra/newview/llpanelmediasettingssecurity.cpp +++ b/indra/newview/llpanelmediasettingssecurity.cpp @@ -1,345 +1,345 @@ -/** - * @file llpanelmediasettingssecurity.cpp - * @brief LLPanelMediaSettingsSecurity class implementation - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llfloaterreg.h" -#include "llpanelmediasettingssecurity.h" -#include "llpanelcontents.h" -#include "llcheckboxctrl.h" -#include "llscrolllistctrl.h" -#include "llscrolllistitem.h" -#include "lluictrlfactory.h" -#include "llwindow.h" -#include "llviewerwindow.h" -#include "llsdutil.h" -#include "llselectmgr.h" -#include "llmediaentry.h" -#include "llfloaterwhitelistentry.h" -#include "llfloatermediasettings.h" -//////////////////////////////////////////////////////////////////////////////// -// -LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() : - mParent( NULL ) -{ - mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); - mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); - // build dialog from XML - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); - -} - -//////////////////////////////////////////////////////////////////////////////// -// -BOOL LLPanelMediaSettingsSecurity::postBuild() -{ - mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); - mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); - - setDefaultBtn("whitelist_add"); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// virtual -LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::draw() -{ - // housekeeping - LLPanel::draw(); - - // if list is empty, disable DEL button and checkbox to enable use of list - if ( mWhiteListList->isEmpty() ) - { - childSetEnabled( "whitelist_del", false ); - childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); - childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); - } - else - { - childSetEnabled( "whitelist_del", true ); - childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); - childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); - }; - - // if nothing is selected, disable DEL button - if ( mWhiteListList->getSelectedValue().asString().empty() ) - { - childSetEnabled( "whitelist_del", false ); - } - else - { - childSetEnabled( "whitelist_del", true ); - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) - { - if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - else - { - if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) - { - self->clearValues(self, editable); - // only show multiple - return; - } - - } - std::string base_key( "" ); - std::string tentative_key( "" ); - - struct - { - std::string key_name; - LLUICtrl* ctrl_ptr; - std::string ctrl_type; - - } data_set [] = - { - { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, - { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, - { "", NULL , "" } - }; - - for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) - { - base_key = std::string( data_set[ i ].key_name ); - tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); - - // TODO: CP - I bet there is a better way to do this using Boost - if ( media_settings[ base_key ].isDefined() ) - { - if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) - { - static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> - setValue( media_settings[ base_key ].asBoolean() ); - } - else - if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) - { - // get control - LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); - list->deleteAllItems(); - - // points to list of white list URLs - LLSD url_list = media_settings[ base_key ]; - - // iterate over them and add to scroll list - LLSD::array_iterator iter = url_list.beginArray(); - while( iter != url_list.endArray() ) - { - // TODO: is iter guaranteed to be valid here? - std::string url = *iter; - list->addSimpleElement( url ); - ++iter; - }; - }; - data_set[ i ].ctrl_ptr->setEnabled(editable); - data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); - }; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - self->mEnableWhiteList->clear(); - self->mWhiteListList->deleteAllItems(); - self->mEnableWhiteList->setEnabled(editable); - self->mWhiteListList->setEnabled(editable); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::preApply() -{ - // no-op -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) -{ - fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); - - // iterate over white list and extract items - std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); - std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); - // *NOTE: need actually set the key to be an emptyArray(), or the merge - // we do with this LLSD will think there's nothing to change. - fill_me_in[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); - while( iter != white_list_items.end() ) - { - std::string white_list_url = (*iter)->getValue().asString(); - fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); - ++iter; - }; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::postApply() -{ - // no-op -} - -/////////////////////////////////////////////////////////////////////////////// -// Try to make a valid URL if a fragment ( -// white list list box widget and build a list to test against. Can also -const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url ) -{ - // use LLURI to determine if we have a valid scheme - LLURI candidate_url( src_url ); - if ( candidate_url.scheme().empty() ) - { - // build a URL comprised of default scheme and the original fragment - const std::string default_scheme( "http://" ); - return default_scheme + src_url; - }; - - // we *could* test the "default scheme" + "original fragment" URL again - // using LLURI to see if it's valid but I think the outcome is the same - // in either case - our only option is to return the original URL - - // we *think* the original url passed in was valid - return src_url; -} - -/////////////////////////////////////////////////////////////////////////////// -// wrapper for testing a URL against the whitelist. We grab entries from -// white list list box widget and build a list to test against. Can also -// optionally pass the URL that you are trying to add to the widget since -// it won't be added until this call returns. -bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url, - const std::string& test_url ) -{ - // the checkUrlAgainstWhitelist(..) function works on a vector - // of strings for the white list entries - in this panel, the white list - // is stored in the widgets themselves so we need to build something compatible. - std::vector< std::string > whitelist_strings; - whitelist_strings.clear(); // may not be required - I forget what the spec says. - - // step through whitelist widget entries and grab them as strings - std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); - std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); - while( iter != white_list_items.end() ) - { - const std::string whitelist_url = (*iter)->getValue().asString(); - whitelist_strings.push_back( whitelist_url ); - - ++iter; - }; - - // add in the URL that might be added to the whitelist so we can test that too - if ( added_url.length() ) - whitelist_strings.push_back( added_url ); - - // possible the URL is just a fragment so we validize it - const std::string valid_url = makeValidUrl( test_url ); - - // indicate if the URL passes whitelist - return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings ); -} - -/////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) -{ - // grab home URL from the general panel (via the parent floater) - std::string home_url( "" ); - if ( mParent ) - home_url = mParent->getHomeUrl(); - - // if the home URL is blank (user hasn't entered it yet) then - // don't bother to check if it passes the white list - if ( home_url.empty() ) - { - mWhiteListList->addSimpleElement( url ); - return; - }; - - // if the URL passes the white list, add it - if ( passesWhiteList( url, home_url ) ) - { - mWhiteListList->addSimpleElement( url ); - } - else - // display a message indicating you can't do that - { - LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) -{ - LLFloaterReg::showInstance("whitelist_entry"); -} - -/////////////////////////////////////////////////////////////////////////////// -// static -void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) -{ - LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; - - self->mWhiteListList->deleteSelectedItems(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent ) -{ - mParent = parent; -}; - +/** + * @file llpanelmediasettingssecurity.cpp + * @brief LLPanelMediaSettingsSecurity class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" +#include "llpanelmediasettingssecurity.h" +#include "llpanelcontents.h" +#include "llcheckboxctrl.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llsdutil.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llfloaterwhitelistentry.h" +#include "llfloatermediasettings.h" +//////////////////////////////////////////////////////////////////////////////// +// +LLPanelMediaSettingsSecurity::LLPanelMediaSettingsSecurity() : + mParent( NULL ) +{ + mCommitCallbackRegistrar.add("Media.whitelistAdd", boost::bind(&LLPanelMediaSettingsSecurity::onBtnAdd, this)); + mCommitCallbackRegistrar.add("Media.whitelistDelete", boost::bind(&LLPanelMediaSettingsSecurity::onBtnDel, this)); + // build dialog from XML + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_media_settings_security.xml"); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLPanelMediaSettingsSecurity::postBuild() +{ + mEnableWhiteList = getChild< LLCheckBoxCtrl >( LLMediaEntry::WHITELIST_ENABLE_KEY ); + mWhiteListList = getChild< LLScrollListCtrl >( LLMediaEntry::WHITELIST_KEY ); + + setDefaultBtn("whitelist_add"); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +LLPanelMediaSettingsSecurity::~LLPanelMediaSettingsSecurity() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::draw() +{ + // housekeeping + LLPanel::draw(); + + // if list is empty, disable DEL button and checkbox to enable use of list + if ( mWhiteListList->isEmpty() ) + { + childSetEnabled( "whitelist_del", false ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, false ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + childSetEnabled( LLMediaEntry::WHITELIST_KEY, true ); + childSetEnabled( LLMediaEntry::WHITELIST_ENABLE_KEY, true ); + }; + + // if nothing is selected, disable DEL button + if ( mWhiteListList->getSelectedValue().asString().empty() ) + { + childSetEnabled( "whitelist_del", false ); + } + else + { + childSetEnabled( "whitelist_del", true ); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::initValues( void* userdata, const LLSD& media_settings , bool editable) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + if ( LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo ) + { + if(LLFloaterMediaSettings::getInstance()->mMultipleMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + else + { + if(LLFloaterMediaSettings::getInstance()->mMultipleValidMedia) + { + self->clearValues(self, editable); + // only show multiple + return; + } + + } + std::string base_key( "" ); + std::string tentative_key( "" ); + + struct + { + std::string key_name; + LLUICtrl* ctrl_ptr; + std::string ctrl_type; + + } data_set [] = + { + { LLMediaEntry::WHITELIST_ENABLE_KEY, self->mEnableWhiteList, "LLCheckBoxCtrl" }, + { LLMediaEntry::WHITELIST_KEY, self->mWhiteListList, "LLScrollListCtrl" }, + { "", NULL , "" } + }; + + for( int i = 0; data_set[ i ].key_name.length() > 0; ++i ) + { + base_key = std::string( data_set[ i ].key_name ); + tentative_key = base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ); + + // TODO: CP - I bet there is a better way to do this using Boost + if ( media_settings[ base_key ].isDefined() ) + { + if ( data_set[ i ].ctrl_type == "LLCheckBoxCtrl" ) + { + static_cast< LLCheckBoxCtrl* >( data_set[ i ].ctrl_ptr )-> + setValue( media_settings[ base_key ].asBoolean() ); + } + else + if ( data_set[ i ].ctrl_type == "LLScrollListCtrl" ) + { + // get control + LLScrollListCtrl* list = static_cast< LLScrollListCtrl* >( data_set[ i ].ctrl_ptr ); + list->deleteAllItems(); + + // points to list of white list URLs + LLSD url_list = media_settings[ base_key ]; + + // iterate over them and add to scroll list + LLSD::array_iterator iter = url_list.beginArray(); + while( iter != url_list.endArray() ) + { + // TODO: is iter guaranteed to be valid here? + std::string url = *iter; + list->addSimpleElement( url ); + ++iter; + }; + }; + data_set[ i ].ctrl_ptr->setEnabled(editable); + data_set[ i ].ctrl_ptr->setTentative( media_settings[ tentative_key ].asBoolean() ); + }; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::clearValues( void* userdata , bool editable) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + self->mEnableWhiteList->clear(); + self->mWhiteListList->deleteAllItems(); + self->mEnableWhiteList->setEnabled(editable); + self->mWhiteListList->setEnabled(editable); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::preApply() +{ + // no-op +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::getValues( LLSD &fill_me_in ) +{ + fill_me_in[LLMediaEntry::WHITELIST_ENABLE_KEY] = mEnableWhiteList->getValue(); + + // iterate over white list and extract items + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + // *NOTE: need actually set the key to be an emptyArray(), or the merge + // we do with this LLSD will think there's nothing to change. + fill_me_in[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); + while( iter != white_list_items.end() ) + { + std::string white_list_url = (*iter)->getValue().asString(); + fill_me_in[ LLMediaEntry::WHITELIST_KEY ].append( white_list_url ); + ++iter; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::postApply() +{ + // no-op +} + +/////////////////////////////////////////////////////////////////////////////// +// Try to make a valid URL if a fragment ( +// white list list box widget and build a list to test against. Can also +const std::string LLPanelMediaSettingsSecurity::makeValidUrl( const std::string& src_url ) +{ + // use LLURI to determine if we have a valid scheme + LLURI candidate_url( src_url ); + if ( candidate_url.scheme().empty() ) + { + // build a URL comprised of default scheme and the original fragment + const std::string default_scheme( "http://" ); + return default_scheme + src_url; + }; + + // we *could* test the "default scheme" + "original fragment" URL again + // using LLURI to see if it's valid but I think the outcome is the same + // in either case - our only option is to return the original URL + + // we *think* the original url passed in was valid + return src_url; +} + +/////////////////////////////////////////////////////////////////////////////// +// wrapper for testing a URL against the whitelist. We grab entries from +// white list list box widget and build a list to test against. Can also +// optionally pass the URL that you are trying to add to the widget since +// it won't be added until this call returns. +bool LLPanelMediaSettingsSecurity::passesWhiteList( const std::string& added_url, + const std::string& test_url ) +{ + // the checkUrlAgainstWhitelist(..) function works on a vector + // of strings for the white list entries - in this panel, the white list + // is stored in the widgets themselves so we need to build something compatible. + std::vector< std::string > whitelist_strings; + whitelist_strings.clear(); // may not be required - I forget what the spec says. + + // step through whitelist widget entries and grab them as strings + std::vector< LLScrollListItem* > white_list_items = mWhiteListList->getAllData(); + std::vector< LLScrollListItem* >::iterator iter = white_list_items.begin(); + while( iter != white_list_items.end() ) + { + const std::string whitelist_url = (*iter)->getValue().asString(); + whitelist_strings.push_back( whitelist_url ); + + ++iter; + }; + + // add in the URL that might be added to the whitelist so we can test that too + if ( added_url.length() ) + whitelist_strings.push_back( added_url ); + + // possible the URL is just a fragment so we validize it + const std::string valid_url = makeValidUrl( test_url ); + + // indicate if the URL passes whitelist + return LLMediaEntry::checkUrlAgainstWhitelist( valid_url, whitelist_strings ); +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::addWhiteListItem(const std::string& url) +{ + // grab home URL from the general panel (via the parent floater) + std::string home_url( "" ); + if ( mParent ) + home_url = mParent->getHomeUrl(); + + // if the home URL is blank (user hasn't entered it yet) then + // don't bother to check if it passes the white list + if ( home_url.empty() ) + { + mWhiteListList->addSimpleElement( url ); + return; + }; + + // if the URL passes the white list, add it + if ( passesWhiteList( url, home_url ) ) + { + mWhiteListList->addSimpleElement( url ); + } + else + // display a message indicating you can't do that + { + LLNotifications::instance().add("WhiteListInvalidatesHomeUrl"); + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnAdd( void* userdata ) +{ + LLFloaterReg::showInstance("whitelist_entry"); +} + +/////////////////////////////////////////////////////////////////////////////// +// static +void LLPanelMediaSettingsSecurity::onBtnDel( void* userdata ) +{ + LLPanelMediaSettingsSecurity *self =(LLPanelMediaSettingsSecurity *)userdata; + + self->mWhiteListList->deleteSelectedItems(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLPanelMediaSettingsSecurity::setParent( LLFloaterMediaSettings* parent ) +{ + mParent = parent; +}; + diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 7a39d8fabc..6722bb212e 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -1,102 +1,102 @@ -/** - * @file llpanelobjectinventory.h - * @brief LLPanelObjectInventory class definition - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLPANELOBJECTINVENTORY_H -#define LL_LLPANELOBJECTINVENTORY_H - -#include "llvoinventorylistener.h" -#include "llpanel.h" - -#include "llinventory.h" - -class LLScrollContainer; -class LLFolderView; -class LLFolderViewFolder; -class LLViewerObject; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLPanelObjectInventory -// -// This class represents the panel used to view and control a -// particular task's inventory. -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener -{ -public: - // dummy param block for template registration purposes - struct Params : public LLPanel::Params {}; - - LLPanelObjectInventory(const Params&); - virtual ~LLPanelObjectInventory(); - - virtual BOOL postBuild(); - - void doToSelected(const LLSD& userdata); - - void refresh(); - const LLUUID& getTaskUUID() { return mTaskUUID;} - void removeSelectedItem(); - void startRenamingSelectedItem(); - - LLFolderView* getRootFolder() const { return mFolders; } - - virtual void draw(); - virtual void deleteAllChildren(); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); - - static void idle(void* user_data); - -protected: - void reset(); - /*virtual*/ void inventoryChanged(LLViewerObject* object, - InventoryObjectList* inventory, - S32 serial_num, - void* user_data); - void updateInventory(); - void createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents); - void createViewsForCategory(InventoryObjectList* inventory, - LLInventoryObject* parent, - LLFolderViewFolder* folder); - void clearContents(); - -private: - LLScrollContainer* mScroller; - LLFolderView* mFolders; - - LLUUID mTaskUUID; - BOOL mHaveInventory; - BOOL mIsInventoryEmpty; - BOOL mInventoryNeedsUpdate; -}; - -#endif // LL_LLPANELOBJECTINVENTORY_H +/** + * @file llpanelobjectinventory.h + * @brief LLPanelObjectInventory class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELOBJECTINVENTORY_H +#define LL_LLPANELOBJECTINVENTORY_H + +#include "llvoinventorylistener.h" +#include "llpanel.h" + +#include "llinventory.h" + +class LLScrollContainer; +class LLFolderView; +class LLFolderViewFolder; +class LLViewerObject; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelObjectInventory +// +// This class represents the panel used to view and control a +// particular task's inventory. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener +{ +public: + // dummy param block for template registration purposes + struct Params : public LLPanel::Params {}; + + LLPanelObjectInventory(const Params&); + virtual ~LLPanelObjectInventory(); + + virtual BOOL postBuild(); + + void doToSelected(const LLSD& userdata); + + void refresh(); + const LLUUID& getTaskUUID() { return mTaskUUID;} + void removeSelectedItem(); + void startRenamingSelectedItem(); + + LLFolderView* getRootFolder() const { return mFolders; } + + virtual void draw(); + virtual void deleteAllChildren(); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, std::string& tooltip_msg); + + static void idle(void* user_data); + +protected: + void reset(); + /*virtual*/ void inventoryChanged(LLViewerObject* object, + InventoryObjectList* inventory, + S32 serial_num, + void* user_data); + void updateInventory(); + void createFolderViews(LLInventoryObject* inventory_root, InventoryObjectList& contents); + void createViewsForCategory(InventoryObjectList* inventory, + LLInventoryObject* parent, + LLFolderViewFolder* folder); + void clearContents(); + +private: + LLScrollContainer* mScroller; + LLFolderView* mFolders; + + LLUUID mTaskUUID; + BOOL mHaveInventory; + BOOL mIsInventoryEmpty; + BOOL mInventoryNeedsUpdate; +}; + +#endif // LL_LLPANELOBJECTINVENTORY_H diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 58962b67d6..824def3d92 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -1,279 +1,279 @@ -/** - * @file LLSidepanelInventory.cpp - * @brief Side Bar "Inventory" panel - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llsidepanelinventory.h" - -#include "llagent.h" -#include "llbutton.h" -#include "llinventorybridge.h" -#include "llinventorypanel.h" -#include "llpanelmaininventory.h" -#include "llsidepaneliteminfo.h" -#include "llsidepaneltaskinfo.h" -#include "lltabcontainer.h" -#include "llselectmgr.h" - -static LLRegisterPanelClassWrapper t_inventory("sidepanel_inventory"); - -LLSidepanelInventory::LLSidepanelInventory() - : LLPanel(), - mItemPanel(NULL), - mPanelMainInventory(NULL) -{ - - //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() -} - -LLSidepanelInventory::~LLSidepanelInventory() -{ -} - -BOOL LLSidepanelInventory::postBuild() -{ - // UI elements from inventory panel - { - mInventoryPanel = getChild("sidepanel__inventory_panel"); - - mInfoBtn = mInventoryPanel->getChild("info_btn"); - mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this)); - - mShareBtn = mInventoryPanel->getChild("share_btn"); - mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); - - mWearBtn = mInventoryPanel->getChild("wear_btn"); - mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this)); - - mPlayBtn = mInventoryPanel->getChild("play_btn"); - mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this)); - - mTeleportBtn = mInventoryPanel->getChild("teleport_btn"); - mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this)); - - mOverflowBtn = mInventoryPanel->getChild("overflow_btn"); - mOverflowBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onOverflowButtonClicked, this)); - - mPanelMainInventory = mInventoryPanel->getChild("panel_main_inventory"); - mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2)); - } - - // UI elements from item panel - { - mItemPanel = getChild("sidepanel__item_panel"); - - LLButton* back_btn = mItemPanel->getChild("back_btn"); - back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); - } - - // UI elements from task panel - { - mTaskPanel = getChild("sidepanel__task_panel"); - if (mTaskPanel) - { - LLButton* back_btn = mTaskPanel->getChild("back_btn"); - back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); - } - } - - return TRUE; -} - -void LLSidepanelInventory::onOpen(const LLSD& key) -{ - if(key.size() == 0) - return; - - mItemPanel->reset(); - - if (key.has("id")) - { - mItemPanel->setItemID(key["id"].asUUID()); - if (key.has("object")) - { - mItemPanel->setObjectID(key["object"].asUUID()); - } - showItemInfoPanel(); - } - if (key.has("task")) - { - if (mTaskPanel) - mTaskPanel->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - showTaskInfoPanel(); - } - if (key.has("select")) - { - mPanelMainInventory->getPanel()->setSelection(key["select"].asUUID(), TAKE_FOCUS_NO); - } -} - -void LLSidepanelInventory::onInfoButtonClicked() -{ - LLInventoryItem *item = getSelectedItem(); - if (item) - { - mItemPanel->reset(); - mItemPanel->setItemID(item->getUUID()); - showItemInfoPanel(); - } -} - -void LLSidepanelInventory::onShareButtonClicked() -{ -} - -void LLSidepanelInventory::performActionOnSelection(const std::string &action) -{ - LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild("panel_main_inventory"); - LLFolderViewItem* current_item = panel_main_inventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); - if (!current_item) - { - return; - } - current_item->getListener()->performAction(panel_main_inventory->getActivePanel()->getRootFolder(), panel_main_inventory->getActivePanel()->getModel(), action); -} - -void LLSidepanelInventory::onWearButtonClicked() -{ - performActionOnSelection("wear"); - performActionOnSelection("attach"); -} - -void LLSidepanelInventory::onPlayButtonClicked() -{ - performActionOnSelection("activate"); -} - -void LLSidepanelInventory::onTeleportButtonClicked() -{ - performActionOnSelection("teleport"); -} - -void LLSidepanelInventory::onOverflowButtonClicked() -{ -} - -void LLSidepanelInventory::onBackButtonClicked() -{ - showInventoryPanel(); -} - -void LLSidepanelInventory::onSelectionChange(const std::deque &items, BOOL user_action) -{ - updateVerbs(); -} - -void LLSidepanelInventory::showItemInfoPanel() -{ - mItemPanel->setVisible(TRUE); - if (mTaskPanel) - mTaskPanel->setVisible(FALSE); - mInventoryPanel->setVisible(FALSE); - - mItemPanel->dirty(); - mItemPanel->setIsEditing(FALSE); -} - -void LLSidepanelInventory::showTaskInfoPanel() -{ - mItemPanel->setVisible(FALSE); - mInventoryPanel->setVisible(FALSE); - - if (mTaskPanel) - { - mTaskPanel->setVisible(TRUE); - mTaskPanel->dirty(); - mTaskPanel->setIsEditing(FALSE); - } -} - -void LLSidepanelInventory::showInventoryPanel() -{ - mItemPanel->setVisible(FALSE); - if (mTaskPanel) - mTaskPanel->setVisible(FALSE); - mInventoryPanel->setVisible(TRUE); - updateVerbs(); -} - -void LLSidepanelInventory::updateVerbs() -{ - mInfoBtn->setEnabled(FALSE); - mShareBtn->setEnabled(FALSE); - - mWearBtn->setVisible(FALSE); - mWearBtn->setEnabled(FALSE); - mPlayBtn->setVisible(FALSE); - mPlayBtn->setEnabled(FALSE); - mTeleportBtn->setVisible(FALSE); - mTeleportBtn->setEnabled(FALSE); - - const LLInventoryItem *item = getSelectedItem(); - if (!item) - return; - - mInfoBtn->setEnabled(TRUE); - mShareBtn->setEnabled(TRUE); - - switch(item->getInventoryType()) - { - case LLInventoryType::IT_WEARABLE: - case LLInventoryType::IT_OBJECT: - case LLInventoryType::IT_ATTACHMENT: - mWearBtn->setVisible(TRUE); - mWearBtn->setEnabled(TRUE); - break; - case LLInventoryType::IT_SOUND: - case LLInventoryType::IT_GESTURE: - case LLInventoryType::IT_ANIMATION: - mPlayBtn->setVisible(TRUE); - mPlayBtn->setEnabled(TRUE); - break; - case LLInventoryType::IT_LANDMARK: - mTeleportBtn->setVisible(TRUE); - mTeleportBtn->setEnabled(TRUE); - break; - default: - break; - } -} - -LLInventoryItem *LLSidepanelInventory::getSelectedItem() -{ - LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild("panel_main_inventory"); - LLFolderViewItem* current_item = panel_main_inventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); - if (!current_item) - { - return NULL; - } - const LLUUID &item_id = current_item->getListener()->getUUID(); - LLInventoryItem *item = gInventory.getItem(item_id); - return item; -} +/** + * @file LLSidepanelInventory.cpp + * @brief Side Bar "Inventory" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsidepanelinventory.h" + +#include "llagent.h" +#include "llbutton.h" +#include "llinventorybridge.h" +#include "llinventorypanel.h" +#include "llpanelmaininventory.h" +#include "llsidepaneliteminfo.h" +#include "llsidepaneltaskinfo.h" +#include "lltabcontainer.h" +#include "llselectmgr.h" + +static LLRegisterPanelClassWrapper t_inventory("sidepanel_inventory"); + +LLSidepanelInventory::LLSidepanelInventory() + : LLPanel(), + mItemPanel(NULL), + mPanelMainInventory(NULL) +{ + + //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() +} + +LLSidepanelInventory::~LLSidepanelInventory() +{ +} + +BOOL LLSidepanelInventory::postBuild() +{ + // UI elements from inventory panel + { + mInventoryPanel = getChild("sidepanel__inventory_panel"); + + mInfoBtn = mInventoryPanel->getChild("info_btn"); + mInfoBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onInfoButtonClicked, this)); + + mShareBtn = mInventoryPanel->getChild("share_btn"); + mShareBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onShareButtonClicked, this)); + + mWearBtn = mInventoryPanel->getChild("wear_btn"); + mWearBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onWearButtonClicked, this)); + + mPlayBtn = mInventoryPanel->getChild("play_btn"); + mPlayBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onPlayButtonClicked, this)); + + mTeleportBtn = mInventoryPanel->getChild("teleport_btn"); + mTeleportBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onTeleportButtonClicked, this)); + + mOverflowBtn = mInventoryPanel->getChild("overflow_btn"); + mOverflowBtn->setClickedCallback(boost::bind(&LLSidepanelInventory::onOverflowButtonClicked, this)); + + mPanelMainInventory = mInventoryPanel->getChild("panel_main_inventory"); + mPanelMainInventory->setSelectCallback(boost::bind(&LLSidepanelInventory::onSelectionChange, this, _1, _2)); + } + + // UI elements from item panel + { + mItemPanel = getChild("sidepanel__item_panel"); + + LLButton* back_btn = mItemPanel->getChild("back_btn"); + back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); + } + + // UI elements from task panel + { + mTaskPanel = getChild("sidepanel__task_panel"); + if (mTaskPanel) + { + LLButton* back_btn = mTaskPanel->getChild("back_btn"); + back_btn->setClickedCallback(boost::bind(&LLSidepanelInventory::onBackButtonClicked, this)); + } + } + + return TRUE; +} + +void LLSidepanelInventory::onOpen(const LLSD& key) +{ + if(key.size() == 0) + return; + + mItemPanel->reset(); + + if (key.has("id")) + { + mItemPanel->setItemID(key["id"].asUUID()); + if (key.has("object")) + { + mItemPanel->setObjectID(key["object"].asUUID()); + } + showItemInfoPanel(); + } + if (key.has("task")) + { + if (mTaskPanel) + mTaskPanel->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + showTaskInfoPanel(); + } + if (key.has("select")) + { + mPanelMainInventory->getPanel()->setSelection(key["select"].asUUID(), TAKE_FOCUS_NO); + } +} + +void LLSidepanelInventory::onInfoButtonClicked() +{ + LLInventoryItem *item = getSelectedItem(); + if (item) + { + mItemPanel->reset(); + mItemPanel->setItemID(item->getUUID()); + showItemInfoPanel(); + } +} + +void LLSidepanelInventory::onShareButtonClicked() +{ +} + +void LLSidepanelInventory::performActionOnSelection(const std::string &action) +{ + LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild("panel_main_inventory"); + LLFolderViewItem* current_item = panel_main_inventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); + if (!current_item) + { + return; + } + current_item->getListener()->performAction(panel_main_inventory->getActivePanel()->getRootFolder(), panel_main_inventory->getActivePanel()->getModel(), action); +} + +void LLSidepanelInventory::onWearButtonClicked() +{ + performActionOnSelection("wear"); + performActionOnSelection("attach"); +} + +void LLSidepanelInventory::onPlayButtonClicked() +{ + performActionOnSelection("activate"); +} + +void LLSidepanelInventory::onTeleportButtonClicked() +{ + performActionOnSelection("teleport"); +} + +void LLSidepanelInventory::onOverflowButtonClicked() +{ +} + +void LLSidepanelInventory::onBackButtonClicked() +{ + showInventoryPanel(); +} + +void LLSidepanelInventory::onSelectionChange(const std::deque &items, BOOL user_action) +{ + updateVerbs(); +} + +void LLSidepanelInventory::showItemInfoPanel() +{ + mItemPanel->setVisible(TRUE); + if (mTaskPanel) + mTaskPanel->setVisible(FALSE); + mInventoryPanel->setVisible(FALSE); + + mItemPanel->dirty(); + mItemPanel->setIsEditing(FALSE); +} + +void LLSidepanelInventory::showTaskInfoPanel() +{ + mItemPanel->setVisible(FALSE); + mInventoryPanel->setVisible(FALSE); + + if (mTaskPanel) + { + mTaskPanel->setVisible(TRUE); + mTaskPanel->dirty(); + mTaskPanel->setIsEditing(FALSE); + } +} + +void LLSidepanelInventory::showInventoryPanel() +{ + mItemPanel->setVisible(FALSE); + if (mTaskPanel) + mTaskPanel->setVisible(FALSE); + mInventoryPanel->setVisible(TRUE); + updateVerbs(); +} + +void LLSidepanelInventory::updateVerbs() +{ + mInfoBtn->setEnabled(FALSE); + mShareBtn->setEnabled(FALSE); + + mWearBtn->setVisible(FALSE); + mWearBtn->setEnabled(FALSE); + mPlayBtn->setVisible(FALSE); + mPlayBtn->setEnabled(FALSE); + mTeleportBtn->setVisible(FALSE); + mTeleportBtn->setEnabled(FALSE); + + const LLInventoryItem *item = getSelectedItem(); + if (!item) + return; + + mInfoBtn->setEnabled(TRUE); + mShareBtn->setEnabled(TRUE); + + switch(item->getInventoryType()) + { + case LLInventoryType::IT_WEARABLE: + case LLInventoryType::IT_OBJECT: + case LLInventoryType::IT_ATTACHMENT: + mWearBtn->setVisible(TRUE); + mWearBtn->setEnabled(TRUE); + break; + case LLInventoryType::IT_SOUND: + case LLInventoryType::IT_GESTURE: + case LLInventoryType::IT_ANIMATION: + mPlayBtn->setVisible(TRUE); + mPlayBtn->setEnabled(TRUE); + break; + case LLInventoryType::IT_LANDMARK: + mTeleportBtn->setVisible(TRUE); + mTeleportBtn->setEnabled(TRUE); + break; + default: + break; + } +} + +LLInventoryItem *LLSidepanelInventory::getSelectedItem() +{ + LLPanelMainInventory *panel_main_inventory = mInventoryPanel->getChild("panel_main_inventory"); + LLFolderViewItem* current_item = panel_main_inventory->getActivePanel()->getRootFolder()->getCurSelectedItem(); + if (!current_item) + { + return NULL; + } + const LLUUID &item_id = current_item->getListener()->getUUID(); + LLInventoryItem *item = gInventory.getItem(item_id); + return item; +} diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h index 9eba77b5c3..6aa9cc745f 100644 --- a/indra/newview/llsidepanelinventory.h +++ b/indra/newview/llsidepanelinventory.h @@ -1,91 +1,91 @@ -/** - * @file LLSidepanelInventory.h - * @brief Side Bar "Inventory" panel - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSIDEPANELINVENTORY_H -#define LL_LLSIDEPANELINVENTORY_H - -#include "llpanel.h" - -class LLFolderViewItem; -class LLInventoryItem; -class LLPanelMainInventory; -class LLSidepanelItemInfo; -class LLSidepanelTaskInfo; - -class LLSidepanelInventory : public LLPanel -{ -public: - LLSidepanelInventory(); - virtual ~LLSidepanelInventory(); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void onOpen(const LLSD& key); - -protected: - // Tracks highlighted (selected) item in inventory panel. - LLInventoryItem *getSelectedItem(); - void onSelectionChange(const std::deque &items, BOOL user_action); - // "wear", "teleport", etc. - void performActionOnSelection(const std::string &action); - - void showItemInfoPanel(); - void showTaskInfoPanel(); - void showInventoryPanel(); - void updateVerbs(); - - // - // UI Elements - // -private: - LLPanel* mInventoryPanel; // Main inventory view - LLSidepanelItemInfo* mItemPanel; // Individual item view - LLSidepanelTaskInfo* mTaskPanel; // Individual in-world object view - LLPanelMainInventory* mPanelMainInventory; - -protected: - void onInfoButtonClicked(); - void onShareButtonClicked(); - void onWearButtonClicked(); - void onPlayButtonClicked(); - void onTeleportButtonClicked(); - void onOverflowButtonClicked(); - void onBackButtonClicked(); -private: - LLButton* mInfoBtn; - LLButton* mShareBtn; - LLButton* mWearBtn; - LLButton* mPlayBtn; - LLButton* mTeleportBtn; - LLButton* mOverflowBtn; - -}; - -#endif //LL_LLSIDEPANELINVENTORY_H +/** + * @file LLSidepanelInventory.h + * @brief Side Bar "Inventory" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSIDEPANELINVENTORY_H +#define LL_LLSIDEPANELINVENTORY_H + +#include "llpanel.h" + +class LLFolderViewItem; +class LLInventoryItem; +class LLPanelMainInventory; +class LLSidepanelItemInfo; +class LLSidepanelTaskInfo; + +class LLSidepanelInventory : public LLPanel +{ +public: + LLSidepanelInventory(); + virtual ~LLSidepanelInventory(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + +protected: + // Tracks highlighted (selected) item in inventory panel. + LLInventoryItem *getSelectedItem(); + void onSelectionChange(const std::deque &items, BOOL user_action); + // "wear", "teleport", etc. + void performActionOnSelection(const std::string &action); + + void showItemInfoPanel(); + void showTaskInfoPanel(); + void showInventoryPanel(); + void updateVerbs(); + + // + // UI Elements + // +private: + LLPanel* mInventoryPanel; // Main inventory view + LLSidepanelItemInfo* mItemPanel; // Individual item view + LLSidepanelTaskInfo* mTaskPanel; // Individual in-world object view + LLPanelMainInventory* mPanelMainInventory; + +protected: + void onInfoButtonClicked(); + void onShareButtonClicked(); + void onWearButtonClicked(); + void onPlayButtonClicked(); + void onTeleportButtonClicked(); + void onOverflowButtonClicked(); + void onBackButtonClicked(); +private: + LLButton* mInfoBtn; + LLButton* mShareBtn; + LLButton* mWearBtn; + LLButton* mPlayBtn; + LLButton* mTeleportBtn; + LLButton* mOverflowBtn; + +}; + +#endif //LL_LLSIDEPANELINVENTORY_H diff --git a/indra/newview/llsidepanelinventorysubpanel.cpp b/indra/newview/llsidepanelinventorysubpanel.cpp index 162198f1c5..23931defdd 100644 --- a/indra/newview/llsidepanelinventorysubpanel.cpp +++ b/indra/newview/llsidepanelinventorysubpanel.cpp @@ -1,155 +1,155 @@ -/** - * @file llsidepanelinventorysubpanel.cpp - * @brief A floater which shows an inventory item's properties. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llsidepanelinventorysubpanel.h" - -#include "roles_constants.h" - -#include "llagent.h" -#include "llavataractions.h" -#include "llbutton.h" -#include "llfloaterreg.h" -#include "llgroupactions.h" -#include "llinventorymodel.h" -#include "lllineeditor.h" -#include "llradiogroup.h" -#include "llviewercontrol.h" -#include "llviewerinventory.h" -#include "llviewerobjectlist.h" - - -///---------------------------------------------------------------------------- -/// Class LLSidepanelInventorySubpanel -///---------------------------------------------------------------------------- - -// Default constructor -LLSidepanelInventorySubpanel::LLSidepanelInventorySubpanel() - : LLPanel(), - mIsDirty(TRUE), - mIsEditing(FALSE), - mEditBtn(NULL), - mCancelBtn(NULL), - mSaveBtn(NULL) -{ -} - -// Destroys the object -LLSidepanelInventorySubpanel::~LLSidepanelInventorySubpanel() -{ -} - -// virtual -BOOL LLSidepanelInventorySubpanel::postBuild() -{ - mEditBtn = getChild("edit_btn"); - mEditBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onEditButtonClicked, this)); - - mSaveBtn = getChild("save_btn"); - mSaveBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onSaveButtonClicked, this)); - - mCancelBtn = getChild("cancel_btn"); - mCancelBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onCancelButtonClicked, this)); - return TRUE; -} - -void LLSidepanelInventorySubpanel::setVisible(BOOL visible) -{ - if (visible) - { - dirty(); - } - LLPanel::setVisible(visible); -} - -void LLSidepanelInventorySubpanel::setIsEditing(BOOL edit) -{ - mIsEditing = edit; - mIsDirty = TRUE; -} - -BOOL LLSidepanelInventorySubpanel::getIsEditing() const -{ - return mIsEditing; -} - -void LLSidepanelInventorySubpanel::reset() -{ - mIsDirty = TRUE; -} - -void LLSidepanelInventorySubpanel::draw() -{ - if (mIsDirty) - { - mIsDirty = FALSE; - refresh(); - updateVerbs(); - } - - LLPanel::draw(); -} - -void LLSidepanelInventorySubpanel::dirty() -{ - mIsDirty = TRUE; - setIsEditing(FALSE); -} - -void LLSidepanelInventorySubpanel::updateVerbs() -{ - mEditBtn->setVisible(!mIsEditing); - mSaveBtn->setVisible(mIsEditing); - mCancelBtn->setVisible(mIsEditing); -} - -void LLSidepanelInventorySubpanel::onEditButtonClicked() -{ - setIsEditing(TRUE); - refresh(); - updateVerbs(); -} - -void LLSidepanelInventorySubpanel::onSaveButtonClicked() -{ - save(); - setIsEditing(FALSE); - refresh(); - updateVerbs(); -} - -void LLSidepanelInventorySubpanel::onCancelButtonClicked() -{ - setIsEditing(FALSE); - refresh(); - updateVerbs(); -} +/** + * @file llsidepanelinventorysubpanel.cpp + * @brief A floater which shows an inventory item's properties. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsidepanelinventorysubpanel.h" + +#include "roles_constants.h" + +#include "llagent.h" +#include "llavataractions.h" +#include "llbutton.h" +#include "llfloaterreg.h" +#include "llgroupactions.h" +#include "llinventorymodel.h" +#include "lllineeditor.h" +#include "llradiogroup.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" +#include "llviewerobjectlist.h" + + +///---------------------------------------------------------------------------- +/// Class LLSidepanelInventorySubpanel +///---------------------------------------------------------------------------- + +// Default constructor +LLSidepanelInventorySubpanel::LLSidepanelInventorySubpanel() + : LLPanel(), + mIsDirty(TRUE), + mIsEditing(FALSE), + mEditBtn(NULL), + mCancelBtn(NULL), + mSaveBtn(NULL) +{ +} + +// Destroys the object +LLSidepanelInventorySubpanel::~LLSidepanelInventorySubpanel() +{ +} + +// virtual +BOOL LLSidepanelInventorySubpanel::postBuild() +{ + mEditBtn = getChild("edit_btn"); + mEditBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onEditButtonClicked, this)); + + mSaveBtn = getChild("save_btn"); + mSaveBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onSaveButtonClicked, this)); + + mCancelBtn = getChild("cancel_btn"); + mCancelBtn->setClickedCallback(boost::bind(&LLSidepanelInventorySubpanel::onCancelButtonClicked, this)); + return TRUE; +} + +void LLSidepanelInventorySubpanel::setVisible(BOOL visible) +{ + if (visible) + { + dirty(); + } + LLPanel::setVisible(visible); +} + +void LLSidepanelInventorySubpanel::setIsEditing(BOOL edit) +{ + mIsEditing = edit; + mIsDirty = TRUE; +} + +BOOL LLSidepanelInventorySubpanel::getIsEditing() const +{ + return mIsEditing; +} + +void LLSidepanelInventorySubpanel::reset() +{ + mIsDirty = TRUE; +} + +void LLSidepanelInventorySubpanel::draw() +{ + if (mIsDirty) + { + mIsDirty = FALSE; + refresh(); + updateVerbs(); + } + + LLPanel::draw(); +} + +void LLSidepanelInventorySubpanel::dirty() +{ + mIsDirty = TRUE; + setIsEditing(FALSE); +} + +void LLSidepanelInventorySubpanel::updateVerbs() +{ + mEditBtn->setVisible(!mIsEditing); + mSaveBtn->setVisible(mIsEditing); + mCancelBtn->setVisible(mIsEditing); +} + +void LLSidepanelInventorySubpanel::onEditButtonClicked() +{ + setIsEditing(TRUE); + refresh(); + updateVerbs(); +} + +void LLSidepanelInventorySubpanel::onSaveButtonClicked() +{ + save(); + setIsEditing(FALSE); + refresh(); + updateVerbs(); +} + +void LLSidepanelInventorySubpanel::onCancelButtonClicked() +{ + setIsEditing(FALSE); + refresh(); + updateVerbs(); +} diff --git a/indra/newview/llsidepanelinventorysubpanel.h b/indra/newview/llsidepanelinventorysubpanel.h index 6503887cd1..a74f4fdee6 100644 --- a/indra/newview/llsidepanelinventorysubpanel.h +++ b/indra/newview/llsidepanelinventorysubpanel.h @@ -1,82 +1,82 @@ -/** - * @file llsidepanelinventorysubpanel.h - * @brief A panel which shows an inventory item's properties. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSIDEPANELINVENTORYSUBPANEL_H -#define LL_LLSIDEPANELINVENTORYSUBPANEL_H - -#include "llpanel.h" - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLSidepanelInventorySubpanel -// Base class for inventory sidepanel panels (e.g. item info, task info). -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLButton; -class LLInventoryItem; - -class LLSidepanelInventorySubpanel : public LLPanel -{ -public: - LLSidepanelInventorySubpanel(); - virtual ~LLSidepanelInventorySubpanel(); - - /*virtual*/ void setVisible(BOOL visible); - virtual BOOL postBuild(); - virtual void draw(); - virtual void reset(); - - void dirty(); - void setIsEditing(BOOL edit); -protected: - virtual void refresh() = 0; - virtual void save() = 0; - virtual void updateVerbs(); - - BOOL getIsEditing() const; - - // - // UI Elements - // -protected: - void onEditButtonClicked(); - void onSaveButtonClicked(); - void onCancelButtonClicked(); - LLButton* mEditBtn; - LLButton* mSaveBtn; - LLButton* mCancelBtn; - -private: - BOOL mIsDirty; // item properties need to be updated - BOOL mIsEditing; // if we're in edit mode -}; - -#endif // LL_LLSIDEPANELINVENTORYSUBPANEL_H +/** + * @file llsidepanelinventorysubpanel.h + * @brief A panel which shows an inventory item's properties. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSIDEPANELINVENTORYSUBPANEL_H +#define LL_LLSIDEPANELINVENTORYSUBPANEL_H + +#include "llpanel.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLSidepanelInventorySubpanel +// Base class for inventory sidepanel panels (e.g. item info, task info). +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLButton; +class LLInventoryItem; + +class LLSidepanelInventorySubpanel : public LLPanel +{ +public: + LLSidepanelInventorySubpanel(); + virtual ~LLSidepanelInventorySubpanel(); + + /*virtual*/ void setVisible(BOOL visible); + virtual BOOL postBuild(); + virtual void draw(); + virtual void reset(); + + void dirty(); + void setIsEditing(BOOL edit); +protected: + virtual void refresh() = 0; + virtual void save() = 0; + virtual void updateVerbs(); + + BOOL getIsEditing() const; + + // + // UI Elements + // +protected: + void onEditButtonClicked(); + void onSaveButtonClicked(); + void onCancelButtonClicked(); + LLButton* mEditBtn; + LLButton* mSaveBtn; + LLButton* mCancelBtn; + +private: + BOOL mIsDirty; // item properties need to be updated + BOOL mIsEditing; // if we're in edit mode +}; + +#endif // LL_LLSIDEPANELINVENTORYSUBPANEL_H diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp index ff6e2d7363..5081c33f8e 100644 --- a/indra/newview/llsidepaneliteminfo.cpp +++ b/indra/newview/llsidepaneliteminfo.cpp @@ -1,883 +1,883 @@ -/** - * @file llsidepaneliteminfo.cpp - * @brief A floater which shows an inventory item's properties. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llsidepaneliteminfo.h" - -#include "roles_constants.h" - -#include "llagent.h" -#include "llavataractions.h" -#include "llbutton.h" -#include "llfloaterreg.h" -#include "llgroupactions.h" -#include "llinventorymodel.h" -#include "llinventoryobserver.h" -#include "lllineeditor.h" -#include "llradiogroup.h" -#include "llviewercontrol.h" -#include "llviewerinventory.h" -#include "llviewerobjectlist.h" - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLItemPropertiesObserver -// -// Helper class to watch for changes to the item. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLItemPropertiesObserver : public LLInventoryObserver -{ -public: - LLItemPropertiesObserver(LLSidepanelItemInfo* floater) - : mFloater(floater) - { - gInventory.addObserver(this); - } - virtual ~LLItemPropertiesObserver() - { - gInventory.removeObserver(this); - } - virtual void changed(U32 mask); -private: - LLSidepanelItemInfo* mFloater; -}; - -void LLItemPropertiesObserver::changed(U32 mask) -{ - // if there's a change we're interested in. - if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0) - { - mFloater->dirty(); - } -} - - - -///---------------------------------------------------------------------------- -/// Class LLSidepanelItemInfo -///---------------------------------------------------------------------------- - -static LLRegisterPanelClassWrapper t_item_info("sidepanel_item_info"); - -// Default constructor -LLSidepanelItemInfo::LLSidepanelItemInfo() - : mItemID(LLUUID::null) -{ - mPropertiesObserver = new LLItemPropertiesObserver(this); - - //LLUICtrlFactory::getInstance()->buildFloater(this,"floater_inventory_item_properties.xml"); -} - -// Destroys the object -LLSidepanelItemInfo::~LLSidepanelItemInfo() -{ - delete mPropertiesObserver; - mPropertiesObserver = NULL; -} - -// virtual -BOOL LLSidepanelItemInfo::postBuild() -{ - LLSidepanelInventorySubpanel::postBuild(); - - // build the UI - // item name & description - childSetPrevalidate("LabelItemName",&LLLineEditor::prevalidateASCIIPrintableNoPipe); - //getChild("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this)); - childSetPrevalidate("LabelItemDesc",&LLLineEditor::prevalidateASCIIPrintableNoPipe); - //getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this)); - - // Creator information - getChild("BtnCreator")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickCreator,this)); - - // owner information - getChild("BtnOwner")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickOwner,this)); - - refresh(); - return TRUE; -} - -void LLSidepanelItemInfo::setObjectID(const LLUUID& object_id) -{ - mObjectID = object_id; -} - -void LLSidepanelItemInfo::setItemID(const LLUUID& item_id) -{ - mItemID = item_id; -} - -void LLSidepanelItemInfo::reset() -{ - LLSidepanelInventorySubpanel::reset(); - - mObjectID = LLUUID::null; - mItemID = LLUUID::null; -} - -void LLSidepanelItemInfo::refresh() -{ - LLInventoryItem* item = findItem(); - if(item) - { - refreshFromItem(item); - updateVerbs(); - } - else - { - if (getIsEditing()) - { - setIsEditing(FALSE); - return; - } - } - - if (!getIsEditing()) - { - const std::string no_item_names[]={ - "LabelItemName", - "LabelItemDesc", - "LabelCreatorName", - "LabelOwnerName", - "CheckOwnerModify", - "CheckOwnerCopy", - "CheckOwnerTransfer", - "CheckShareWithGroup", - "CheckEveryoneCopy", - "CheckNextOwnerModify", - "CheckNextOwnerCopy", - "CheckNextOwnerTransfer", - "CheckPurchase", - "RadioSaleType", - "Edit Cost" - }; - - for(size_t t=0; tisComplete(); - const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType()); - const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD); - const LLPermissions& perm = item->getPermissions(); - const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, - GP_OBJECT_MANIPULATE); - const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, - GP_OBJECT_SET_SALE) && - !cannot_restrict_permissions; - const BOOL is_link = i->getIsLinkType(); - - // You need permission to modify the object to modify an inventory - // item in it. - LLViewerObject* object = NULL; - if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID); - BOOL is_obj_modify = TRUE; - if(object) - { - is_obj_modify = object->permOwnerModify(); - } - - ////////////////////// - // ITEM NAME & DESC // - ////////////////////// - BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm, - GP_OBJECT_MANIPULATE) - && is_obj_modify && is_complete; - - childSetEnabled("LabelItemNameTitle",TRUE); - childSetEnabled("LabelItemName",is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards - childSetText("LabelItemName",item->getName()); - childSetEnabled("LabelItemDescTitle",TRUE); - childSetEnabled("LabelItemDesc",is_modifiable); - childSetVisible("IconLocked",!is_modifiable); - childSetText("LabelItemDesc",item->getDescription()); - - ////////////////// - // CREATOR NAME // - ////////////////// - if(!gCacheName) return; - if(!gAgent.getRegion()) return; - - if (item->getCreatorUUID().notNull()) - { - std::string name; - gCacheName->getFullName(item->getCreatorUUID(), name); - childSetEnabled("BtnCreator",TRUE); - childSetEnabled("LabelCreatorTitle",TRUE); - childSetEnabled("LabelCreatorName",TRUE); - childSetText("LabelCreatorName",name); - } - else - { - childSetEnabled("BtnCreator",FALSE); - childSetEnabled("LabelCreatorTitle",FALSE); - childSetEnabled("LabelCreatorName",FALSE); - childSetText("LabelCreatorName",getString("unknown")); - } - - //////////////// - // OWNER NAME // - //////////////// - if(perm.isOwned()) - { - std::string name; - if (perm.isGroupOwned()) - { - gCacheName->getGroupName(perm.getGroup(), name); - } - else - { - gCacheName->getFullName(perm.getOwner(), name); - } - childSetEnabled("BtnOwner",TRUE); - childSetEnabled("LabelOwnerTitle",TRUE); - childSetEnabled("LabelOwnerName",TRUE); - childSetText("LabelOwnerName",name); - } - else - { - childSetEnabled("BtnOwner",FALSE); - childSetEnabled("LabelOwnerTitle",FALSE); - childSetEnabled("LabelOwnerName",FALSE); - childSetText("LabelOwnerName",getString("public")); - } - - ////////////////// - // ACQUIRE DATE // - ////////////////// - - time_t time_utc = item->getCreationDate(); - if (0 == time_utc) - { - childSetText("LabelAcquiredDate",getString("unknown")); - } - else - { - std::string timeStr = getString("acquiredDate"); - LLSD substitution; - substitution["datetime"] = (S32) time_utc; - LLStringUtil::format (timeStr, substitution); - childSetText ("LabelAcquiredDate", timeStr); - } - - /////////////////////// - // OWNER PERMISSIONS // - /////////////////////// - if(can_agent_manipulate) - { - childSetText("OwnerLabel",getString("you_can")); - } - else - { - childSetText("OwnerLabel",getString("owner_can")); - } - - U32 base_mask = perm.getMaskBase(); - U32 owner_mask = perm.getMaskOwner(); - U32 group_mask = perm.getMaskGroup(); - U32 everyone_mask = perm.getMaskEveryone(); - U32 next_owner_mask = perm.getMaskNextOwner(); - - childSetEnabled("OwnerLabel",TRUE); - childSetEnabled("CheckOwnerModify",FALSE); - childSetValue("CheckOwnerModify",LLSD((BOOL)(owner_mask & PERM_MODIFY))); - childSetEnabled("CheckOwnerCopy",FALSE); - childSetValue("CheckOwnerCopy",LLSD((BOOL)(owner_mask & PERM_COPY))); - childSetEnabled("CheckOwnerTransfer",FALSE); - childSetValue("CheckOwnerTransfer",LLSD((BOOL)(owner_mask & PERM_TRANSFER))); - - /////////////////////// - // DEBUG PERMISSIONS // - /////////////////////// - - if( gSavedSettings.getBOOL("DebugPermissions") ) - { - BOOL slam_perm = FALSE; - BOOL overwrite_group = FALSE; - BOOL overwrite_everyone = FALSE; - - if (item->getType() == LLAssetType::AT_OBJECT) - { - U32 flags = item->getFlags(); - slam_perm = flags & LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM; - overwrite_everyone = flags & LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE; - overwrite_group = flags & LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; - } - - std::string perm_string; - - perm_string = "B: "; - perm_string += mask_to_string(base_mask); - childSetText("BaseMaskDebug",perm_string); - childSetVisible("BaseMaskDebug",TRUE); - - perm_string = "O: "; - perm_string += mask_to_string(owner_mask); - childSetText("OwnerMaskDebug",perm_string); - childSetVisible("OwnerMaskDebug",TRUE); - - perm_string = "G"; - perm_string += overwrite_group ? "*: " : ": "; - perm_string += mask_to_string(group_mask); - childSetText("GroupMaskDebug",perm_string); - childSetVisible("GroupMaskDebug",TRUE); - - perm_string = "E"; - perm_string += overwrite_everyone ? "*: " : ": "; - perm_string += mask_to_string(everyone_mask); - childSetText("EveryoneMaskDebug",perm_string); - childSetVisible("EveryoneMaskDebug",TRUE); - - perm_string = "N"; - perm_string += slam_perm ? "*: " : ": "; - perm_string += mask_to_string(next_owner_mask); - childSetText("NextMaskDebug",perm_string); - childSetVisible("NextMaskDebug",TRUE); - } - else - { - childSetVisible("BaseMaskDebug",FALSE); - childSetVisible("OwnerMaskDebug",FALSE); - childSetVisible("GroupMaskDebug",FALSE); - childSetVisible("EveryoneMaskDebug",FALSE); - childSetVisible("NextMaskDebug",FALSE); - } - - ///////////// - // SHARING // - ///////////// - - // Check for ability to change values. - if (is_link || cannot_restrict_permissions) - { - childSetEnabled("CheckShareWithGroup",FALSE); - childSetEnabled("CheckEveryoneCopy",FALSE); - } - else if (is_obj_modify && can_agent_manipulate) - { - childSetEnabled("CheckShareWithGroup",TRUE); - childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER)); - } - else - { - childSetEnabled("CheckShareWithGroup",FALSE); - childSetEnabled("CheckEveryoneCopy",FALSE); - } - - // Set values. - BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE; - BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE; - BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE; - - if (is_group_copy && is_group_modify && is_group_move) - { - childSetValue("CheckShareWithGroup",LLSD((BOOL)TRUE)); - - LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); - if(ctl) - { - ctl->setTentative(FALSE); - } - } - else if (!is_group_copy && !is_group_modify && !is_group_move) - { - childSetValue("CheckShareWithGroup",LLSD((BOOL)FALSE)); - LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); - if(ctl) - { - ctl->setTentative(FALSE); - } - } - else - { - LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); - if(ctl) - { - ctl->setTentative(TRUE); - ctl->set(TRUE); - } - } - - childSetValue("CheckEveryoneCopy",LLSD((BOOL)(everyone_mask & PERM_COPY))); - - /////////////// - // SALE INFO // - /////////////// - - const LLSaleInfo& sale_info = item->getSaleInfo(); - BOOL is_for_sale = sale_info.isForSale(); - // Check for ability to change values. - if (is_obj_modify && can_agent_sell - && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE)) - { - childSetEnabled("SaleLabel",is_complete); - childSetEnabled("CheckPurchase",is_complete); - - childSetEnabled("NextOwnerLabel",TRUE); - childSetEnabled("CheckNextOwnerModify",(base_mask & PERM_MODIFY) && !cannot_restrict_permissions); - childSetEnabled("CheckNextOwnerCopy",(base_mask & PERM_COPY) && !cannot_restrict_permissions); - childSetEnabled("CheckNextOwnerTransfer",(next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); - - childSetEnabled("RadioSaleType",is_complete && is_for_sale); - childSetEnabled("TextPrice",is_complete && is_for_sale); - childSetEnabled("Edit Cost",is_complete && is_for_sale); - } - else - { - childSetEnabled("SaleLabel",FALSE); - childSetEnabled("CheckPurchase",FALSE); - - childSetEnabled("NextOwnerLabel",FALSE); - childSetEnabled("CheckNextOwnerModify",FALSE); - childSetEnabled("CheckNextOwnerCopy",FALSE); - childSetEnabled("CheckNextOwnerTransfer",FALSE); - - childSetEnabled("RadioSaleType",FALSE); - childSetEnabled("TextPrice",FALSE); - childSetEnabled("Edit Cost",FALSE); - } - - // Set values. - childSetValue("CheckPurchase", is_for_sale); - childSetEnabled("combobox sale copy", is_for_sale); - childSetEnabled("Edit Cost", is_for_sale); - childSetValue("CheckNextOwnerModify",LLSD(BOOL(next_owner_mask & PERM_MODIFY))); - childSetValue("CheckNextOwnerCopy",LLSD(BOOL(next_owner_mask & PERM_COPY))); - childSetValue("CheckNextOwnerTransfer",LLSD(BOOL(next_owner_mask & PERM_TRANSFER))); - - LLRadioGroup* radioSaleType = getChild("RadioSaleType"); - if (is_for_sale) - { - radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); - S32 numerical_price; - numerical_price = sale_info.getSalePrice(); - childSetText("Edit Cost",llformat("%d",numerical_price)); - } - else - { - radioSaleType->setSelectedIndex(-1); - childSetText("Edit Cost",llformat("%d",0)); - } -} - -void LLSidepanelItemInfo::onClickCreator() -{ - LLInventoryItem* item = findItem(); - if(!item) return; - if(!item->getCreatorUUID().isNull()) - { - LLAvatarActions::showProfile(item->getCreatorUUID()); - } -} - -// static -void LLSidepanelItemInfo::onClickOwner() -{ - LLInventoryItem* item = findItem(); - if(!item) return; - if(item->getPermissions().isGroupOwned()) - { - LLGroupActions::show(item->getPermissions().getGroup()); - } - else - { - LLAvatarActions::showProfile(item->getPermissions().getOwner()); - } -} - -// static -void LLSidepanelItemInfo::onCommitName() -{ - //llinfos << "LLSidepanelItemInfo::onCommitName()" << llendl; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); - if(!item) - { - return; - } - LLLineEditor* labelItemName = getChild("LabelItemName"); - - if(labelItemName&& - (item->getName() != labelItemName->getText()) && - (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) ) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(labelItemName->getText()); - if(mObjectID.isNull()) - { - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - LLViewerObject* object = gObjectList.findObject(mObjectID); - if(object) - { - object->updateInventory( - new_item, - TASK_INVENTORY_ITEM_KEY, - false); - } - } - } -} - -void LLSidepanelItemInfo::onCommitDescription() -{ - //llinfos << "LLSidepanelItemInfo::onCommitDescription()" << llendl; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); - if(!item) return; - - LLLineEditor* labelItemDesc = getChild("LabelItemDesc"); - if(!labelItemDesc) - { - return; - } - if((item->getDescription() != labelItemDesc->getText()) && - (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))) - { - LLPointer new_item = new LLViewerInventoryItem(item); - - new_item->setDescription(labelItemDesc->getText()); - if(mObjectID.isNull()) - { - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - LLViewerObject* object = gObjectList.findObject(mObjectID); - if(object) - { - object->updateInventory( - new_item, - TASK_INVENTORY_ITEM_KEY, - false); - } - } - } -} - -// static -void LLSidepanelItemInfo::onCommitPermissions() -{ - //llinfos << "LLSidepanelItemInfo::onCommitPermissions()" << llendl; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); - if(!item) return; - LLPermissions perm(item->getPermissions()); - - - LLCheckBoxCtrl* CheckShareWithGroup = getChild("CheckShareWithGroup"); - - if(CheckShareWithGroup) - { - perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(), - CheckShareWithGroup->get(), - PERM_MODIFY | PERM_MOVE | PERM_COPY); - } - LLCheckBoxCtrl* CheckEveryoneCopy = getChild("CheckEveryoneCopy"); - if(CheckEveryoneCopy) - { - perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), - CheckEveryoneCopy->get(), PERM_COPY); - } - - LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify"); - if(CheckNextOwnerModify) - { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), - CheckNextOwnerModify->get(), PERM_MODIFY); - } - LLCheckBoxCtrl* CheckNextOwnerCopy = getChild("CheckNextOwnerCopy"); - if(CheckNextOwnerCopy) - { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), - CheckNextOwnerCopy->get(), PERM_COPY); - } - LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild("CheckNextOwnerTransfer"); - if(CheckNextOwnerTransfer) - { - perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), - CheckNextOwnerTransfer->get(), PERM_TRANSFER); - } - if(perm != item->getPermissions() - && item->isComplete()) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setPermissions(perm); - U32 flags = new_item->getFlags(); - // If next owner permissions have changed (and this is an object) - // then set the slam permissions flag so that they are applied on rez. - if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner()) - && (item->getType() == LLAssetType::AT_OBJECT)) - { - flags |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM; - } - // If everyone permissions have changed (and this is an object) - // then set the overwrite everyone permissions flag so they - // are applied on rez. - if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone()) - && (item->getType() == LLAssetType::AT_OBJECT)) - { - flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE; - } - // If group permissions have changed (and this is an object) - // then set the overwrite group permissions flag so they - // are applied on rez. - if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup()) - && (item->getType() == LLAssetType::AT_OBJECT)) - { - flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; - } - new_item->setFlags(flags); - if(mObjectID.isNull()) - { - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - LLViewerObject* object = gObjectList.findObject(mObjectID); - if(object) - { - object->updateInventory( - new_item, - TASK_INVENTORY_ITEM_KEY, - false); - } - } - } - else - { - // need to make sure we don't just follow the click - refresh(); - } -} - -// static -void LLSidepanelItemInfo::onCommitSaleInfo() -{ - //llinfos << "LLSidepanelItemInfo::onCommitSaleInfo()" << llendl; - updateSaleInfo(); -} - -// static -void LLSidepanelItemInfo::onCommitSaleType() -{ - //llinfos << "LLSidepanelItemInfo::onCommitSaleType()" << llendl; - updateSaleInfo(); -} - -void LLSidepanelItemInfo::updateSaleInfo() -{ - LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); - if(!item) return; - LLSaleInfo sale_info(item->getSaleInfo()); - if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE)) - { - childSetValue("CheckPurchase",LLSD((BOOL)FALSE)); - } - - if((BOOL)childGetValue("CheckPurchase")) - { - // turn on sale info - LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY; - - LLRadioGroup* RadioSaleType = getChild("RadioSaleType"); - if(RadioSaleType) - { - switch (RadioSaleType->getSelectedIndex()) - { - case 0: - sale_type = LLSaleInfo::FS_ORIGINAL; - break; - case 1: - sale_type = LLSaleInfo::FS_COPY; - break; - case 2: - sale_type = LLSaleInfo::FS_CONTENTS; - break; - default: - sale_type = LLSaleInfo::FS_COPY; - break; - } - } - - if (sale_type == LLSaleInfo::FS_COPY - && !gAgent.allowOperation(PERM_COPY, item->getPermissions(), - GP_OBJECT_SET_SALE)) - { - sale_type = LLSaleInfo::FS_ORIGINAL; - } - - - - S32 price = -1; - price = getChild("Edit Cost")->getValue().asInteger();; - - // Invalid data - turn off the sale - if (price < 0) - { - sale_type = LLSaleInfo::FS_NOT; - price = 0; - } - - sale_info.setSaleType(sale_type); - sale_info.setSalePrice(price); - } - else - { - sale_info.setSaleType(LLSaleInfo::FS_NOT); - } - if(sale_info != item->getSaleInfo() - && item->isComplete()) - { - LLPointer new_item = new LLViewerInventoryItem(item); - - // Force an update on the sale price at rez - if (item->getType() == LLAssetType::AT_OBJECT) - { - U32 flags = new_item->getFlags(); - flags |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_SALE; - new_item->setFlags(flags); - } - - new_item->setSaleInfo(sale_info); - if(mObjectID.isNull()) - { - // This is in the agent's inventory. - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - // This is in an object's contents. - LLViewerObject* object = gObjectList.findObject(mObjectID); - if(object) - { - object->updateInventory( - new_item, - TASK_INVENTORY_ITEM_KEY, - false); - } - } - } - else - { - // need to make sure we don't just follow the click - refresh(); - } -} - -LLInventoryItem* LLSidepanelItemInfo::findItem() const -{ - LLInventoryItem* item = NULL; - if(mObjectID.isNull()) - { - // it is in agent inventory - item = gInventory.getItem(mItemID); - } - else - { - LLViewerObject* object = gObjectList.findObject(mObjectID); - if(object) - { - item = (LLInventoryItem*)object->getInventoryObject(mItemID); - } - } - return item; -} - -// virtual -void LLSidepanelItemInfo::updateVerbs() -{ - LLSidepanelInventorySubpanel::updateVerbs(); - - const LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); - if (item) - { - const LLPermissions& perm = item->getPermissions(); - BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm, - GP_OBJECT_MANIPULATE); - mEditBtn->setEnabled(is_modifiable); - } -} - -// virtual -void LLSidepanelItemInfo::save() -{ - onCommitName(); - onCommitDescription(); - onCommitPermissions(); - onCommitSaleInfo(); - onCommitSaleType(); -} +/** + * @file llsidepaneliteminfo.cpp + * @brief A floater which shows an inventory item's properties. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llsidepaneliteminfo.h" + +#include "roles_constants.h" + +#include "llagent.h" +#include "llavataractions.h" +#include "llbutton.h" +#include "llfloaterreg.h" +#include "llgroupactions.h" +#include "llinventorymodel.h" +#include "llinventoryobserver.h" +#include "lllineeditor.h" +#include "llradiogroup.h" +#include "llviewercontrol.h" +#include "llviewerinventory.h" +#include "llviewerobjectlist.h" + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLItemPropertiesObserver +// +// Helper class to watch for changes to the item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLItemPropertiesObserver : public LLInventoryObserver +{ +public: + LLItemPropertiesObserver(LLSidepanelItemInfo* floater) + : mFloater(floater) + { + gInventory.addObserver(this); + } + virtual ~LLItemPropertiesObserver() + { + gInventory.removeObserver(this); + } + virtual void changed(U32 mask); +private: + LLSidepanelItemInfo* mFloater; +}; + +void LLItemPropertiesObserver::changed(U32 mask) +{ + // if there's a change we're interested in. + if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0) + { + mFloater->dirty(); + } +} + + + +///---------------------------------------------------------------------------- +/// Class LLSidepanelItemInfo +///---------------------------------------------------------------------------- + +static LLRegisterPanelClassWrapper t_item_info("sidepanel_item_info"); + +// Default constructor +LLSidepanelItemInfo::LLSidepanelItemInfo() + : mItemID(LLUUID::null) +{ + mPropertiesObserver = new LLItemPropertiesObserver(this); + + //LLUICtrlFactory::getInstance()->buildFloater(this,"floater_inventory_item_properties.xml"); +} + +// Destroys the object +LLSidepanelItemInfo::~LLSidepanelItemInfo() +{ + delete mPropertiesObserver; + mPropertiesObserver = NULL; +} + +// virtual +BOOL LLSidepanelItemInfo::postBuild() +{ + LLSidepanelInventorySubpanel::postBuild(); + + // build the UI + // item name & description + childSetPrevalidate("LabelItemName",&LLLineEditor::prevalidateASCIIPrintableNoPipe); + //getChild("LabelItemName")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onCommitName,this)); + childSetPrevalidate("LabelItemDesc",&LLLineEditor::prevalidateASCIIPrintableNoPipe); + //getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLSidepanelItemInfo:: onCommitDescription, this)); + + // Creator information + getChild("BtnCreator")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickCreator,this)); + + // owner information + getChild("BtnOwner")->setCommitCallback(boost::bind(&LLSidepanelItemInfo::onClickOwner,this)); + + refresh(); + return TRUE; +} + +void LLSidepanelItemInfo::setObjectID(const LLUUID& object_id) +{ + mObjectID = object_id; +} + +void LLSidepanelItemInfo::setItemID(const LLUUID& item_id) +{ + mItemID = item_id; +} + +void LLSidepanelItemInfo::reset() +{ + LLSidepanelInventorySubpanel::reset(); + + mObjectID = LLUUID::null; + mItemID = LLUUID::null; +} + +void LLSidepanelItemInfo::refresh() +{ + LLInventoryItem* item = findItem(); + if(item) + { + refreshFromItem(item); + updateVerbs(); + } + else + { + if (getIsEditing()) + { + setIsEditing(FALSE); + return; + } + } + + if (!getIsEditing()) + { + const std::string no_item_names[]={ + "LabelItemName", + "LabelItemDesc", + "LabelCreatorName", + "LabelOwnerName", + "CheckOwnerModify", + "CheckOwnerCopy", + "CheckOwnerTransfer", + "CheckShareWithGroup", + "CheckEveryoneCopy", + "CheckNextOwnerModify", + "CheckNextOwnerCopy", + "CheckNextOwnerTransfer", + "CheckPurchase", + "RadioSaleType", + "Edit Cost" + }; + + for(size_t t=0; tisComplete(); + const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType()); + const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD); + const LLPermissions& perm = item->getPermissions(); + const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, + GP_OBJECT_MANIPULATE); + const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, + GP_OBJECT_SET_SALE) && + !cannot_restrict_permissions; + const BOOL is_link = i->getIsLinkType(); + + // You need permission to modify the object to modify an inventory + // item in it. + LLViewerObject* object = NULL; + if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID); + BOOL is_obj_modify = TRUE; + if(object) + { + is_obj_modify = object->permOwnerModify(); + } + + ////////////////////// + // ITEM NAME & DESC // + ////////////////////// + BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm, + GP_OBJECT_MANIPULATE) + && is_obj_modify && is_complete; + + childSetEnabled("LabelItemNameTitle",TRUE); + childSetEnabled("LabelItemName",is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards + childSetText("LabelItemName",item->getName()); + childSetEnabled("LabelItemDescTitle",TRUE); + childSetEnabled("LabelItemDesc",is_modifiable); + childSetVisible("IconLocked",!is_modifiable); + childSetText("LabelItemDesc",item->getDescription()); + + ////////////////// + // CREATOR NAME // + ////////////////// + if(!gCacheName) return; + if(!gAgent.getRegion()) return; + + if (item->getCreatorUUID().notNull()) + { + std::string name; + gCacheName->getFullName(item->getCreatorUUID(), name); + childSetEnabled("BtnCreator",TRUE); + childSetEnabled("LabelCreatorTitle",TRUE); + childSetEnabled("LabelCreatorName",TRUE); + childSetText("LabelCreatorName",name); + } + else + { + childSetEnabled("BtnCreator",FALSE); + childSetEnabled("LabelCreatorTitle",FALSE); + childSetEnabled("LabelCreatorName",FALSE); + childSetText("LabelCreatorName",getString("unknown")); + } + + //////////////// + // OWNER NAME // + //////////////// + if(perm.isOwned()) + { + std::string name; + if (perm.isGroupOwned()) + { + gCacheName->getGroupName(perm.getGroup(), name); + } + else + { + gCacheName->getFullName(perm.getOwner(), name); + } + childSetEnabled("BtnOwner",TRUE); + childSetEnabled("LabelOwnerTitle",TRUE); + childSetEnabled("LabelOwnerName",TRUE); + childSetText("LabelOwnerName",name); + } + else + { + childSetEnabled("BtnOwner",FALSE); + childSetEnabled("LabelOwnerTitle",FALSE); + childSetEnabled("LabelOwnerName",FALSE); + childSetText("LabelOwnerName",getString("public")); + } + + ////////////////// + // ACQUIRE DATE // + ////////////////// + + time_t time_utc = item->getCreationDate(); + if (0 == time_utc) + { + childSetText("LabelAcquiredDate",getString("unknown")); + } + else + { + std::string timeStr = getString("acquiredDate"); + LLSD substitution; + substitution["datetime"] = (S32) time_utc; + LLStringUtil::format (timeStr, substitution); + childSetText ("LabelAcquiredDate", timeStr); + } + + /////////////////////// + // OWNER PERMISSIONS // + /////////////////////// + if(can_agent_manipulate) + { + childSetText("OwnerLabel",getString("you_can")); + } + else + { + childSetText("OwnerLabel",getString("owner_can")); + } + + U32 base_mask = perm.getMaskBase(); + U32 owner_mask = perm.getMaskOwner(); + U32 group_mask = perm.getMaskGroup(); + U32 everyone_mask = perm.getMaskEveryone(); + U32 next_owner_mask = perm.getMaskNextOwner(); + + childSetEnabled("OwnerLabel",TRUE); + childSetEnabled("CheckOwnerModify",FALSE); + childSetValue("CheckOwnerModify",LLSD((BOOL)(owner_mask & PERM_MODIFY))); + childSetEnabled("CheckOwnerCopy",FALSE); + childSetValue("CheckOwnerCopy",LLSD((BOOL)(owner_mask & PERM_COPY))); + childSetEnabled("CheckOwnerTransfer",FALSE); + childSetValue("CheckOwnerTransfer",LLSD((BOOL)(owner_mask & PERM_TRANSFER))); + + /////////////////////// + // DEBUG PERMISSIONS // + /////////////////////// + + if( gSavedSettings.getBOOL("DebugPermissions") ) + { + BOOL slam_perm = FALSE; + BOOL overwrite_group = FALSE; + BOOL overwrite_everyone = FALSE; + + if (item->getType() == LLAssetType::AT_OBJECT) + { + U32 flags = item->getFlags(); + slam_perm = flags & LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM; + overwrite_everyone = flags & LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE; + overwrite_group = flags & LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; + } + + std::string perm_string; + + perm_string = "B: "; + perm_string += mask_to_string(base_mask); + childSetText("BaseMaskDebug",perm_string); + childSetVisible("BaseMaskDebug",TRUE); + + perm_string = "O: "; + perm_string += mask_to_string(owner_mask); + childSetText("OwnerMaskDebug",perm_string); + childSetVisible("OwnerMaskDebug",TRUE); + + perm_string = "G"; + perm_string += overwrite_group ? "*: " : ": "; + perm_string += mask_to_string(group_mask); + childSetText("GroupMaskDebug",perm_string); + childSetVisible("GroupMaskDebug",TRUE); + + perm_string = "E"; + perm_string += overwrite_everyone ? "*: " : ": "; + perm_string += mask_to_string(everyone_mask); + childSetText("EveryoneMaskDebug",perm_string); + childSetVisible("EveryoneMaskDebug",TRUE); + + perm_string = "N"; + perm_string += slam_perm ? "*: " : ": "; + perm_string += mask_to_string(next_owner_mask); + childSetText("NextMaskDebug",perm_string); + childSetVisible("NextMaskDebug",TRUE); + } + else + { + childSetVisible("BaseMaskDebug",FALSE); + childSetVisible("OwnerMaskDebug",FALSE); + childSetVisible("GroupMaskDebug",FALSE); + childSetVisible("EveryoneMaskDebug",FALSE); + childSetVisible("NextMaskDebug",FALSE); + } + + ///////////// + // SHARING // + ///////////// + + // Check for ability to change values. + if (is_link || cannot_restrict_permissions) + { + childSetEnabled("CheckShareWithGroup",FALSE); + childSetEnabled("CheckEveryoneCopy",FALSE); + } + else if (is_obj_modify && can_agent_manipulate) + { + childSetEnabled("CheckShareWithGroup",TRUE); + childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER)); + } + else + { + childSetEnabled("CheckShareWithGroup",FALSE); + childSetEnabled("CheckEveryoneCopy",FALSE); + } + + // Set values. + BOOL is_group_copy = (group_mask & PERM_COPY) ? TRUE : FALSE; + BOOL is_group_modify = (group_mask & PERM_MODIFY) ? TRUE : FALSE; + BOOL is_group_move = (group_mask & PERM_MOVE) ? TRUE : FALSE; + + if (is_group_copy && is_group_modify && is_group_move) + { + childSetValue("CheckShareWithGroup",LLSD((BOOL)TRUE)); + + LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); + if(ctl) + { + ctl->setTentative(FALSE); + } + } + else if (!is_group_copy && !is_group_modify && !is_group_move) + { + childSetValue("CheckShareWithGroup",LLSD((BOOL)FALSE)); + LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); + if(ctl) + { + ctl->setTentative(FALSE); + } + } + else + { + LLCheckBoxCtrl* ctl = getChild("CheckShareWithGroup"); + if(ctl) + { + ctl->setTentative(TRUE); + ctl->set(TRUE); + } + } + + childSetValue("CheckEveryoneCopy",LLSD((BOOL)(everyone_mask & PERM_COPY))); + + /////////////// + // SALE INFO // + /////////////// + + const LLSaleInfo& sale_info = item->getSaleInfo(); + BOOL is_for_sale = sale_info.isForSale(); + // Check for ability to change values. + if (is_obj_modify && can_agent_sell + && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE)) + { + childSetEnabled("SaleLabel",is_complete); + childSetEnabled("CheckPurchase",is_complete); + + childSetEnabled("NextOwnerLabel",TRUE); + childSetEnabled("CheckNextOwnerModify",(base_mask & PERM_MODIFY) && !cannot_restrict_permissions); + childSetEnabled("CheckNextOwnerCopy",(base_mask & PERM_COPY) && !cannot_restrict_permissions); + childSetEnabled("CheckNextOwnerTransfer",(next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); + + childSetEnabled("RadioSaleType",is_complete && is_for_sale); + childSetEnabled("TextPrice",is_complete && is_for_sale); + childSetEnabled("Edit Cost",is_complete && is_for_sale); + } + else + { + childSetEnabled("SaleLabel",FALSE); + childSetEnabled("CheckPurchase",FALSE); + + childSetEnabled("NextOwnerLabel",FALSE); + childSetEnabled("CheckNextOwnerModify",FALSE); + childSetEnabled("CheckNextOwnerCopy",FALSE); + childSetEnabled("CheckNextOwnerTransfer",FALSE); + + childSetEnabled("RadioSaleType",FALSE); + childSetEnabled("TextPrice",FALSE); + childSetEnabled("Edit Cost",FALSE); + } + + // Set values. + childSetValue("CheckPurchase", is_for_sale); + childSetEnabled("combobox sale copy", is_for_sale); + childSetEnabled("Edit Cost", is_for_sale); + childSetValue("CheckNextOwnerModify",LLSD(BOOL(next_owner_mask & PERM_MODIFY))); + childSetValue("CheckNextOwnerCopy",LLSD(BOOL(next_owner_mask & PERM_COPY))); + childSetValue("CheckNextOwnerTransfer",LLSD(BOOL(next_owner_mask & PERM_TRANSFER))); + + LLRadioGroup* radioSaleType = getChild("RadioSaleType"); + if (is_for_sale) + { + radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); + S32 numerical_price; + numerical_price = sale_info.getSalePrice(); + childSetText("Edit Cost",llformat("%d",numerical_price)); + } + else + { + radioSaleType->setSelectedIndex(-1); + childSetText("Edit Cost",llformat("%d",0)); + } +} + +void LLSidepanelItemInfo::onClickCreator() +{ + LLInventoryItem* item = findItem(); + if(!item) return; + if(!item->getCreatorUUID().isNull()) + { + LLAvatarActions::showProfile(item->getCreatorUUID()); + } +} + +// static +void LLSidepanelItemInfo::onClickOwner() +{ + LLInventoryItem* item = findItem(); + if(!item) return; + if(item->getPermissions().isGroupOwned()) + { + LLGroupActions::show(item->getPermissions().getGroup()); + } + else + { + LLAvatarActions::showProfile(item->getPermissions().getOwner()); + } +} + +// static +void LLSidepanelItemInfo::onCommitName() +{ + //llinfos << "LLSidepanelItemInfo::onCommitName()" << llendl; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); + if(!item) + { + return; + } + LLLineEditor* labelItemName = getChild("LabelItemName"); + + if(labelItemName&& + (item->getName() != labelItemName->getText()) && + (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) ) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->rename(labelItemName->getText()); + if(mObjectID.isNull()) + { + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + LLViewerObject* object = gObjectList.findObject(mObjectID); + if(object) + { + object->updateInventory( + new_item, + TASK_INVENTORY_ITEM_KEY, + false); + } + } + } +} + +void LLSidepanelItemInfo::onCommitDescription() +{ + //llinfos << "LLSidepanelItemInfo::onCommitDescription()" << llendl; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); + if(!item) return; + + LLLineEditor* labelItemDesc = getChild("LabelItemDesc"); + if(!labelItemDesc) + { + return; + } + if((item->getDescription() != labelItemDesc->getText()) && + (gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE))) + { + LLPointer new_item = new LLViewerInventoryItem(item); + + new_item->setDescription(labelItemDesc->getText()); + if(mObjectID.isNull()) + { + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + LLViewerObject* object = gObjectList.findObject(mObjectID); + if(object) + { + object->updateInventory( + new_item, + TASK_INVENTORY_ITEM_KEY, + false); + } + } + } +} + +// static +void LLSidepanelItemInfo::onCommitPermissions() +{ + //llinfos << "LLSidepanelItemInfo::onCommitPermissions()" << llendl; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); + if(!item) return; + LLPermissions perm(item->getPermissions()); + + + LLCheckBoxCtrl* CheckShareWithGroup = getChild("CheckShareWithGroup"); + + if(CheckShareWithGroup) + { + perm.setGroupBits(gAgent.getID(), gAgent.getGroupID(), + CheckShareWithGroup->get(), + PERM_MODIFY | PERM_MOVE | PERM_COPY); + } + LLCheckBoxCtrl* CheckEveryoneCopy = getChild("CheckEveryoneCopy"); + if(CheckEveryoneCopy) + { + perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), + CheckEveryoneCopy->get(), PERM_COPY); + } + + LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify"); + if(CheckNextOwnerModify) + { + perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + CheckNextOwnerModify->get(), PERM_MODIFY); + } + LLCheckBoxCtrl* CheckNextOwnerCopy = getChild("CheckNextOwnerCopy"); + if(CheckNextOwnerCopy) + { + perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + CheckNextOwnerCopy->get(), PERM_COPY); + } + LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild("CheckNextOwnerTransfer"); + if(CheckNextOwnerTransfer) + { + perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), + CheckNextOwnerTransfer->get(), PERM_TRANSFER); + } + if(perm != item->getPermissions() + && item->isComplete()) + { + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setPermissions(perm); + U32 flags = new_item->getFlags(); + // If next owner permissions have changed (and this is an object) + // then set the slam permissions flag so that they are applied on rez. + if((perm.getMaskNextOwner()!=item->getPermissions().getMaskNextOwner()) + && (item->getType() == LLAssetType::AT_OBJECT)) + { + flags |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_PERM; + } + // If everyone permissions have changed (and this is an object) + // then set the overwrite everyone permissions flag so they + // are applied on rez. + if ((perm.getMaskEveryone()!=item->getPermissions().getMaskEveryone()) + && (item->getType() == LLAssetType::AT_OBJECT)) + { + flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE; + } + // If group permissions have changed (and this is an object) + // then set the overwrite group permissions flag so they + // are applied on rez. + if ((perm.getMaskGroup()!=item->getPermissions().getMaskGroup()) + && (item->getType() == LLAssetType::AT_OBJECT)) + { + flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; + } + new_item->setFlags(flags); + if(mObjectID.isNull()) + { + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + LLViewerObject* object = gObjectList.findObject(mObjectID); + if(object) + { + object->updateInventory( + new_item, + TASK_INVENTORY_ITEM_KEY, + false); + } + } + } + else + { + // need to make sure we don't just follow the click + refresh(); + } +} + +// static +void LLSidepanelItemInfo::onCommitSaleInfo() +{ + //llinfos << "LLSidepanelItemInfo::onCommitSaleInfo()" << llendl; + updateSaleInfo(); +} + +// static +void LLSidepanelItemInfo::onCommitSaleType() +{ + //llinfos << "LLSidepanelItemInfo::onCommitSaleType()" << llendl; + updateSaleInfo(); +} + +void LLSidepanelItemInfo::updateSaleInfo() +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); + if(!item) return; + LLSaleInfo sale_info(item->getSaleInfo()); + if(!gAgent.allowOperation(PERM_TRANSFER, item->getPermissions(), GP_OBJECT_SET_SALE)) + { + childSetValue("CheckPurchase",LLSD((BOOL)FALSE)); + } + + if((BOOL)childGetValue("CheckPurchase")) + { + // turn on sale info + LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_COPY; + + LLRadioGroup* RadioSaleType = getChild("RadioSaleType"); + if(RadioSaleType) + { + switch (RadioSaleType->getSelectedIndex()) + { + case 0: + sale_type = LLSaleInfo::FS_ORIGINAL; + break; + case 1: + sale_type = LLSaleInfo::FS_COPY; + break; + case 2: + sale_type = LLSaleInfo::FS_CONTENTS; + break; + default: + sale_type = LLSaleInfo::FS_COPY; + break; + } + } + + if (sale_type == LLSaleInfo::FS_COPY + && !gAgent.allowOperation(PERM_COPY, item->getPermissions(), + GP_OBJECT_SET_SALE)) + { + sale_type = LLSaleInfo::FS_ORIGINAL; + } + + + + S32 price = -1; + price = getChild("Edit Cost")->getValue().asInteger();; + + // Invalid data - turn off the sale + if (price < 0) + { + sale_type = LLSaleInfo::FS_NOT; + price = 0; + } + + sale_info.setSaleType(sale_type); + sale_info.setSalePrice(price); + } + else + { + sale_info.setSaleType(LLSaleInfo::FS_NOT); + } + if(sale_info != item->getSaleInfo() + && item->isComplete()) + { + LLPointer new_item = new LLViewerInventoryItem(item); + + // Force an update on the sale price at rez + if (item->getType() == LLAssetType::AT_OBJECT) + { + U32 flags = new_item->getFlags(); + flags |= LLInventoryItem::II_FLAGS_OBJECT_SLAM_SALE; + new_item->setFlags(flags); + } + + new_item->setSaleInfo(sale_info); + if(mObjectID.isNull()) + { + // This is in the agent's inventory. + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } + else + { + // This is in an object's contents. + LLViewerObject* object = gObjectList.findObject(mObjectID); + if(object) + { + object->updateInventory( + new_item, + TASK_INVENTORY_ITEM_KEY, + false); + } + } + } + else + { + // need to make sure we don't just follow the click + refresh(); + } +} + +LLInventoryItem* LLSidepanelItemInfo::findItem() const +{ + LLInventoryItem* item = NULL; + if(mObjectID.isNull()) + { + // it is in agent inventory + item = gInventory.getItem(mItemID); + } + else + { + LLViewerObject* object = gObjectList.findObject(mObjectID); + if(object) + { + item = (LLInventoryItem*)object->getInventoryObject(mItemID); + } + } + return item; +} + +// virtual +void LLSidepanelItemInfo::updateVerbs() +{ + LLSidepanelInventorySubpanel::updateVerbs(); + + const LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); + if (item) + { + const LLPermissions& perm = item->getPermissions(); + BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm, + GP_OBJECT_MANIPULATE); + mEditBtn->setEnabled(is_modifiable); + } +} + +// virtual +void LLSidepanelItemInfo::save() +{ + onCommitName(); + onCommitDescription(); + onCommitPermissions(); + onCommitSaleInfo(); + onCommitSaleType(); +} diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h index b348b5cceb..4bfbd56ea7 100644 --- a/indra/newview/llsidepaneliteminfo.h +++ b/indra/newview/llsidepaneliteminfo.h @@ -1,91 +1,91 @@ -/** - * @file llsidepaneliteminfo.h - * @brief A panel which shows an inventory item's properties. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * 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 - * - * 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 - * - * 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. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLSIDEPANELITEMINFO_H -#define LL_LLSIDEPANELITEMINFO_H - -#include "llsidepanelinventorysubpanel.h" - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLSidepanelItemInfo -// Object properties for inventory side panel. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLButton; -class LLInventoryItem; -class LLItemPropertiesObserver; -class LLViewerObject; -class LLPermissions; - -class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel -{ -public: - LLSidepanelItemInfo(); - virtual ~LLSidepanelItemInfo(); - - /*virtual*/ BOOL postBuild(); - /*virtual*/ void reset(); - - void setObjectID(const LLUUID& object_id); - void setItemID(const LLUUID& item_id); - void setEditMode(BOOL edit); - -protected: - /*virtual*/ void refresh(); - /*virtual*/ void save(); - /*virtual*/ void updateVerbs(); - - LLInventoryItem* findItem() const; - LLViewerObject* findObject() const; - - void refreshFromItem(LLInventoryItem* item); - -private: - LLUUID mItemID; // inventory UUID for the inventory item. - LLUUID mObjectID; // in-world task UUID, or null if in agent inventory. - LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item - - // - // UI Elements - // -protected: - void onClickCreator(); - void onClickOwner(); - void onCommitName(); - void onCommitDescription(); - void onCommitPermissions(); - void onCommitSaleInfo(); - void onCommitSaleType(); - void updateSaleInfo(); -}; - -#endif // LL_LLSIDEPANELITEMINFO_H +/** + * @file llsidepaneliteminfo.h + * @brief A panel which shows an inventory item's properties. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * 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 + * + * 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 + * + * 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. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSIDEPANELITEMINFO_H +#define LL_LLSIDEPANELITEMINFO_H + +#include "llsidepanelinventorysubpanel.h" + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLSidepanelItemInfo +// Object properties for inventory side panel. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLButton; +class LLInventoryItem; +class LLItemPropertiesObserver; +class LLViewerObject; +class LLPermissions; + +class LLSidepanelItemInfo : public LLSidepanelInventorySubpanel +{ +public: + LLSidepanelItemInfo(); + virtual ~LLSidepanelItemInfo(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void reset(); + + void setObjectID(const LLUUID& object_id); + void setItemID(const LLUUID& item_id); + void setEditMode(BOOL edit); + +protected: + /*virtual*/ void refresh(); + /*virtual*/ void save(); + /*virtual*/ void updateVerbs(); + + LLInventoryItem* findItem() const; + LLViewerObject* findObject() const; + + void refreshFromItem(LLInventoryItem* item); + +private: + LLUUID mItemID; // inventory UUID for the inventory item. + LLUUID mObjectID; // in-world task UUID, or null if in agent inventory. + LLItemPropertiesObserver* mPropertiesObserver; // for syncing changes to item + + // + // UI Elements + // +protected: + void onClickCreator(); + void onClickOwner(); + void onCommitName(); + void onCommitDescription(); + void onCommitPermissions(); + void onCommitSaleInfo(); + void onCommitSaleType(); + void updateSaleInfo(); +}; + +#endif // LL_LLSIDEPANELITEMINFO_H diff --git a/indra/newview/skins/default/xui/da/panel_edit_profile.xml b/indra/newview/skins/default/xui/da/panel_edit_profile.xml index 74b7c7dd72..b4d0fa20ef 100644 --- a/indra/newview/skins/default/xui/da/panel_edit_profile.xml +++ b/indra/newview/skins/default/xui/da/panel_edit_profile.xml @@ -1,45 +1,45 @@ - - - - [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] - - - - - - - - - - - - http://www.secondlife.com/account/partners.php?lang=da - - - - - - - [SECOND_LIFE]: - - - - - - - - - Optaget autosvar: - - - - + + + + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + + + + + + + + + + + + http://www.secondlife.com/account/partners.php?lang=da + + + + + + + [SECOND_LIFE]: + + + + + + + + + Optaget autosvar: + + + + diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index 8522a89ec1..ea5c33b3c8 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -1,40 +1,40 @@ - - - - - - Second Life wird Ihnen präsentiert von Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl und vielen anderen. - -Vielen Dank den folgenden Einwohnern, die uns geholfen haben, dies zur bisher besten Version zu machen: able whitman, Adeon Writer, adonaira aabye, Aeron Kohime, Agathos Frascati, Aimee Trescothick, Aleric Inglewood, Alissa Sabre, Aminom Marvin, Angela Talamasca, Aralara Rajal, Armin Weatherwax, Ashrilyn Hayashida, Athanasius Skytower, Aura Dirval, Barney Boomslang, Biancaluce Robbiani, Biker Offcourse, Borg Capalini, Bulli Schumann, catherine pfeffer, Chalice Yao, Corre Porta, Court Goodman, Cummere Mayo, Dale Innis, Darien Caldwell, Darjeeling Schoonhoven, Daten Thielt, dimentox travanti, Dirk Talamasca, Drew Dwi, Duckless Vandyke, Elanthius Flagstaff, Electro Burnstein, emiley tomsen, Escort DeFarge, Eva Rau, Ezian Ecksol, Fire Centaur, Fluf Fredriksson, Francisco Koolhoven, Frontera Thor, Frungi Stastny, Gally Young, gearsawe stonecutter, Gigs Taggart, Gordon Wendt, Gudmund Shepherd, Gypsy Paz, Harleen Gretzky, Henri Beauchamp, Inma Rau, Irene Muni, Iskar Ariantho, Jacek Antonelli, JB Kraft, Jessicka Graves, Joeseph Albanese, Joshua Philgarlic, Khyota Wulluf, kirstenlee Cinquetti, Latif Khalifa, Lex Neva, Lilibeth Andree, Lisa Lowe, Lunita Savira, Loosey Demonia, lum pfohl, Marcos Fonzarelli, MartinRJ Fayray, Marusame Arai, Matthew Dowd, Maya Remblai, McCabe Maxsted, Meghan Dench, Melchoir Tokhes, Menos Short, Michelle2 Zenovka, Mimika Oh, Minerva Memel, Mm Alder, Ochi Wolfe, Omei Turnbull, Pesho Replacement, Phantom Ninetails, phoenixflames kukulcan, Polo Gufler, prez pessoa, princess niven, Prokofy Neva, Qie Niangao, Rem Beattie, RodneyLee Jessop, Saijanai Kuhn, Seg Baphomet, Sergen Davies, Shirley Marquez, SignpostMarv Martin, Sindy Tsure, Sira Arbizu, Skips Jigsaw, Sougent Harrop, Spritely Pixel, Squirrel Wood, StarSong Bright, Subversive Writer, Sugarcult Dagger, Sylumm Grigorovich, Tammy Nowotny, Tanooki Darkes, Tayra Dagostino, Theoretical Chemistry, Thickbrick Sleaford, valerie rosewood, Vex Streeter, Vixen Heron, Whoops Babii, Winter Ventura, Xiki Luik, Yann Dufaux, Yina Yao, Yukinoroh Kamachi, Zolute Infinity, Zwagoth Klaar - - - -Um im Geschäftsleben erfolreich zu sein, sei kühn, sei schnell, sei anders. --Henry Marchant - - - - - 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion -APR Copyright (C) 2000-2004 The Apache Software Foundation -cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se) -expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. -FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). -GL Copyright (C) 1999-2004 Brian Paul. -Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. -jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) -jpeglib Copyright (C) 1991-1998, Thomas G. Lane. -ogg/vorbis Copyright (C) 2001, Xiphophorus -OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. -SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga -SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) -xmlrpc-epi Copyright (C) 2000 Epinions, Inc. -zlib Copyright (C) 1995-2002 Jean-loup Gailly und Mark Adler. -google-perftools Copyright (c) 2005, Google Inc. - -Alle Rechte vorbehalten. Details siehe licenses.txt. - -Voice-Chat-Audiocoding: Polycom(R) Siren14(TM) (ITU-T Empf.G.722.1 Anhang C) - - - - + + + + + + Second Life wird Ihnen präsentiert von Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl und vielen anderen. + +Vielen Dank den folgenden Einwohnern, die uns geholfen haben, dies zur bisher besten Version zu machen: able whitman, Adeon Writer, adonaira aabye, Aeron Kohime, Agathos Frascati, Aimee Trescothick, Aleric Inglewood, Alissa Sabre, Aminom Marvin, Angela Talamasca, Aralara Rajal, Armin Weatherwax, Ashrilyn Hayashida, Athanasius Skytower, Aura Dirval, Barney Boomslang, Biancaluce Robbiani, Biker Offcourse, Borg Capalini, Bulli Schumann, catherine pfeffer, Chalice Yao, Corre Porta, Court Goodman, Cummere Mayo, Dale Innis, Darien Caldwell, Darjeeling Schoonhoven, Daten Thielt, dimentox travanti, Dirk Talamasca, Drew Dwi, Duckless Vandyke, Elanthius Flagstaff, Electro Burnstein, emiley tomsen, Escort DeFarge, Eva Rau, Ezian Ecksol, Fire Centaur, Fluf Fredriksson, Francisco Koolhoven, Frontera Thor, Frungi Stastny, Gally Young, gearsawe stonecutter, Gigs Taggart, Gordon Wendt, Gudmund Shepherd, Gypsy Paz, Harleen Gretzky, Henri Beauchamp, Inma Rau, Irene Muni, Iskar Ariantho, Jacek Antonelli, JB Kraft, Jessicka Graves, Joeseph Albanese, Joshua Philgarlic, Khyota Wulluf, kirstenlee Cinquetti, Latif Khalifa, Lex Neva, Lilibeth Andree, Lisa Lowe, Lunita Savira, Loosey Demonia, lum pfohl, Marcos Fonzarelli, MartinRJ Fayray, Marusame Arai, Matthew Dowd, Maya Remblai, McCabe Maxsted, Meghan Dench, Melchoir Tokhes, Menos Short, Michelle2 Zenovka, Mimika Oh, Minerva Memel, Mm Alder, Ochi Wolfe, Omei Turnbull, Pesho Replacement, Phantom Ninetails, phoenixflames kukulcan, Polo Gufler, prez pessoa, princess niven, Prokofy Neva, Qie Niangao, Rem Beattie, RodneyLee Jessop, Saijanai Kuhn, Seg Baphomet, Sergen Davies, Shirley Marquez, SignpostMarv Martin, Sindy Tsure, Sira Arbizu, Skips Jigsaw, Sougent Harrop, Spritely Pixel, Squirrel Wood, StarSong Bright, Subversive Writer, Sugarcult Dagger, Sylumm Grigorovich, Tammy Nowotny, Tanooki Darkes, Tayra Dagostino, Theoretical Chemistry, Thickbrick Sleaford, valerie rosewood, Vex Streeter, Vixen Heron, Whoops Babii, Winter Ventura, Xiki Luik, Yann Dufaux, Yina Yao, Yukinoroh Kamachi, Zolute Infinity, Zwagoth Klaar + + + +Um im Geschäftsleben erfolreich zu sein, sei kühn, sei schnell, sei anders. --Henry Marchant + + + + + 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion +APR Copyright (C) 2000-2004 The Apache Software Foundation +cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se) +expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. +FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). +GL Copyright (C) 1999-2004 Brian Paul. +Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. +jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) +jpeglib Copyright (C) 1991-1998, Thomas G. Lane. +ogg/vorbis Copyright (C) 2001, Xiphophorus +OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. +SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga +SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +xmlrpc-epi Copyright (C) 2000 Epinions, Inc. +zlib Copyright (C) 1995-2002 Jean-loup Gailly und Mark Adler. +google-perftools Copyright (c) 2005, Google Inc. + +Alle Rechte vorbehalten. Details siehe licenses.txt. + +Voice-Chat-Audiocoding: Polycom(R) Siren14(TM) (ITU-T Empf.G.722.1 Anhang C) + + + + diff --git a/indra/newview/skins/default/xui/de/floater_about_land.xml b/indra/newview/skins/default/xui/de/floater_about_land.xml index ae0ad2af65..d6d7434d58 100644 --- a/indra/newview/skins/default/xui/de/floater_about_land.xml +++ b/indra/newview/skins/default/xui/de/floater_about_land.xml @@ -1,475 +1,475 @@ - - - - [MINUTES] Minuten - - - Minute - - - [SECONDS] Sekunden - - - - - Nur neue Benutzer - - - Jeder - - - Gebiet: - - - [AREA] qm. - - - Auktions-ID: [ID] - - - Bestätigen Sie den Kauf, um dieses Land zu bearbeiten. - - - (In Gruppenbesitz) - - - Profil... - - - Info... - - - (öffentlich) - - - (keiner) - - - (Wird verkauft) - - - Keine Parzelle ausgewählt. -Öffnen Sie „Welt“ > „Land-Info“ oder wählen Sie eine andere Parzelle aus, um Informationen darüber anzuzeigen. - - - Name: - - - Beschreibung: - - - Typ: - - - Mainland / Homestead - - - Einstufung: - - - Adult - - - Eigentümer: - - - Leyla Linden - -