Merge branch 'DRTVWR-591-maint-X' into marchcat/591-x-pbr-merge

# Conflicts:
#	indra/llrender/llgl.cpp
#	indra/llrender/llvertexbuffer.cpp
#	indra/llui/llflatlistview.cpp
#	indra/newview/app_settings/settings.xml
#	indra/newview/lldrawpoolground.cpp
#	indra/newview/llinventorybridge.cpp
#	indra/newview/llinventorygallery.cpp
#	indra/newview/llspatialpartition.cpp
#	indra/newview/llviewercontrol.cpp
#	indra/newview/llviewertexture.cpp
#	indra/newview/llvosky.cpp
#	indra/newview/skins/default/xui/en/menu_inventory.xml
master
Andrey Lihatskiy 2023-11-30 13:02:19 +02:00
commit 27dae1d967
203 changed files with 4165 additions and 5091 deletions

View File

@ -240,6 +240,7 @@ Ansariel Hiller
SL-18432
SL-19140
SL-4126
SL-20524
Aralara Rajal
Arare Chantilly
CHUIBUG-191
@ -382,6 +383,7 @@ Chaser Zaks
BUG-225599
BUG-227485
SL-16874
SL-20442
Cherry Cheevers
ChickyBabes Zuzu
Chorazin Allen

View File

@ -42,16 +42,6 @@ const S32 GESTURE_VERSION = 2;
// LLMultiGesture
//---------------------------------------------------------------------------
LLMultiGesture::LLMultiGesture()
: mKey(),
mMask(),
mName(),
mTrigger(),
mReplaceText(),
mSteps(),
mPlaying(FALSE),
mCurrentStep(0),
mDoneCallback(NULL),
mCallbackData(NULL)
{
reset();
}
@ -67,8 +57,11 @@ void LLMultiGesture::reset()
mPlaying = FALSE;
mCurrentStep = 0;
mWaitTimer.reset();
mWaitingTimer = FALSE;
mWaitingAnimations = FALSE;
mWaitingKeyRelease = FALSE;
mWaitingTimer = FALSE;
mTriggeredByKey = FALSE;
mKeyReleased = FALSE;
mWaitingAtEnd = FALSE;
mRequestedAnimIDs.clear();
mPlayingAnimIDs.clear();

View File

@ -59,11 +59,11 @@ protected:
const LLMultiGesture& operator=(const LLMultiGesture& rhs);
public:
KEY mKey;
MASK mMask;
KEY mKey { 0 };
MASK mMask { 0 };
// This name can be empty if the inventory item is not around and
// the gesture manager has not yet set the name
// the gesture manager has not yet set the name
std::string mName;
// String, like "/foo" or "hello" that makes it play
@ -75,25 +75,34 @@ public:
std::vector<LLGestureStep*> mSteps;
// Is the gesture currently playing?
BOOL mPlaying;
BOOL mPlaying { FALSE };
// "instruction pointer" for steps
S32 mCurrentStep;
S32 mCurrentStep { 0 };
// We're waiting for triggered animations to stop playing
BOOL mWaitingAnimations;
BOOL mWaitingAnimations { FALSE };
// We're waiting for key release
BOOL mWaitingKeyRelease { FALSE };
// We're waiting a fixed amount of time
BOOL mWaitingTimer;
BOOL mWaitingTimer { FALSE };
// We're waiting for triggered animations to stop playing
BOOL mTriggeredByKey { FALSE };
// Has the key been released?
BOOL mKeyReleased { FALSE };
// Waiting after the last step played for all animations to complete
BOOL mWaitingAtEnd;
BOOL mWaitingAtEnd { FALSE };
// Timer for waiting
LLFrameTimer mWaitTimer;
void (*mDoneCallback)(LLMultiGesture* gesture, void* data);
void* mCallbackData;
void (*mDoneCallback)(LLMultiGesture* gesture, void* data) { NULL };
void* mCallbackData { NULL };
// Animations that we requested to start
std::set<LLUUID> mRequestedAnimIDs;
@ -210,6 +219,7 @@ public:
const U32 WAIT_FLAG_TIME = 0x01;
const U32 WAIT_FLAG_ALL_ANIM = 0x02;
const U32 WAIT_FLAG_KEY_RELEASE = 0x04;
class LLGestureStepWait : public LLGestureStep
{

View File

@ -600,6 +600,7 @@ std::string mbcsstring_makeASCII(const std::string& wstr)
}
return out_str;
}
std::string utf8str_removeCRLF(const std::string& utf8str)
{
if (0 == utf8str.length())
@ -621,6 +622,43 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
return out;
}
// Search for any emoji symbol, return true if found
bool wstring_has_emoji(const LLWString& wstr)
{
for (const llwchar& wch : wstr)
{
if (LLStringOps::isEmoji(wch))
return true;
}
return false;
}
// Cut emoji symbols if exist
bool wstring_remove_emojis(LLWString& wstr)
{
bool found = false;
for (size_t i = 0; i < wstr.size(); ++i)
{
if (LLStringOps::isEmoji(wstr[i]))
{
wstr.erase(i--, 1);
found = true;
}
}
return found;
}
// Cut emoji symbols if exist
bool utf8str_remove_emojis(std::string& utf8str)
{
LLWString wstr = utf8str_to_wstring(utf8str);
if (!wstring_remove_emojis(wstr))
return false;
utf8str = wstring_to_utf8str(wstr);
return true;
}
#if LL_WINDOWS
unsigned int ll_wstring_default_code_page()
{
@ -833,6 +871,66 @@ std::string LLStringOps::sDayFormat;
std::string LLStringOps::sAM;
std::string LLStringOps::sPM;
// static
bool LLStringOps::isEmoji(llwchar wch)
{
// Most of the following symbols are not actually emoticons, but rather small pictures
// 0x1F000 .. 0x1F02F - mahjong tiles
// https://symbl.cc/en/unicode/table/#mahjong-tiles
// 0x1F030 .. 0x1F09F - domino tiles
// https://symbl.cc/en/unicode/table/#domino-tiles
// 0x1F0A0 .. 0x1F0FF - playing cards
// https://symbl.cc/en/unicode/table/#playing-cards
// 0x1F100 .. 0x1F1FF - enclosed alphanumeric supplement
// https://symbl.cc/en/unicode/table/#enclosed-alphanumeric-supplement
// 0x1F200 .. 0x1F2FF - enclosed ideographic supplement
// https://symbl.cc/en/unicode/table/#enclosed-ideographic-supplement
// 0x1F300 .. 0x1F5FF - miscellaneous symbols and pictographs
// https://symbl.cc/en/unicode/table/#miscellaneous-symbols-and-pictographs
// 0x1F600 .. 0x1F64F - emoticons
// https://symbl.cc/en/unicode/table/#emoticons
// 0x1F650 .. 0x1F67F - ornamental dingbats
// https://symbl.cc/en/unicode/table/#ornamental-dingbats
// 0x1F680 .. 0x1F6FF - transport and map symbols
// https://symbl.cc/en/unicode/table/#transport-and-map-symbols
// 0x1F700 .. 0x1F77F - alchemical symbols
// https://symbl.cc/en/unicode/table/#alchemical-symbols
// 0x1F780 .. 0x1F7FF - geometric shapes extended
// https://symbl.cc/en/unicode/table/#geometric-shapes-extended
// 0x1F800 .. 0x1F8FF - supplemental arrows c
// https://symbl.cc/en/unicode/table/#supplemental-arrows-c
// 0x1F900 .. 0x1F9FF - supplemental symbols and pictographs
// https://symbl.cc/en/unicode/table/#supplemental-symbols-and-pictographs
// 0x1FA00 .. 0x1FA6F - chess symbols
// https://symbl.cc/en/unicode/table/#chess-symbols
// 0x1FA70 .. 0x1FAFF - symbols and pictographs extended a
// https://symbl.cc/en/unicode/table/#symbols-and-pictographs-extended-a
// 0x1FB00 .. 0x1FBFF - symbols for legacy computing
// https://symbl.cc/en/unicode/table/#symbols-for-legacy-computing
// 0x1FC00 .. 0x1FFFF - undefined block 44
// These symbols aren't defined yet
// https://symbl.cc/en/unicode/table/#undefined-block-44
return wch >= 0x1F000 && wch < 0x1FC00;
}
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
{
@ -1235,9 +1333,17 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
}
else
{
#if 0
// EXT-1565 : Zai Lynch, James Linden : 15/Oct/09
// [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT
// "slt" = Second Life Time, which is deprecated.
// If not utc or user local time, fallback to Pacific time
replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST";
#else
// SL-20370 : Steeltoe Linden : 29/Sep/23
// Change "PDT" to "SLT" on menu bar
replacement = "SLT";
#endif
}
return true;
}

View File

@ -189,6 +189,8 @@ public:
static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
static bool isEmoji(llwchar wch);
static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
static S32 collate(const llwchar* a, const llwchar* b);
@ -737,6 +739,11 @@ LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str);
LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr);
LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
LL_COMMON_API bool utf8str_remove_emojis(std::string& utf8str);
#if LL_WINDOWS
/* @name Windows string helpers

View File

@ -118,7 +118,7 @@ const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f;
const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
const LLUUID SCULPT_DEFAULT_TEXTURE("be293869-d0d9-0a69-5989-ad27f1946fd4"); // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
// Texture rotations are sent over the wire as a S16. This is used to scale the actual float
// value to a S16. Don't use 7FFF as it introduces some odd rounding with 180 since it
@ -2073,7 +2073,7 @@ bool LLFlexibleObjectData::fromLLSD(LLSD& sd)
LLSculptParams::LLSculptParams()
{
mType = PARAMS_SCULPT;
mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
mSculptTexture = SCULPT_DEFAULT_TEXTURE;
mSculptType = LL_SCULPT_TYPE_SPHERE;
}
@ -2159,7 +2159,7 @@ void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type)
U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK;
if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX)
{
mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
mSculptTexture = SCULPT_DEFAULT_TEXTURE;
mSculptType = LL_SCULPT_TYPE_SPHERE;
}
else

View File

@ -89,7 +89,7 @@ extern const F32 OBJECT_REV_MIN;
extern const F32 OBJECT_REV_MAX;
extern const F32 OBJECT_REV_INC;
extern const char *SCULPT_DEFAULT_TEXTURE;
extern const LLUUID SCULPT_DEFAULT_TEXTURE;
//============================================================================

View File

@ -94,7 +94,8 @@ void LLGLTexture::setBoostLevel(S32 level)
{
mBoostLevel = level ;
if(mBoostLevel != LLGLTexture::BOOST_NONE
&& mBoostLevel != LLGLTexture::BOOST_ICON)
&& mBoostLevel != LLGLTexture::BOOST_ICON
&& mBoostLevel != LLGLTexture::BOOST_THUMBNAIL)
{
setNoDelete() ;
}

View File

@ -62,6 +62,7 @@ public:
BOOST_SUPER_HIGH , //textures higher than this need to be downloaded at the required resolution without delay.
BOOST_HUD ,
BOOST_ICON ,
BOOST_THUMBNAIL ,
BOOST_UI ,
BOOST_PREVIEW ,
BOOST_MAP ,

View File

@ -936,3 +936,20 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl
expanded_tab_height /= num_expanded;
return expanded_tab_height;
}
void LLAccordionCtrl::collapseAllTabs()
{
if (mAccordionTabs.size() > 0)
{
for (size_t i = 0; i < mAccordionTabs.size(); ++i)
{
LLAccordionCtrlTab *tab = mAccordionTabs[i];
if (tab->getDisplayChildren())
{
tab->setDisplayChildren(false);
}
}
arrange();
}
}

View File

@ -122,6 +122,8 @@ public:
void setComparator(const LLTabComparator* comp) { mTabComparator = comp; }
void sort();
void collapseAllTabs();
/**
* Sets filter substring as a search_term for help text when there are no any visible tabs.
*/

View File

@ -126,12 +126,12 @@ public:
void setSelected(bool is_selected);
bool getCollapsible() {return mCollapsible;};
bool getCollapsible() { return mCollapsible; };
void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
void setCollapsible(bool collapsible) { mCollapsible = collapsible; };
void changeOpenClose(bool is_open);
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;};
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; };
bool canOpenClose() const { return mCanOpenClose; };
virtual BOOL postBuild();
@ -142,8 +142,8 @@ public:
void draw();
void storeOpenCloseState ();
void restoreOpenCloseState ();
void storeOpenCloseState();
void restoreOpenCloseState();
protected:
LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&);

View File

@ -58,10 +58,11 @@ static LLDefaultChildRegistry::Register<LLButton> r("button");
template class LLButton* LLView::getChild<class LLButton>(
const std::string& name, BOOL recurse) const;
// globals loaded from settings.xml
S32 LLBUTTON_H_PAD = 0;
S32 BTN_HEIGHT_SMALL= 0;
S32 BTN_HEIGHT = 0;
// globals
S32 LLBUTTON_H_PAD = 4;
S32 BTN_HEIGHT_SMALL= 23;
S32 BTN_HEIGHT = 23;
S32 BTN_DROP_SHADOW = 2;
LLButton::Params::Params()
: label_selected("label_selected"), // requires is_toggle true
@ -91,8 +92,8 @@ LLButton::Params::Params()
image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
flash_color("flash_color"),
pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
pad_right("pad_right", LLBUTTON_H_PAD),
pad_left("pad_left", LLBUTTON_H_PAD),
pad_bottom("pad_bottom"),
click_callback("click_callback"),
mouse_down_callback("mouse_down_callback"),

View File

@ -43,10 +43,10 @@
//
// PLEASE please use these "constants" when building your own buttons.
// They are loaded from settings.xml at run time.
extern S32 LLBUTTON_H_PAD;
extern S32 BTN_HEIGHT_SMALL;
extern S32 BTN_HEIGHT;
extern S32 BTN_DROP_SHADOW;
//
// Helpful functions

View File

@ -482,8 +482,6 @@ void LLComboBox::onFocusLost()
void LLComboBox::setButtonVisible(BOOL visible)
{
static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
mButton->setVisible(visible);
if (mTextEntry)
{
@ -491,7 +489,7 @@ void LLComboBox::setButtonVisible(BOOL visible)
if (visible)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@ -530,19 +528,18 @@ void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled)
void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
LLRect rect = getLocalRect();
if (mAllowTextEntry)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
S32 shadow_size = drop_shadow_button;
S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
mButton->setTabStop(FALSE);
mButton->setHAlign(LLFontGL::HCENTER);
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
// clear label on button
std::string cur_label = mButton->getLabelSelected();
LLLineEditor::Params params = p.combo_editor;
@ -1081,13 +1078,11 @@ void LLComboBox::onSetHighlight() const
void LLComboBox::imageLoaded()
{
static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0);
if (mAllowTextEntry)
{
LLRect rect = getLocalRect();
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
S32 shadow_size = drop_shadow_button;
S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
if (mButton->getVisible())
@ -1096,7 +1091,7 @@ void LLComboBox::imageLoaded()
if (mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button;
text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * BTN_DROP_SHADOW;
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
}
}

View File

@ -1361,26 +1361,28 @@ void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show)
mForceShowingUnmatchedItems = show;
}
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent)
{
if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString))
{
mFilterSubString = filter_str;
updateNoItemsMessage(mFilterSubString);
filterItems();
filterItems(false, notify_parent);
}
}
void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
{
if (!item) return;
if (!item)
return false;
BOOL visible = TRUE;
// 0 signifies that filter is matched,
// i.e. we don't hide items that don't support 'match_filter' action, separators etc.
if (0 == item->notify(action))
{
mHasMatchedItems = true;
item->setVisible(true);
}
else
{
@ -1388,34 +1390,45 @@ void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
if (!mForceShowingUnmatchedItems)
{
selectItem(item, false);
visible = FALSE;
}
item->setVisible(mForceShowingUnmatchedItems);
}
if (item->getVisible() != visible)
{
item->setVisible(visible);
return true;
}
return false;
}
void LLFlatListViewEx::filterItems()
void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent)
{
typedef std::vector <LLPanel*> item_panel_list_t;
std::string cur_filter = mFilterSubString;
LLStringUtil::toUpper(cur_filter);
LLSD action;
action.with("match_filter", cur_filter);
item_panel_list_t items;
getItems(items);
mHasMatchedItems = false;
item_panel_list_t::iterator iter = items.begin(), iter_end = items.end();
while (iter < iter_end)
bool visibility_changed = false;
pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end();
while (iter != iter_end)
{
LLPanel* pItem = *(iter++);
updateItemVisibility(pItem, action);
LLPanel* pItem = (*(iter++))->first;
visibility_changed |= updateItemVisibility(pItem, action);
}
sort();
notifyParentItemsRectChanged();
if (re_sort)
{
sort();
}
if (visibility_changed && notify_parent)
{
notifyParentItemsRectChanged();
}
}
bool LLFlatListViewEx::hasMatchedItems()

View File

@ -300,6 +300,7 @@ public:
virtual S32 notify(const LLSD& info) ;
virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
@ -375,7 +376,9 @@ protected:
LLRect getLastSelectedItemRect();
void ensureSelectedVisible();
void ensureSelectedVisible();
const pairs_list_t& getItemPairs() { return mItemPairs; }
private:
@ -482,14 +485,14 @@ public:
/**
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str);
void setFilterSubString(const std::string& filter_str, bool notify_parent);
std::string getFilterSubString() { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
*/
void filterItems();
void filterItems(bool re_sort, bool notify_parent);
/**
* Returns true if last call of filterItems() found at least one matching item
@ -513,7 +516,7 @@ protected:
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
void updateItemVisibility(LLPanel* item, const LLSD &action);
bool updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;

View File

@ -1961,10 +1961,9 @@ void LLFloater::drawShadow(LLPanel* panel)
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
S32 bottom = LLPANEL_BORDER_WIDTH;
static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0);
static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
LLColor4 shadow_color = shadow_color_cached;
F32 shadow_offset = (F32)shadow_offset_S32;
F32 shadow_offset = (F32)DROP_SHADOW_FLOATER;
if (!panel->isBackgroundOpaque())
{

View File

@ -61,6 +61,10 @@ const BOOL CLOSE_NO = FALSE;
const BOOL ADJUST_VERTICAL_YES = TRUE;
const BOOL ADJUST_VERTICAL_NO = FALSE;
const F32 CONTEXT_CONE_IN_ALPHA = 0.f;
const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
const F32 CONTEXT_CONE_FADE_TIME = .08f;
namespace LLFloaterEnums
{
enum EOpenPositioning

View File

@ -335,9 +335,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
void LLFolderView::filter( LLFolderViewFilter& filter )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
const S32 TIME_VISIBLE = 10; // in milliseconds
const S32 TIME_INVISIBLE = 1;
filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? TIME_VISIBLE : TIME_INVISIBLE), 1, 100));
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
@ -765,7 +765,7 @@ void LLFolderView::removeSelectedItems()
}
else
{
LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL;
LL_DEBUGS() << "Cannot delete " << item->getName() << LL_ENDL;
return;
}
}

View File

@ -601,15 +601,13 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
{
static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3);
mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight));
if( hasMouseCapture() && isMovable() )
{
LLFolderView* root = getRoot();
if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()
if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& root->getAllowDrag()
&& root->getCurSelectedItem()
&& root->startDrag())

View File

@ -48,8 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
void LLFolderViewModelCommon::filter()
{
static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
getFilter().resetTime(llclamp(max_time(), 1, 100));
const S32 MAX_FILTER_TIME = 10;
getFilter().resetTime(MAX_FILTER_TIME);
mFolderView->getViewModelItem()->filter(getFilter());
}

View File

@ -170,7 +170,7 @@ public:
virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed
virtual BOOL isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed
virtual BOOL removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;

View File

@ -95,6 +95,7 @@ LLLineEditor::Params::Params()
commit_on_focus_lost("commit_on_focus_lost", true),
ignore_tab("ignore_tab", true),
is_password("is_password", false),
allow_emoji("allow_emoji"),
cursor_color("cursor_color"),
use_bg_color("use_bg_color", false),
bg_color("bg_color"),
@ -141,6 +142,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mIgnoreArrowKeys( FALSE ),
mIgnoreTab( p.ignore_tab ),
mDrawAsterixes( p.is_password ),
mAllowEmoji( p.allow_emoji ),
mSpellCheck( p.spellcheck ),
mSpellCheckStart(-1),
mSpellCheckEnd(-1),
@ -413,8 +415,13 @@ void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit
all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
std::string truncated_utf8 = new_text;
if (!mAllowEmoji)
{
// Cut emoji symbols if exist
utf8str_remove_emojis(truncated_utf8);
}
if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes)
{
{
truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes);
}
mText.assign(truncated_utf8);
@ -586,13 +593,21 @@ void LLLineEditor::replaceWithSuggestion(U32 index)
{
if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
{
LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
if (!mAllowEmoji)
{
// Cut emoji symbols if exist
wstring_remove_emojis(suggestion);
}
if (suggestion.empty())
return;
deselect();
// Delete the misspelled word
mText.erase(it->first, it->second - it->first);
// Insert the suggestion in its place
LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
mText.insert(it->first, suggestion);
setCursor(it->first + (S32)suggestion.length());
@ -955,9 +970,11 @@ void LLLineEditor::removeChar()
}
}
void LLLineEditor::addChar(const llwchar uni_char)
{
if (!mAllowEmoji && LLStringOps::isEmoji(uni_char))
return;
llwchar new_c = uni_char;
if (hasSelection())
{
@ -1257,6 +1274,11 @@ void LLLineEditor::pasteHelper(bool is_primary)
if (!paste.empty())
{
if (!mAllowEmoji)
{
wstring_remove_emojis(paste);
}
if (!prevalidateInput(paste))
return;

View File

@ -92,6 +92,7 @@ public:
ignore_tab,
bg_image_always_focused,
is_password,
allow_emoji,
use_bg_color;
// colors
@ -238,6 +239,7 @@ public:
void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(BOOL b) { mIgnoreTab = b; }
void setPassDelete(BOOL b) { mPassDelete = b; }
void setAllowEmoji(BOOL b) { mAllowEmoji = b; }
void setDrawAsterixes(BOOL b);
// get the cursor position of the beginning/end of the prev/next word in the text
@ -396,6 +398,7 @@ protected:
BOOL mShowImageFocused;
bool mAllowEmoji;
bool mUseBgColor;
LLWString mPreeditWString;

View File

@ -66,8 +66,8 @@
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
view_listener_t::listener_map_t view_listener_t::sListeners;
S32 MENU_BAR_HEIGHT = 0;
S32 MENU_BAR_WIDTH = 0;
S32 MENU_BAR_HEIGHT = 18;
S32 MENU_BAR_WIDTH = 410;
///============================================================================
/// Local function declarations, constants, enums, and typedefs
@ -3229,10 +3229,9 @@ void LLMenuGL::draw( void )
}
if (mDropShadowed && !mTornOff)
{
static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0);
static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
color_drop_shadow, drop_shadow_floater );
color_drop_shadow, DROP_SHADOW_FLOATER);
}
if( mBgVisible )

View File

@ -284,10 +284,9 @@ BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask )
void LLModalDialog::draw()
{
static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0);
gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
shadow_color, shadow_lines);
shadow_color, DROP_SHADOW_FLOATER);
LLFloater::draw();

View File

@ -88,6 +88,7 @@ LLNotificationForm::FormInput::FormInput()
: type("type"),
text("text"),
max_length_chars("max_length_chars"),
allow_emoji("allow_emoji"),
width("width", 0),
value("value")
{}

View File

@ -201,6 +201,7 @@ public:
Mandatory<std::string> type;
Optional<S32> width;
Optional<S32> max_length_chars;
Optional<bool> allow_emoji;
Optional<std::string> text;
Optional<std::string> value;

View File

@ -225,7 +225,8 @@ LLTabContainer::Params::Params()
tabs_flashing_color("tabs_flashing_color"),
tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
use_ellipses("use_ellipses"),
font_halign("halign")
font_halign("halign"),
use_tab_offset("use_tab_offset", false)
{}
LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
@ -264,7 +265,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mTabIconCtrlPad(p.tab_icon_ctrl_pad),
mEnableTabsFlashing(p.enable_tabs_flashing),
mTabsFlashingColor(p.tabs_flashing_color),
mUseTabEllipses(p.use_ellipses)
mUseTabEllipses(p.use_ellipses),
mUseTabOffset(p.use_tab_offset)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@ -1023,11 +1025,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
}
else
{
tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3,
tab_panel_top,
getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2,
tab_panel_bottom );
}
S32 left_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 3 : LLPANEL_BORDER_WIDTH;
S32 right_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 2 : LLPANEL_BORDER_WIDTH;
tab_panel_rect = LLRect(left_offset, tab_panel_top, getRect().getWidth() - right_offset, tab_panel_bottom);
}
child->setFollowsAll();
child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
@ -1516,25 +1517,23 @@ BOOL LLTabContainer::selectTab(S32 which)
LLTabTuple* selected_tuple = getTab(which);
if (!selected_tuple)
{
return FALSE;
}
LLSD cbdata;
if (selected_tuple->mTabPanel)
cbdata = selected_tuple->mTabPanel->getName();
BOOL res = FALSE;
if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
BOOL result = FALSE;
if (!mValidateSignal || (*mValidateSignal)(this, cbdata))
{
res = setTab(which);
if (res && mCommitSignal)
result = setTab(which);
if (result && mCommitSignal)
{
(*mCommitSignal)(this, cbdata);
}
}
return res;
return result;
}
// private

View File

@ -121,6 +121,8 @@ public:
*/
Optional<S32> tab_icon_ctrl_pad;
Optional<bool> use_tab_offset;
Params();
};
@ -321,6 +323,8 @@ private:
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
LLFrameTimer mMouseDownTimer;
bool mUseTabOffset;
};
#endif // LL_TABCONTAINER_H

View File

@ -1134,8 +1134,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3);
if (mouse_distance_squared > drag_threshold * drag_threshold
if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& hasMouseCapture() &&
mStartDragItemCallback && mHandleDragItemCallback)
{

View File

@ -44,8 +44,8 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS);
if (!success)
{
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://secondlife.com/support/downloads/ and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL;
//gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << ". Please reinstall viewer from https://secondlife.com/support/downloads/ and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL;
return false;
}

View File

@ -53,7 +53,7 @@ class LLWindow;
class LLView;
class LLHelp;
const S32 DRAG_N_DROP_DISTANCE_THRESHOLD = 3;
// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim)
enum EDragAndDropType
{

View File

@ -41,6 +41,7 @@
const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE;
const S32 DROP_SHADOW_FLOATER = 5;
class LLUICtrl
: public LLView, public boost::signals2::trackable

View File

@ -199,7 +199,13 @@ public:
// windows only DirectInput8 for joysticks
virtual void* getDirectInput8() { return NULL; };
virtual bool getInputDevices(U32 device_type_filter, void * devices_callback, void* userdata) { return false; };
virtual bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata)
{
return false;
};
virtual S32 getRefreshRate() { return mRefreshRate; }
protected:

View File

@ -27,6 +27,7 @@
#include <AppKit/AppKit.h>
#include <Cocoa/Cocoa.h>
#include <errno.h>
#include "llopenglview-objc.h"
#include "llwindowmacosx-objc.h"
#include "llappdelegate-objc.h"

View File

@ -43,6 +43,13 @@
#include <CoreServices/CoreServices.h>
#include <CoreGraphics/CGDisplayConfiguration.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/usb/IOUSBLib.h>
extern BOOL gDebugWindowProc;
BOOL gHiDPISupport = TRUE;
@ -212,13 +219,16 @@ bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask)
bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character)
{
if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y'))
//if (mask!=MASK_NONE)
{
key = gKeyboard->inverseTranslateKey('Y');
}
else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z'))
{
key = gKeyboard->inverseTranslateKey('Z');
if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y'))
{
key = gKeyboard->inverseTranslateKey('Y');
}
else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z'))
{
key = gKeyboard->inverseTranslateKey('Z');
}
}
mRawKeyEvent = event;
@ -1841,6 +1851,488 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
}
}
// String should match ndof, so string mapping code was copied as is
static char mapChar( char c )
{
unsigned char uc = ( unsigned char ) c;
switch( uc )
{
case '/': return '-'; // use dash instead of slash
case 0x7F: return ' ';
case 0x80: return 'A';
case 0x81: return 'A';
case 0x82: return 'C';
case 0x83: return 'E';
case 0x84: return 'N';
case 0x85: return 'O';
case 0x86: return 'U';
case 0x87: return 'a';
case 0x88: return 'a';
case 0x89: return 'a';
case 0x8A: return 'a';
case 0x8B: return 'a';
case 0x8C: return 'a';
case 0x8D: return 'c';
case 0x8E: return 'e';
case 0x8F: return 'e';
case 0x90: return ' ';
case 0x91: return ' '; // ? '
case 0x92: return ' '; // ? '
case 0x93: return ' '; // ? "
case 0x94: return ' '; // ? "
case 0x95: return ' ';
case 0x96: return ' ';
case 0x97: return ' ';
case 0x98: return ' ';
case 0x99: return ' ';
case 0x9A: return ' ';
case 0x9B: return 0x27;
case 0x9C: return 0x22;
case 0x9D: return ' ';
case 0x9E: return ' ';
case 0x9F: return ' ';
case 0xA0: return ' ';
case 0xA1: return ' ';
case 0xA2: return ' ';
case 0xA3: return ' ';
case 0xA4: return ' ';
case 0xA5: return ' ';
case 0xA6: return ' ';
case 0xA7: return ' ';
case 0xA8: return ' ';
case 0xA9: return ' ';
case 0xAA: return ' ';
case 0xAB: return ' ';
case 0xAC: return ' ';
case 0xAD: return ' ';
case 0xAE: return ' ';
case 0xAF: return ' ';
case 0xB0: return ' ';
case 0xB1: return ' ';
case 0xB2: return ' ';
case 0xB3: return ' ';
case 0xB4: return ' ';
case 0xB5: return ' ';
case 0xB6: return ' ';
case 0xB7: return ' ';
case 0xB8: return ' ';
case 0xB9: return ' ';
case 0xBA: return ' ';
case 0xBB: return ' ';
case 0xBC: return ' ';
case 0xBD: return ' ';
case 0xBE: return ' ';
case 0xBF: return ' ';
case 0xC0: return ' ';
case 0xC1: return ' ';
case 0xC2: return ' ';
case 0xC3: return ' ';
case 0xC4: return ' ';
case 0xC5: return ' ';
case 0xC6: return ' ';
case 0xC7: return ' ';
case 0xC8: return ' ';
case 0xC9: return ' ';
case 0xCA: return ' ';
case 0xCB: return 'A';
case 0xCC: return 'A';
case 0xCD: return 'O';
case 0xCE: return ' ';
case 0xCF: return ' ';
case 0xD0: return '-';
case 0xD1: return '-';
case 0xD2: return 0x22;
case 0xD3: return 0x22;
case 0xD4: return 0x27;
case 0xD5: return 0x27;
case 0xD6: return '-'; // use dash instead of slash
case 0xD7: return ' ';
case 0xD8: return 'y';
case 0xD9: return 'Y';
case 0xDA: return '-'; // use dash instead of slash
case 0xDB: return ' ';
case 0xDC: return '<';
case 0xDD: return '>';
case 0xDE: return ' ';
case 0xDF: return ' ';
case 0xE0: return ' ';
case 0xE1: return ' ';
case 0xE2: return ',';
case 0xE3: return ',';
case 0xE4: return ' ';
case 0xE5: return 'A';
case 0xE6: return 'E';
case 0xE7: return 'A';
case 0xE8: return 'E';
case 0xE9: return 'E';
case 0xEA: return 'I';
case 0xEB: return 'I';
case 0xEC: return 'I';
case 0xED: return 'I';
case 0xEE: return 'O';
case 0xEF: return 'O';
case 0xF0: return ' ';
case 0xF1: return 'O';
case 0xF2: return 'U';
case 0xF3: return 'U';
case 0xF4: return 'U';
case 0xF5: return '|';
case 0xF6: return ' ';
case 0xF7: return ' ';
case 0xF8: return ' ';
case 0xF9: return ' ';
case 0xFA: return '.';
case 0xFB: return ' ';
case 0xFC: return ' ';
case 0xFD: return 0x22;
case 0xFE: return ' ';
case 0xFF: return ' ';
}
return c;
}
// String should match ndof for manufacturer based search to work
static void sanitizeString( char* inCStr )
{
char* charIt = inCStr;
while ( *charIt )
{
*charIt = mapChar( *charIt );
charIt++;
}
}
struct HidDevice
{
long mAxis;
long mLocalID;
char mProduct[256];
char mManufacturer[256];
long mUsage;
long mUsagePage;
};
static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep )
{
CFMutableDictionaryRef io_properties = nil;
io_registry_entry_t entry1;
io_registry_entry_t entry2;
kern_return_t rc;
// Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also
// get dictionary for usb properties: step up two levels and get CF dictionary for USB properties
// try to get parent1
rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 );
if ( KERN_SUCCESS == rc )
{
rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 );
IOObjectRelease( entry1 );
if ( KERN_SUCCESS == rc )
{
rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions );
// either way, release parent2
IOObjectRelease( entry2 );
}
}
if ( KERN_SUCCESS == rc )
{
// IORegistryEntryCreateCFProperties() succeeded
if ( io_properties != nil )
{
CFTypeRef dict_element = 0;
// get device info
// try hid dictionary first, if fail then go to usb dictionary
dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) );
if ( !dict_element )
{
dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) );
}
if ( dict_element )
{
bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8);
sanitizeString(devicep->mProduct);
if ( !res )
{
LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL;
}
}
dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) );
if ( !dict_element )
{
dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) );
}
if ( dict_element )
{
bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 );
sanitizeString(devicep->mManufacturer);
if ( !res )
{
LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL;
}
}
dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) );
if ( !dict_element )
{
dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) );
}
if ( dict_element )
{
bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID );
if ( !res )
{
LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL;
}
}
dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) );
if ( dict_element )
{
bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage );
if ( !res )
{
LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL;
}
dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) );
if ( dict_element )
{
if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) )
{
LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL;
}
}
}
//Add axis, because ndof lib checks sutability by axises as well as other elements
devicep->mAxis = 0;
CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) );
if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) )
{
long count = CFArrayGetCount( (CFArrayRef) hid_elements );
for (int i = 0; i < count; ++i)
{
CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i);
if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( ))
{
long type = 0, usage_page = 0, usage = 0;
CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) );
if ( ref_value )
{
CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type );
}
ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) );
if ( ref_value )
{
CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page );
}
ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) );
if ( ref_value )
{
CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage );
}
if ( type != 0
&& type != kIOHIDElementTypeCollection
&& usage_page == kHIDPage_GenericDesktop)
{
switch( usage )
{
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
devicep->mAxis++;
break;
default:
break;
}
}
}
}
}
CFRelease(io_properties);
}
else
{
LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL;
}
}
}
HidDevice populate_device( io_object_t io_obj )
{
void* interfacep = nullptr;
HidDevice device;
memset( &device, 0, sizeof( HidDevice ) );
CFMutableDictionaryRef device_dic = 0;
kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions );
if ( KERN_SUCCESS == result
&& device_dic )
{
IOReturn io_result = kIOReturnSuccess;
HRESULT query_result = S_OK;
SInt32 the_score = 0;
IOCFPlugInInterface **the_interface = NULL;
io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID, &the_interface, &the_score );
if ( io_result == kIOReturnSuccess )
{
query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) );
if ( query_result != S_OK )
{
LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL;
}
IODestroyPlugInInterface( the_interface );
}
else
{
LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL;
}
if ( interfacep )
{
result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 );
if ( result != kIOReturnSuccess)
{
LL_WARNS("Joystick") << "open failed" << LL_ENDL;
}
}
// extract needed fields
populate_device_info( io_obj, device_dic, &device );
// Release interface
if ( interfacep )
{
( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep );
( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep );
interfacep = NULL;
}
CFRelease( device_dic );
}
else
{
LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL;
}
return device;
}
static void get_devices(std::list<HidDevice> &list_of_devices,
io_iterator_t inIODeviceIterator)
{
IOReturn result = kIOReturnSuccess; // assume success( optimist! )
io_object_t io_obj = 0;
while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) )
{
HidDevice device = populate_device( io_obj );
if (debugLoggingEnabled("Joystick"))
{
list_of_devices.push_back(device);
LL_DEBUGS("Joystick") << "Device axises: " << (S32)device.mAxis
<< "Device HIDUsepage: " << (S32)device.mUsagePage
<< "Device HIDUsage: " << (S32)device.mUsage
<< LL_ENDL;
}
else
{
// Should match ndof
if (device.mAxis >= 3
|| (device.mUsagePage == kHIDPage_GenericDesktop
&& (device.mUsage == kHIDUsage_GD_MultiAxisController
|| device.mUsage == kHIDUsage_GD_GamePad
|| device.mUsage == kHIDUsage_GD_Joystick))
|| (device.mUsagePage == kHIDPage_Game
&& device.mUsage == kHIDUsage_Game_3DGameController)
|| strstr(device.mManufacturer, "3Dconnexion"))
{
list_of_devices.push_back(device);
}
}
// release the device object, it is no longer needed
result = IOObjectRelease( io_obj );
if ( KERN_SUCCESS != result )
{
LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL;
}
}
}
bool LLWindowMacOSX::getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata)
{
bool return_value = false;
CFMutableDictionaryRef device_dict_ref;
IOReturn result = kIOReturnSuccess; // assume success( optimist! )
// Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error.
// A dictionary to match devices to?
device_dict_ref = IOServiceMatching( kIOHIDDeviceKey );
// BUG FIX! one reference is consumed by IOServiceGetMatchingServices
CFRetain( device_dict_ref );
io_iterator_t io_iter = 0;
// create an IO object iterator
result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter );
if ( kIOReturnSuccess != result )
{
LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL;
}
if ( io_iter )
{
// add all existing devices
std::list<HidDevice> device_list;
get_devices(device_list, io_iter);
std::list<HidDevice>::iterator iter;
for (iter = device_list.begin(); iter != device_list.end(); ++iter)
{
std::string label(iter->mProduct);
LLSD data;
data["manufacturer"] = std::string(iter->mManufacturer);
data["product"] = label;
if (osx_callback(label, data, userdata))
{
break; //found device
}
}
return_value = true;
}
CFRelease( device_dict_ref );
return return_value;
}
LLSD LLWindowMacOSX::getNativeKeyData()
{
LLSD result = LLSD::emptyMap();

View File

@ -115,6 +115,11 @@ public:
void interruptLanguageTextInput() override;
void spawnWebBrowser(const std::string& escaped_url, bool async) override;
F32 getSystemUISize() override;
bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata) override;
static std::vector<std::string> getDisplaysResolutionList();

View File

@ -4490,7 +4490,10 @@ void* LLWindowWin32::getDirectInput8()
return &gDirectInput8;
}
bool LLWindowWin32::getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata)
bool LLWindowWin32::getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void * di8_devices_callback,
void* userdata)
{
if (gDirectInput8 != NULL)
{

View File

@ -131,7 +131,10 @@ public:
static void setDPIAwareness();
/*virtual*/ void* getDirectInput8();
/*virtual*/ bool getInputDevices(U32 device_type_filter, void * di8_devices_callback, void* userdata);
/*virtual*/ bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata);
U32 getRawWParam() { return mRawWParam; }

View File

@ -1497,8 +1497,6 @@ DECL_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
LLSD test_llsd = LLSD()["testing1"] = LLSD()["testing2"];
DECL_LLCC(LLSD, test_llsd);
static LLCachedControl<std::string> test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment");
void test_cached_control()
{
#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL
@ -1515,8 +1513,6 @@ void test_cached_control()
TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f));
TEST_LLCC(LLColor4U, LLColor4U(255, 200, 100, 255));
//There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd);
if((std::string)test_BrowserHomePage != "http://www.secondlife.com") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL;
}
#endif // TEST_CACHED_CONTROL

View File

@ -837,7 +837,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
if (!LLXMLNode::parseFile(filename, root, NULL))
{
LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL;
LL_WARNS() << "Problem reading UI description file: " << filename << " " << errno << LL_ENDL;
return false;
}

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

View File

@ -1,16 +1,5 @@
<llsd>
<map>
<key>AppearanceCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>AvatarSitRotation</key>
<map>
<key>Comment</key>
@ -90,17 +79,6 @@
<key>Value</key>
<real>0.90322577953338623</real>
</map>
<key>EditCameraMovement</key>
<map>
<key>Comment</key>
<string>When entering build mode, camera moves up above avatar</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FocusOffsetRearView</key>
<map>
<key>Comment</key>

File diff suppressed because it is too large Load Diff

View File

@ -397,8 +397,18 @@ CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \
# Other shortcuts
SetOutPath "$INSTDIR"
CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
Push $0
${GetParameters} $COMMANDLINE
${GetOptionsS} $COMMANDLINE "/marker" $0
# Returns error if option does not exist
IfErrors 0 DESKTOP_SHORTCUT_DONE
# "/marker" is set by updater, do not recreate desktop shortcut
CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
DESKTOP_SHORTCUT_DONE:
Pop $0
CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \
"$INSTDIR\$VIEWER_EXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$VIEWER_EXE"
CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \

View File

@ -1925,7 +1925,8 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
}
else
{
target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
LLCachedControl<F32> dynamic_camera_strength(gSavedSettings, "DynamicCameraStrength");
target_lag = vel * dynamic_camera_strength / 30.f;
}
mCameraLag = lerp(mCameraLag, target_lag, lag_interp);

View File

@ -49,10 +49,10 @@ public:
void sendAgentPicksRequest()
{
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(gAgent.getID());
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(gAgent.getID());
}
typedef boost::function<void(LLAvatarPicks*)> server_respond_callback_t;
typedef boost::function<void(LLAvatarData*)> server_respond_callback_t;
void setServerRespondCallback(const server_respond_callback_t& cb)
{
@ -61,10 +61,10 @@ public:
virtual void processProperties(void* data, EAvatarProcessorType type)
{
if(APT_PICKS == type)
if(APT_PROPERTIES == type)
{
LLAvatarPicks* picks = static_cast<LLAvatarPicks*>(data);
if(picks && gAgent.getID() == picks->target_id)
LLAvatarData* picks = static_cast<LLAvatarData*>(data);
if(picks && gAgent.getID() == picks->avatar_id)
{
if(mServerRespondCallback)
{
@ -115,7 +115,7 @@ bool LLAgentPicksInfo::isPickLimitReached()
return getNumberOfPicks() >= getMaxNumberOfPicks();
}
void LLAgentPicksInfo::onServerRespond(LLAvatarPicks* picks)
void LLAgentPicksInfo::onServerRespond(LLAvatarData* picks)
{
if(!picks)
{

View File

@ -29,7 +29,7 @@
#include "llsingleton.h"
struct LLAvatarPicks;
struct LLAvatarData;
/**
* Class that provides information about Agent Picks
@ -74,7 +74,7 @@ public:
void decrementNumberOfPicks() { --mNumberOfPicks; }
void onServerRespond(LLAvatarPicks* picks);
void onServerRespond(LLAvatarData* picks);
private:

View File

@ -1399,7 +1399,7 @@ const std::string LLAppearanceMgr::sExpectedTextureName = "OutfitPreview";
const LLUUID LLAppearanceMgr::getCOF() const
{
return gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
return mCOFID;
}
S32 LLAppearanceMgr::getCOFVersion() const
@ -1415,6 +1415,11 @@ S32 LLAppearanceMgr::getCOFVersion() const
}
}
void LLAppearanceMgr::initCOFID()
{
mCOFID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
}
const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink()
{
const LLUUID& current_outfit_cat = getCOF();
@ -3749,6 +3754,14 @@ LLSD LLAppearanceMgr::dumpCOF() const
return result;
}
void LLAppearanceMgr::cleanup()
{
mIsInUpdateAppearanceFromCOF = false;
mOutstandingAppearanceBakeRequest = false;
mRerequestAppearanceBake = false;
mCOFID.setNull();
}
// static
void LLAppearanceMgr::onIdle(void *)
{
@ -4117,7 +4130,7 @@ void LLAppearanceMgr::wearBaseOutfit()
updateCOF(base_outfit_id);
}
void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, nullary_func_t post_update_func)
{
LL_DEBUGS("UIUsage") << "removeItemsFromAvatar" << LL_ENDL;
LLUIUsage::instance().logCommand("Avatar.RemoveItem");
@ -4127,7 +4140,7 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL;
return;
}
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(true, true, post_update_func);
for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
{
const LLUUID& id_to_remove = *it;
@ -4146,11 +4159,11 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
}
}
void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove, nullary_func_t post_update_func)
{
uuid_vec_t ids_to_remove;
ids_to_remove.push_back(id_to_remove);
removeItemsFromAvatar(ids_to_remove);
removeItemsFromAvatar(ids_to_remove, post_update_func);
}
@ -4387,20 +4400,45 @@ BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const
return FALSE;
}
BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
bool LLAppearanceMgr::getIsInCOF(const LLInventoryObject* obj) const
{
if (!getIsInCOF(obj_id)) return FALSE;
const LLUUID& cof = getCOF();
if (obj->getUUID() == cof)
return true;
if (obj && obj->getParentUUID() == cof)
return true;
return false;
}
bool LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const
{
if (!getIsInCOF(obj_id)) return false;
// If a non-link somehow ended up in COF, allow deletion.
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj && !obj->getIsLinkType())
{
return FALSE;
return false;
}
// For now, don't allow direct deletion from the COF. Instead, force users
// to choose "Detach" or "Take Off".
return TRUE;
return true;
}
bool LLAppearanceMgr::getIsProtectedCOFItem(const LLInventoryObject* obj) const
{
if (!getIsInCOF(obj)) return false;
// If a non-link somehow ended up in COF, allow deletion.
if (obj && !obj->getIsLinkType())
{
return false;
}
// For now, don't allow direct deletion from the COF. Instead, force users
// to choose "Detach" or "Take Off".
return true;
}
class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver

View File

@ -111,9 +111,11 @@ public:
// Find the Current Outfit folder.
const LLUUID getCOF() const;
S32 getCOFVersion() const;
void initCOFID();
// Debugging - get truncated LLSD summary of COF contents.
LLSD dumpCOF() const;
void cleanup();
// Finds the folder link to the currently worn outfit
const LLViewerInventoryItem *getBaseOutfitLink();
@ -195,8 +197,8 @@ public:
bool updateBaseOutfit();
//Remove clothing or detach an object from the agent (a bodypart cannot be removed)
void removeItemsFromAvatar(const uuid_vec_t& item_ids);
void removeItemFromAvatar(const LLUUID& item_id);
void removeItemsFromAvatar(const uuid_vec_t& item_ids, nullary_func_t post_update_func = no_op);
void removeItemFromAvatar(const LLUUID& item_id, nullary_func_t post_update_func = no_op);
void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel);
@ -276,6 +278,7 @@ private:
attachments_changed_signal_t mAttachmentsChangeSignal;
LLUUID mCOFImageID;
LLUUID mCOFID;
std::unique_ptr<LLOutfitUnLockTimer> mUnlockOutfitTimer;
@ -290,8 +293,10 @@ private:
public:
// Is this in the COF?
BOOL getIsInCOF(const LLUUID& obj_id) const;
// Is this in the COF and can the user delete it from the COF?
BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const;
bool getIsInCOF(const LLInventoryObject* obj) const;
// Is this in the COF and can the user delete it from the COF?
bool getIsProtectedCOFItem(const LLUUID& obj_id) const;
bool getIsProtectedCOFItem(const LLInventoryObject* obj) const;
// Outfits will prioritize textures with such name to use for preview in gallery
static const std::string sExpectedTextureName;

View File

@ -526,13 +526,6 @@ bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
// or for things that are performance critical. JC
static void settings_to_globals()
{
LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
#if LL_DARWIN
@ -4290,7 +4283,8 @@ bool LLAppViewer::initCache()
LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion());
const U32 CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS = 128;
LLVOCache::getInstance()->initCache(LL_PATH_CACHE, CACHE_NUMBER_OF_REGIONS_FOR_OBJECTS, getObjectCacheVersion());
return true;
}

View File

@ -245,7 +245,7 @@ void LLAvatarIconCtrl::setValue(const LLSD& value)
// messages. People API already hits the user table.
LLIconCtrl::setValue(mDefaultIconName, LLViewerFetchedTexture::BOOST_UI);
app->addObserver(mAvatarId, this);
app->sendAvatarPropertiesRequest(mAvatarId);
app->sendAvatarLegacyPropertiesRequest(mAvatarId);
}
}
}
@ -294,9 +294,9 @@ bool LLAvatarIconCtrl::updateFromCache()
//virtual
void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type)
{
if (APT_PROPERTIES == type)
if (APT_PROPERTIES_LEGACY == type)
{
LLAvatarData* avatar_data = static_cast<LLAvatarData*>(data);
LLAvatarLegacyData* avatar_data = static_cast<LLAvatarLegacyData*>(data);
if (avatar_data)
{
if (avatar_data->avatar_id != mAvatarId)

View File

@ -52,24 +52,23 @@ LLAvatarPropertiesProcessor::~LLAvatarPropertiesProcessor()
void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer)
{
if (!observer)
return;
// Check if that observer is already in mObservers for that avatar_id
observer_multimap_t::iterator it;
using pair = std::pair<LLUUID, LLAvatarPropertiesObserver*>;
observer_multimap_t::iterator begin = mObservers.begin();
observer_multimap_t::iterator end = mObservers.end();
observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p)
{
return p.first == avatar_id && p.second == observer;
});
// IAN BUG this should update the observer's UUID if this is a dupe - sent to PE
it = mObservers.find(avatar_id);
while (it != mObservers.end())
if (it == end)
{
if (it->second == observer)
{
return;
}
else
{
++it;
}
mObservers.emplace(avatar_id, observer);
}
mObservers.insert(std::pair<LLUUID, LLAvatarPropertiesObserver*>(avatar_id, observer));
}
void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer)
@ -79,19 +78,18 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat
return;
}
observer_multimap_t::iterator it;
it = mObservers.find(avatar_id);
while (it != mObservers.end())
// Check if that observer is in mObservers for that avatar_id
using pair = std::pair<LLUUID, LLAvatarPropertiesObserver*>;
observer_multimap_t::iterator begin = mObservers.begin();
observer_multimap_t::iterator end = mObservers.end();
observer_multimap_t::iterator it = std::find_if(begin, end, [&](const pair& p)
{
return p.first == avatar_id && p.second == observer;
});
if (it != end)
{
if (it->second == observer)
{
mObservers.erase(it);
break;
}
else
{
++it;
}
mObservers.erase(it);
}
}
@ -116,32 +114,30 @@ void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarPr
return;
}
std::string cap;
switch (type)
// Try to send HTTP request if cap_url is available
if (type == APT_PROPERTIES)
{
case APT_PROPERTIES:
// indicate we're going to make a request
sendAvatarPropertiesRequestMessage(avatar_id);
// can use getRegionCapability("AgentProfile"), but it is heavy
// initAgentProfileCapRequest(avatar_id, cap);
break;
case APT_PICKS:
case APT_GROUPS:
case APT_NOTES:
if (cap.empty())
std::string cap_url = gAgent.getRegionCapability("AgentProfile");
if (!cap_url.empty())
{
// indicate we're going to make a request
sendGenericRequest(avatar_id, type, method);
initAgentProfileCapRequest(avatar_id, cap_url, type);
}
else
{
initAgentProfileCapRequest(avatar_id, cap);
// Don't sent UDP request for APT_PROPERTIES
LL_WARNS() << "No cap_url for APT_PROPERTIES, request for " << avatar_id << " is not sent" << LL_ENDL;
}
break;
default:
return;
}
// Send UDP request
if (type == APT_PROPERTIES_LEGACY)
{
sendAvatarPropertiesRequestMessage(avatar_id);
}
else
{
sendGenericRequest(avatar_id, type, method);
break;
}
}
@ -150,33 +146,29 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA
// indicate we're going to make a request
addPendingRequest(avatar_id, type);
std::vector<std::string> strings;
strings.push_back(avatar_id.asString());
std::vector<std::string> strings{ avatar_id.asString() };
send_generic_message(method, strings);
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id)
{
addPendingRequest(avatar_id, APT_PROPERTIES);
addPendingRequest(avatar_id, APT_PROPERTIES_LEGACY);
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
msg->addUUIDFast(_PREHASH_AvatarID, avatar_id);
gAgent.sendReliableMessage();
}
void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url)
void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type)
{
addPendingRequest(avatar_id, APT_PROPERTIES);
addPendingRequest(avatar_id, APT_PICKS);
addPendingRequest(avatar_id, APT_GROUPS);
addPendingRequest(avatar_id, APT_NOTES);
addPendingRequest(avatar_id, type);
LLCoros::instance().launch("requestAgentUserInfoCoro",
boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id));
[cap_url, avatar_id, type]() { requestAvatarPropertiesCoro(cap_url, avatar_id, type); });
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
@ -184,19 +176,9 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avat
sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest");
}
void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id)
void LLAvatarPropertiesProcessor::sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id)
{
sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
}
void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id)
{
sendGenericRequest(avatar_id, APT_NOTES, "avatarnotesrequest");
}
void LLAvatarPropertiesProcessor::sendAvatarGroupsRequest(const LLUUID& avatar_id)
{
sendGenericRequest(avatar_id, APT_GROUPS, "avatargroupsrequest");
sendRequest(avatar_id, APT_PROPERTIES_LEGACY, "AvatarPropertiesRequest");
}
void LLAvatarPropertiesProcessor::sendAvatarTexturesRequest(const LLUUID& avatar_id)
@ -211,42 +193,6 @@ void LLAvatarPropertiesProcessor::sendAvatarClassifiedsRequest(const LLUUID& ava
sendGenericRequest(avatar_id, APT_CLASSIFIEDS, "avatarclassifiedsrequest");
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props)
{
if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null))
{
LL_WARNS() << "Sending avatarinfo update DENIED - invalid agent" << LL_ENDL;
return;
}
LL_WARNS() << "Sending avatarinfo update. This trims profile descriptions!!!" << LL_ENDL;
// This value is required by sendAvatarPropertiesUpdate method.
//A profile should never be mature. (From the original code)
BOOL mature = FALSE;
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast (_PREHASH_AvatarPropertiesUpdate);
msg->nextBlockFast (_PREHASH_AgentData);
msg->addUUIDFast (_PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast (_PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast (_PREHASH_PropertiesData);
msg->addUUIDFast (_PREHASH_ImageID, avatar_props->image_id);
msg->addUUIDFast (_PREHASH_FLImageID, avatar_props->fl_image_id);
msg->addStringFast (_PREHASH_AboutText, avatar_props->about_text);
msg->addStringFast (_PREHASH_FLAboutText, avatar_props->fl_about_text);
msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish);
msg->addBOOL(_PREHASH_MaturePublish, mature);
msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url);
gAgent.sendReliableMessage();
}
//static
std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_data)
{
@ -271,19 +217,21 @@ std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_
std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data)
{
// Special accounts like M Linden don't have payment info revealed.
if (!avatar_data->caption_text.empty()) return "";
if (!avatar_data->caption_text.empty())
return "";
// Linden employees don't have payment info revealed
const S32 LINDEN_EMPLOYEE_INDEX = 3;
if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return "";
constexpr S32 LINDEN_EMPLOYEE_INDEX = 3;
if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
return "";
BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED);
BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED);
bool transacted = (avatar_data->flags & AVATAR_TRANSACTED);
bool identified = (avatar_data->flags & AVATAR_IDENTIFIED);
// Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations
//BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED);
const char* payment_text;
if(transacted)
if (transacted)
{
payment_text = "PaymentInfoUsed";
}
@ -302,18 +250,22 @@ std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_
bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avatar_data)
{
// Special accounts like M Linden don't have payment info revealed.
if (!avatar_data->caption_text.empty()) return true;
if (!avatar_data->caption_text.empty())
return true;
// Linden employees don't have payment info revealed
const S32 LINDEN_EMPLOYEE_INDEX = 3;
if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return true;
constexpr S32 LINDEN_EMPLOYEE_INDEX = 3;
if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX)
return true;
return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED));
}
// static
void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id)
void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type)
{
LLAvatarPropertiesProcessor& inst = instance();
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy));
@ -323,104 +275,104 @@ void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_ur
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setFollowRedirects(true);
std::string finalUrl = cap_url + "/" + agent_id.asString();
std::string finalUrl = cap_url + "/" + avatar_id.asString();
LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
// Response is being processed, no longer pending is required
inst.removePendingRequest(avatar_id, type);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status
|| !result.has("id")
|| agent_id != result["id"].asUUID())
|| avatar_id != result["id"].asUUID())
{
LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
LLAvatarPropertiesProcessor* self = getInstance();
self->removePendingRequest(agent_id, APT_PROPERTIES);
self->removePendingRequest(agent_id, APT_PICKS);
self->removePendingRequest(agent_id, APT_GROUPS);
self->removePendingRequest(agent_id, APT_NOTES);
LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << avatar_id
<< (!status ? " (no HTTP status)" : !result.has("id") ? " (no result.id)" :
std::string(" (result.id=") + result["id"].asUUID().asString() + ")")
<< LL_ENDL;
return;
}
// Avatar Data
LLAvatarData avatar_data;
std::string birth_date;
avatar_data.agent_id = agent_id;
avatar_data.avatar_id = agent_id;
avatar_data.agent_id = gAgentID;
avatar_data.avatar_id = avatar_id;
avatar_data.image_id = result["sl_image_id"].asUUID();
avatar_data.fl_image_id = result["fl_image_id"].asUUID();
avatar_data.partner_id = result["partner_id"].asUUID();
avatar_data.about_text = result["sl_about_text"].asString();
avatar_data.fl_about_text = result["fl_about_text"].asString();
avatar_data.born_on = result["member_since"].asDate();
avatar_data.profile_url = getProfileURL(agent_id.asString());
// TODO: SL-20163 Remove the "has" check when SRV-684 is done
// and the field "hide_age" is included to the http response
inst.mIsHideAgeSupportedByServer = result.has("hide_age");
avatar_data.hide_age = inst.isHideAgeSupportedByServer() && result["hide_age"].asBoolean();
avatar_data.profile_url = getProfileURL(avatar_id.asString());
avatar_data.customer_type = result["customer_type"].asString();
avatar_data.notes = result["notes"].asString();
avatar_data.flags = 0;
avatar_data.caption_index = 0;
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_PROPERTIES);
self->notifyObservers(agent_id, &avatar_data, APT_PROPERTIES);
// Picks
LLSD picks_array = result["picks"];
LLAvatarPicks avatar_picks;
avatar_picks.agent_id = agent_id; // Not in use?
avatar_picks.target_id = agent_id;
for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
if (result["online"].asBoolean())
{
const LLSD& pick_data = *it;
avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
avatar_data.flags |= AVATAR_ONLINE;
}
if (result["allow_publish"].asBoolean())
{
avatar_data.flags |= AVATAR_ALLOW_PUBLISH;
}
if (result["identified"].asBoolean())
{
avatar_data.flags |= AVATAR_IDENTIFIED;
}
if (result["transacted"].asBoolean())
{
avatar_data.flags |= AVATAR_TRANSACTED;
}
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_PICKS);
self->notifyObservers(agent_id, &avatar_picks, APT_PICKS);
avatar_data.caption_index = 0;
if (result.has("charter_member")) // won't be present if "caption" is set
{
avatar_data.caption_index = result["charter_member"].asInteger();
}
else if (result.has("caption"))
{
avatar_data.caption_text = result["caption"].asString();
}
// Groups
LLSD groups_array = result["groups"];
LLAvatarGroups avatar_groups;
avatar_groups.agent_id = agent_id; // Not in use?
avatar_groups.avatar_id = agent_id; // target_id
for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
{
const LLSD& group_info = *it;
LLAvatarGroups::LLGroupData group_data;
LLAvatarData::LLGroupData group_data;
group_data.group_powers = 0; // Not in use?
group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
group_data.group_id = group_info["id"].asUUID();
group_data.group_name = group_info["name"].asString();
group_data.group_insignia_id = group_info["image_id"].asUUID();
avatar_groups.group_list.push_back(group_data);
avatar_data.group_list.push_back(group_data);
}
self->removePendingRequest(agent_id, APT_GROUPS);
self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS);
// Picks
LLSD picks_array = result["picks"];
for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
{
const LLSD& pick_data = *it;
avatar_data.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
}
// Notes
LLAvatarNotes avatar_notes;
avatar_notes.agent_id = agent_id;
avatar_notes.target_id = agent_id;
avatar_notes.notes = result["notes"].asString();
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_NOTES);
self->notifyObservers(agent_id, &avatar_notes, APT_NOTES);
inst.notifyObservers(avatar_id, &avatar_data, type);
}
void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**)
void LLAvatarPropertiesProcessor::processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**)
{
LLAvatarData avatar_data;
LLAvatarLegacyData avatar_data;
std::string birth_date;
msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_data.agent_id);
@ -434,51 +386,23 @@ void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem*
msg->getString( _PREHASH_PropertiesData, _PREHASH_ProfileURL, avatar_data.profile_url);
msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_Flags, avatar_data.flags);
LLDateUtil::dateFromPDTString(avatar_data.born_on, birth_date);
avatar_data.caption_index = 0;
S32 charter_member_size = 0;
charter_member_size = msg->getSize(_PREHASH_PropertiesData, _PREHASH_CharterMember);
if(1 == charter_member_size)
if (1 == charter_member_size)
{
msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember, &avatar_data.caption_index, 1);
}
else if(1 < charter_member_size)
else if (1 < charter_member_size)
{
msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text);
}
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES);
self->notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES);
}
void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**)
{
/*
AvatarInterestsReply is automatically sent by the server in response to the
AvatarPropertiesRequest sent when the panel is opened (in addition to the AvatarPropertiesReply message).
If the interests panel is no longer part of the design (?) we should just register the message
to a handler function that does nothing.
That will suppress the warnings and be compatible with old server versions.
WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply
*/
LLInterestsData interests_data;
msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id );
msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id );
msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, interests_data.want_to_mask );
msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, interests_data.want_to_text );
msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, interests_data.skills_mask );
msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, interests_data.skills_text );
msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, interests_data.languages_text );
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO);
self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO);
self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES_LEGACY);
self->notifyObservers(avatar_data.avatar_id, &avatar_data, APT_PROPERTIES_LEGACY);
}
void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**)
@ -497,7 +421,7 @@ void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem*
msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, data.classified_id, n);
msg->getString(_PREHASH_Data, _PREHASH_Name, data.name, n);
classifieds.classifieds_list.push_back(data);
classifieds.classifieds_list.emplace_back(data);
}
LLAvatarPropertiesProcessor* self = getInstance();
@ -534,44 +458,6 @@ void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* ms
self->notifyObservers(c_info.creator_id, &c_info, APT_CLASSIFIED_INFO);
}
void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**)
{
LLAvatarNotes avatar_notes;
msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_notes.agent_id);
msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id);
msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes);
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(avatar_notes.target_id, APT_NOTES);
self->notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES);
}
void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**)
{
LLAvatarPicks avatar_picks;
msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id);
msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id);
S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data);
for (int block = 0; block < block_count; ++block)
{
LLUUID pick_id;
std::string pick_name;
msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block);
msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block);
avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name));
}
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(avatar_picks.target_id, APT_PICKS);
self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS);
}
void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**)
{
LLPickData pick_data;
@ -602,46 +488,18 @@ void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, voi
self->notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO);
}
void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**)
{
LLAvatarGroups avatar_groups;
msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, avatar_groups.agent_id );
msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_groups.avatar_id );
S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
for(S32 i = 0; i < group_count; ++i)
{
LLAvatarGroups::LLGroupData group_data;
msg->getU64( _PREHASH_GroupData, _PREHASH_GroupPowers, group_data.group_powers, i );
msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_data.group_title, i );
msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_data.group_id, i);
msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_data.group_name, i );
msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_data.group_insignia_id, i );
avatar_groups.group_list.push_back(group_data);
}
LLAvatarPropertiesProcessor* self = getInstance();
self->removePendingRequest(avatar_groups.avatar_id, APT_GROUPS);
self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS);
}
void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type)
void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id, void* data, EAvatarProcessorType type)
{
// Copy the map (because observers may delete themselves when updated?)
LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers;
observer_multimap_t::iterator oi = observers.begin();
observer_multimap_t::iterator end = observers.end();
for (; oi != end; ++oi)
for (const auto& [agent_id, observer] : observers)
{
// only notify observers for the same agent, or if the observer
// didn't know the agent ID and passed a NULL id.
const LLUUID &agent_id = oi->first;
if (agent_id == id || agent_id.isNull())
{
oi->second->processProperties(data,type);
observer->processProperties(data, type);
}
}
}
@ -655,8 +513,8 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32
// setup message header
msg->newMessageFast(_PREHASH_GrantUserRights);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlockFast(_PREHASH_Rights);
msg->addUUID(_PREHASH_AgentRelated, avatar_id);
@ -666,34 +524,13 @@ void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32
}
}
void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes)
{
if(!avatar_id.isNull())
{
LLMessageSystem* msg = gMessageSystem;
// setup message header
msg->newMessageFast(_PREHASH_AvatarNotesUpdate);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->nextBlockFast(_PREHASH_Data);
msg->addUUID(_PREHASH_TargetID, avatar_id);
msg->addString(_PREHASH_Notes, notes);
gAgent.sendReliableMessage();
}
}
void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id )
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessage(_PREHASH_PickDelete);
msg->nextBlock(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_PickID, pick_id);
gAgent.sendReliableMessage();
@ -709,8 +546,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_
msg->newMessage(_PREHASH_ClassifiedDelete);
msg->nextBlock(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, classified_id);
@ -718,39 +555,17 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_
gAgent.sendReliableMessage();
}
void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data)
{
if(!interests_data)
{
return;
}
LLMessageSystem* msg = gMessageSystem;
msg->newMessage(_PREHASH_AvatarInterestsUpdate);
msg->nextBlockFast( _PREHASH_AgentData);
msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast( _PREHASH_SessionID, gAgent.getSessionID() );
msg->nextBlockFast( _PREHASH_PropertiesData);
msg->addU32Fast( _PREHASH_WantToMask, interests_data->want_to_mask);
msg->addStringFast( _PREHASH_WantToText, interests_data->want_to_text);
msg->addU32Fast( _PREHASH_SkillsMask, interests_data->skills_mask);
msg->addStringFast( _PREHASH_SkillsText, interests_data->skills_text);
msg->addString( _PREHASH_LanguagesText, interests_data->languages_text);
gAgent.sendReliableMessage();
}
void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick)
{
if (!new_pick) return;
if (!new_pick)
return;
LLMessageSystem* msg = gMessageSystem;
msg->newMessage(_PREHASH_PickInfoUpdate);
msg->nextBlock(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_PickID, new_pick->pick_id);
@ -787,8 +602,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif
msg->newMessage(_PREHASH_ClassifiedInfoUpdate);
msg->nextBlock(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id);
@ -809,9 +624,7 @@ void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id,
{
// Must ask for a pick based on the creator id because
// the pick database is distributed to the inventory cluster. JC
std::vector<std::string> request_params;
request_params.push_back(creator_id.asString() );
request_params.push_back(pick_id.asString() );
std::vector<std::string> request_params{ creator_id.asString(), pick_id.asString() };
send_generic_message("pickinforequest", request_params);
}
@ -822,8 +635,8 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classi
msg->newMessage(_PREHASH_ClassifiedInfoRequest);
msg->nextBlock(_PREHASH_AgentData);
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUID(_PREHASH_AgentID, gAgentID);
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
msg->nextBlock(_PREHASH_Data);
msg->addUUID(_PREHASH_ClassifiedID, classified_id);
@ -840,7 +653,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva
if (it == mRequestTimestamps.end()) return false;
// We found a request, check if it has timed out
U32 now = time(NULL);
U32 now = time(nullptr);
const U32 REQUEST_EXPIRE_SECS = 5;
U32 expires = it->second + REQUEST_EXPIRE_SECS;
@ -854,7 +667,7 @@ bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAva
void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type)
{
timestamp_map_t::key_type key = std::make_pair(avatar_id, type);
U32 now = time(NULL);
U32 now = time(nullptr);
// Add or update existing (expired) request
mRequestTimestamps[ key ] = now;
}

View File

@ -50,54 +50,71 @@ class LLMessageSystem;
enum EAvatarProcessorType
{
APT_PROPERTIES,
APT_NOTES,
APT_GROUPS,
APT_PICKS,
APT_PROPERTIES_LEGACY, // APT_PROPERTIES via udp request (Truncates data!!!)
APT_PROPERTIES, // APT_PROPERTIES via http request
APT_PICK_INFO,
APT_TEXTURES,
APT_INTERESTS_INFO,
APT_CLASSIFIEDS,
APT_CLASSIFIED_INFO
};
struct LLInterestsData
// legacy data is supposed to match AvatarPropertiesReply,
// but it is obsolete, fields like about_text will truncate
// data, if you need them, use AgenProfile cap.
// Todo: remove it once once icon ids get moved elsewhere,
// since AgentProfile is too large for bulk icon requests
struct LLAvatarLegacyData
{
LLUUID agent_id;
LLUUID avatar_id; //target id
U32 want_to_mask;
std::string want_to_text;
U32 skills_mask;
std::string skills_text;
std::string languages_text;
LLUUID agent_id;
LLUUID avatar_id; //target id
LLUUID image_id;
LLUUID fl_image_id;
LLUUID partner_id;
std::string about_text;
std::string fl_about_text;
LLDate born_on;
std::string profile_url;
U8 caption_index;
std::string caption_text;
std::string customer_type;
U32 flags;
};
struct LLAvatarData
{
LLUUID agent_id;
LLUUID avatar_id; //target id
LLUUID image_id;
LLUUID fl_image_id;
LLUUID partner_id;
std::string about_text;
std::string fl_about_text;
LLDate born_on;
std::string profile_url;
U8 caption_index;
std::string caption_text;
LLUUID agent_id;
LLUUID avatar_id; //target id
LLUUID image_id;
LLUUID fl_image_id;
LLUUID partner_id;
std::string about_text;
std::string fl_about_text;
LLDate born_on;
std::string profile_url;
U8 caption_index;
std::string caption_text;
std::string customer_type;
U32 flags;
BOOL allow_publish;
U32 flags;
bool hide_age;
std::string notes;
struct LLGroupData;
typedef std::list<LLGroupData> group_list_t;
group_list_t group_list;
typedef std::pair<LLUUID, std::string> pick_data_t;
typedef std::list< pick_data_t> picks_list_t;
picks_list_t picks_list;
};
struct LLAvatarPicks
struct LLAvatarData::LLGroupData
{
LLUUID agent_id;
LLUUID target_id; //target id
typedef std::pair<LLUUID,std::string> pick_data_t;
typedef std::list< pick_data_t> picks_list_t;
picks_list_t picks_list;
U64 group_powers;
BOOL accept_notices;
std::string group_title;
LLUUID group_id;
std::string group_name;
LLUUID group_insignia_id;
};
struct LLPickData
@ -121,36 +138,6 @@ struct LLPickData
//used only in write (update) requests
LLUUID session_id;
};
struct LLAvatarNotes
{
LLUUID agent_id;
LLUUID target_id; //target id
std::string notes;
};
struct LLAvatarGroups
{
LLUUID agent_id;
LLUUID avatar_id; //target id
BOOL list_in_profile;
struct LLGroupData;
typedef std::list<LLGroupData> group_list_t;
group_list_t group_list;
struct LLGroupData
{
U64 group_powers;
BOOL accept_notices;
std::string group_title;
LLUUID group_id;
std::string group_name;
LLUUID group_insignia_id;
};
};
struct LLAvatarClassifieds
@ -211,9 +198,7 @@ public:
// Request various types of avatar data. Duplicate requests will be
// suppressed while waiting for a response from the network.
void sendAvatarPropertiesRequest(const LLUUID& avatar_id);
void sendAvatarPicksRequest(const LLUUID& avatar_id);
void sendAvatarNotesRequest(const LLUUID& avatar_id);
void sendAvatarGroupsRequest(const LLUUID& avatar_id);
void sendAvatarLegacyPropertiesRequest(const LLUUID& avatar_id);
void sendAvatarTexturesRequest(const LLUUID& avatar_id);
void sendAvatarClassifiedsRequest(const LLUUID& avatar_id);
@ -222,21 +207,17 @@ public:
void sendClassifiedInfoRequest(const LLUUID& classified_id);
void sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props);
void sendPickInfoUpdate(const LLPickData* new_pick);
void sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data);
void sendFriendRights(const LLUUID& avatar_id, S32 rights);
void sendNotes(const LLUUID& avatar_id, const std::string notes);
void sendPickDelete(const LLUUID& pick_id);
void sendClassifiedDelete(const LLUUID& classified_id);
void sendInterestsInfoUpdate(const LLInterestsData* interests_data);
bool isHideAgeSupportedByServer() { return mIsHideAgeSupportedByServer; }
// Returns translated, human readable string for account type, such
// as "Resident" or "Linden Employee". Used for profiles, inspectors.
@ -249,30 +230,23 @@ public:
static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data);
static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id);
static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID avatar_id, EAvatarProcessorType type);
static void processAvatarPropertiesReply(LLMessageSystem* msg, void**);
static void processAvatarInterestsReply(LLMessageSystem* msg, void**);
// Processing of UDP variant of properties, truncates certain fields!
static void processAvatarLegacyPropertiesReply(LLMessageSystem* msg, void**);
static void processAvatarClassifiedsReply(LLMessageSystem* msg, void**);
static void processClassifiedInfoReply(LLMessageSystem* msg, void**);
static void processAvatarGroupsReply(LLMessageSystem* msg, void**);
static void processAvatarNotesReply(LLMessageSystem* msg, void**);
static void processAvatarPicksReply(LLMessageSystem* msg, void**);
static void processPickInfoReply(LLMessageSystem* msg, void**);
protected:
void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id);
void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url);
void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url, EAvatarProcessorType type);
void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type);
@ -302,6 +276,9 @@ protected:
// Map avatar_id+request_type -> U32 timestamp in seconds
typedef std::map< std::pair<LLUUID, EAvatarProcessorType>, U32> timestamp_map_t;
timestamp_map_t mRequestTimestamps;
// Is returned by isHideAgeSupportedByServer()
bool mIsHideAgeSupportedByServer { false };
};
#endif // LL_LLAVATARPROPERTIESPROCESSOR_H

View File

@ -88,7 +88,7 @@ LLScreenChannel* LLChannelManager::createNotificationChannel()
{
// creating params for a channel
LLScreenChannelBase::Params p;
p.id = LLUUID(gSavedSettings.getString("NotificationChannelUUID"));
p.id = NOTIFICATION_CHANNEL_UUID;
p.channel_align = CA_RIGHT;
p.toast_align = NA_TOP;
@ -108,7 +108,7 @@ void LLChannelManager::onLoginCompleted()
if (!channel) continue;
// don't calc notifications for Nearby Chat
if(channel->getChannelID() == LLUUID(gSavedSettings.getString("NearByChatChannelUUID")))
if(channel->getChannelID() == NEARBY_CHAT_CHANNEL_UUID)
{
continue;
}
@ -130,7 +130,7 @@ void LLChannelManager::onLoginCompleted()
{
// create a channel for the StartUp Toast
LLScreenChannelBase::Params p;
p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID"));
p.id = STARTUP_CHANNEL_UUID;
p.channel_align = CA_RIGHT;
mStartUpChannel = createChannel(p);
@ -143,9 +143,8 @@ void LLChannelManager::onLoginCompleted()
gViewerWindow->getRootView()->addChild(mStartUpChannel);
// init channel's position and size
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound);
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
mStartUpChannel->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound);
mStartUpChannel->setMouseDownCallback(boost::bind(&LLFloaterNotificationsTabbed::onStartUpToastClick, LLFloaterNotificationsTabbed::getInstance(), _2, _3, _4));
mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));
@ -164,7 +163,7 @@ void LLChannelManager::onStartUpToastClose()
{
mStartUpChannel->setVisible(FALSE);
mStartUpChannel->closeStartUpToast();
removeChannelByID(LLUUID(gSavedSettings.getString("StartUpChannelUUID")));
removeChannelByID(STARTUP_CHANNEL_UUID);
mStartUpChannel = NULL;
}
@ -258,12 +257,12 @@ LLNotificationsUI::LLScreenChannel* LLChannelManager::getNotificationScreenChann
{
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
findChannelByID(NOTIFICATION_CHANNEL_UUID));
if (channel == NULL)
{
LL_WARNS() << "Can't find screen channel by NotificationChannelUUID" << LL_ENDL;
llassert(!"Can't find screen channel by NotificationChannelUUID");
LL_WARNS() << "Can't find screen channel by Notification Channel UUID" << LL_ENDL;
llassert(!"Can't find screen channel by Notification Channel UUID");
}
return channel;

View File

@ -142,7 +142,7 @@ protected:
registrar.add("Attachment.Touch", boost::bind(handleMultiple, handle_attachment_touch, mUUIDs));
registrar.add("Attachment.Edit", boost::bind(handleMultiple, handle_item_edit, mUUIDs));
registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs));
registrar.add("Attachment.Detach", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
enable_registrar.add("Attachment.OnEnable", boost::bind(&CofAttachmentContextMenu::onEnable, this, _2));
@ -195,7 +195,7 @@ protected:
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
LLUUID selected_id = mUUIDs.back();
registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs));
registrar.add("Clothing.TakeOff", boost::bind(&LLAppearanceMgr::removeItemsFromAvatar, LLAppearanceMgr::getInstance(), mUUIDs, no_op));
registrar.add("Clothing.Replace", boost::bind(replaceWearable, selected_id));
registrar.add("Clothing.Edit", boost::bind(LLAgentWearables::editWearable, selected_id));
registrar.add("Clothing.Create", boost::bind(&CofClothingContextMenu::createNew, this, selected_id));

View File

@ -66,6 +66,7 @@ namespace
{
const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue");
const F32 QUEUE_INVENTORY_FETCH_TIMEOUT = 300.f;
// ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged
// callback mechanism and the LLEventPump coroutine architecture allowing the
@ -359,8 +360,6 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
// Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
// which is caught in objectScriptProcessingQueueCoro
bool monocompile = floater->mMono;
F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
// Initial test to see if we can (or should) attempt to compile the script.
LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory);
@ -385,7 +384,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
LLExperienceCache::instance().fetchAssociatedExperience(inventory->getParentUUID(), inventory->getUUID(),
boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1));
result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
floater.check();
@ -435,7 +434,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
&LLFloaterCompileQueue::handleScriptRetrieval,
&userData);
result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
}
@ -481,7 +480,7 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
}
result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true)));
result = llcoro::suspendUntilEventOnWithTimeout(pump, QUEUE_INVENTORY_FETCH_TIMEOUT, LLSDMap("timeout", LLSD::Boolean(true)));
floater.check();
@ -736,8 +735,6 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
// Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
// This is expected if the dialog closes.
LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true);
F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
try
{
@ -759,7 +756,7 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
args["[OBJECT_NAME]"] = (*itObj).mObjectName;
floater->addStringMessage(floater->getString("LoadingObjInv", args));
LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, QUEUE_INVENTORY_FETCH_TIMEOUT,
LLSDMap("timeout", LLSD::Boolean(true)));
if (result.has("timeout"))

View File

@ -99,21 +99,6 @@ LLVOAvatar *LLControlAvatar::getAttachedAvatar()
void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const
{
F32 max_legal_offset = MAX_LEGAL_OFFSET;
if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset"))
{
max_legal_offset = gSavedSettings.getF32("AnimatedObjectsMaxLegalOffset");
}
max_legal_offset = llmax(max_legal_offset,0.f);
F32 max_legal_size = MAX_LEGAL_SIZE;
if (gSavedSettings.getControl("AnimatedObjectsMaxLegalSize"))
{
max_legal_size = gSavedSettings.getF32("AnimatedObjectsMaxLegalSize");
}
max_legal_size = llmax(max_legal_size, 1.f);
new_pos_fixup = LLVector3();
new_scale_fixup = 1.0f;
LLVector3 vol_pos = mRootVolp->getRenderPosition();
@ -138,9 +123,9 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
{
LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents);
F32 offset_dist = pos_box_offset.length();
if (offset_dist > max_legal_offset && offset_dist > 0.f)
if (offset_dist > MAX_LEGAL_OFFSET && offset_dist > 0.f)
{
F32 target_dist = (offset_dist - max_legal_offset);
F32 target_dist = (offset_dist - MAX_LEGAL_OFFSET);
new_pos_fixup = (target_dist/offset_dist)*pos_box_offset;
}
if (new_pos_fixup != mPositionConstraintFixup)
@ -153,11 +138,11 @@ void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_
}
}
if (box_size/mScaleConstraintFixup > max_legal_size)
if (box_size/mScaleConstraintFixup > MAX_LEGAL_SIZE)
{
new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size;
new_scale_fixup = mScaleConstraintFixup* MAX_LEGAL_SIZE /box_size;
LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup "
<< mScaleConstraintFixup << " max legal " << max_legal_size
<< mScaleConstraintFixup << " max legal " << MAX_LEGAL_SIZE
<< " -> new scale " << new_scale_fixup << LL_ENDL;
}
}
@ -202,8 +187,7 @@ void LLControlAvatar::matchVolumeTransform()
mRoot->setWorldRotation(obj_rot * joint_rot);
setRotation(mRoot->getRotation());
F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
setGlobalScale(global_scale * mScaleConstraintFixup);
setGlobalScale(mScaleConstraintFixup);
}
else
{
@ -253,8 +237,7 @@ void LLControlAvatar::matchVolumeTransform()
}
mRoot->setPosition(vol_pos + mPositionConstraintFixup);
F32 global_scale = gSavedSettings.getF32("AnimatedObjectsGlobalScale");
setGlobalScale(global_scale * mScaleConstraintFixup);
setGlobalScale(mScaleConstraintFixup);
}
}
}
@ -379,6 +362,7 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
void LLControlAvatar::markDead()
{
mRootVolp = NULL;
super::markDead();
mControlAVBridge = NULL;
}

View File

@ -82,7 +82,7 @@ public:
virtual BOOL isItemRenameable() const { return TRUE; }
virtual BOOL renameItem(const std::string& new_name) { mName = new_name; mNeedsRefresh = true; return TRUE; }
virtual BOOL isItemMovable( void ) const { return FALSE; }
virtual BOOL isItemRemovable( void ) const { return FALSE; }
virtual BOOL isItemRemovable(bool check_worn = true) const { return FALSE; }
virtual BOOL isItemInTrash( void) const { return FALSE; }
virtual BOOL removeItem() { return FALSE; }
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) { }

View File

@ -760,19 +760,6 @@ void LLDrawable::movePartition()
if (part)
{
part->move(this, getSpatialGroup());
// SL-18251 "On-screen animesh characters using pelvis offset animations
// disappear when root goes off-screen"
//
// Update extents of the root node when Control Avatar changes it's bounds
if (mRenderType == LLPipeline::RENDER_TYPE_CONTROL_AV && isRoot())
{
LLControlAvatar* controlAvatar = dynamic_cast<LLControlAvatar*>(getVObj().get());
if (controlAvatar && controlAvatar->mControlAVBridge)
{
((LLSpatialGroup*)controlAvatar->mControlAVBridge->mOctree->getListener(0))->setState(LLViewerOctreeGroup::DIRTY);
}
}
}
}

View File

@ -2104,7 +2104,7 @@ void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environ
{
LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL;
}
else if (LLApp::isExiting())
else if (LLApp::isExiting() || gDisconnected)
{
return;
}

View File

@ -627,6 +627,9 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF
switch(filter)
{
case FFLOAD_ALL:
case FFLOAD_EXE:
allowedv->push_back("app");
allowedv->push_back("exe");
allowedv->push_back("wav");
allowedv->push_back("bvh");
allowedv->push_back("anim");
@ -647,9 +650,6 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF
allowedv->push_back("tpic");
allowedv->push_back("png");
break;
case FFLOAD_EXE:
allowedv->push_back("app");
allowedv->push_back("exe");
break;
case FFLOAD_WAV:
allowedv->push_back("wav");

View File

@ -107,15 +107,11 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
mCloseOnSelect(FALSE),
mExcludeAgentFromSearchResults(FALSE),
mContextConeOpacity (0.f),
mContextConeInAlpha(0.f),
mContextConeOutAlpha(0.f),
mContextConeFadeTime(0.f)
mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA),
mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA),
mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
{
mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
BOOL LLFloaterAvatarPicker::postBuild()

View File

@ -102,9 +102,9 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
mActive ( TRUE ),
mCanApplyImmediately ( show_apply_immediate ),
mContextConeOpacity ( 0.f ),
mContextConeInAlpha ( 0.f ),
mContextConeOutAlpha ( 0.f ),
mContextConeFadeTime ( 0.f )
mContextConeInAlpha (CONTEXT_CONE_IN_ALPHA),
mContextConeOutAlpha (CONTEXT_CONE_OUT_ALPHA),
mContextConeFadeTime (CONTEXT_CONE_FADE_TIME)
{
buildFromFile ( "floater_color_picker.xml");
@ -116,10 +116,6 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show
mApplyImmediateCheck->setEnabled(FALSE);
mApplyImmediateCheck->set(FALSE);
}
mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterColorPicker::~LLFloaterColorPicker()

View File

@ -37,13 +37,14 @@
const std::string LL_FCP_COMPLETE_NAME("complete_name");
const std::string LL_FCP_ACCOUNT_NAME("user_name");
const S32 CONVERSATION_HISTORY_PAGE_SIZE = 100;
LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_id)
: LLFloater(session_id),
mChatHistory(NULL),
mSessionID(session_id.asUUID()),
mCurrentPage(0),
mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")),
mPageSize(CONVERSATION_HISTORY_PAGE_SIZE),
mAccountName(session_id[LL_FCP_ACCOUNT_NAME]),
mCompleteName(session_id[LL_FCP_COMPLETE_NAME]),
mMutex(),

View File

@ -116,7 +116,7 @@ BOOL LLFloaterEnvironmentAdjust::postBuild()
getChild<LLTextureCtrl>(FIELD_SKY_CLOUD_MAP)->setAllowNoTexture(TRUE);
getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setDefaultImageAssetID(LLSettingsWater::GetDefaultWaterNormalAssetId());
getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setBlankImageAssetID(LLUUID(gSavedSettings.getString("DefaultBlankNormalTexture")));
getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setBlankImageAssetID(DEFAULT_BLANK_NORMAL_TEXTURE);
getChild<LLTextureCtrl>(FIELD_WATER_NORMAL_MAP)->setCommitCallback([this](LLUICtrl *, const LLSD &) { onWaterMapChanged(); });
getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setCommitCallback([this](LLUICtrl*, const LLSD&) { onReflectionProbeAmbianceChanged(); });

View File

@ -88,13 +88,10 @@ LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key )
:LLFloater(key)
,mSearchPanel(NULL)
,mContextConeOpacity(0.f)
,mContextConeInAlpha(0.f)
,mContextConeOutAlpha(0.f)
,mContextConeFadeTime(0.f)
,mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA)
,mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA)
,mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
{
mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha");
mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha");
mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime");
}
LLFloaterExperiencePicker::~LLFloaterExperiencePicker()

View File

@ -260,7 +260,8 @@ void LLFloaterIMNearbyChat::loadHistory()
void LLFloaterIMNearbyChat::removeScreenChat()
{
LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID")));
LLNotificationsUI::LLScreenChannelBase* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
LLNotificationsUI::NEARBY_CHAT_CHANNEL_UUID);
if(chat_channel)
{
chat_channel->removeToastsFromChannel();

View File

@ -459,7 +459,7 @@ LLFloaterIMNearbyChatHandler::LLFloaterIMNearbyChatHandler()
{
// Getting a Channel for our notifications
LLFloaterIMNearbyChatScreenChannel::Params p;
p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID"));
p.id = NEARBY_CHAT_CHANNEL_UUID;
LLFloaterIMNearbyChatScreenChannel* channel = new LLFloaterIMNearbyChatScreenChannel(p);
LLFloaterIMNearbyChatScreenChannel::create_toast_panel_callback_t callback = createToastPanel;

View File

@ -651,7 +651,7 @@ void LLFloaterIMSession::setDocked(bool docked, bool pop_on_undock)
// update notification channel state
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
if(!isChatMultiTab())
{
@ -687,7 +687,7 @@ void LLFloaterIMSession::setVisible(BOOL visible)
{
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
LLFloaterIMSessionTab::setVisible(visible);
@ -865,7 +865,7 @@ void LLFloaterIMSession::updateMessages()
// remove embedded notification from channel
LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
(LLNotificationsUI::LLChannelManager::getInstance()->
findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
findChannelByID(LLNotificationsUI::NOTIFICATION_CHANNEL_UUID));
if (getVisible())
{
// toast will be automatically closed since it is not storable toast

View File

@ -250,6 +250,13 @@ void LLFloaterJoystick::refresh()
initFromSettings();
}
bool LLFloaterJoystick::addDeviceCallback(std::string &name, LLSD& value, void* userdata)
{
LLFloaterJoystick * floater = (LLFloaterJoystick*)userdata;
floater->mJoysticksCombo->add(name, value, ADD_BOTTOM, 1);
return false; // keep searching
}
void LLFloaterJoystick::addDevice(std::string &name, LLSD& value)
{
mJoysticksCombo->add(name, value, ADD_BOTTOM, 1);
@ -264,19 +271,21 @@ void LLFloaterJoystick::refreshListOfDevices()
mHasDeviceList = false;
void* win_calback = nullptr;
// di8_devices_callback callback is immediate and happens in scope of getInputDevices()
#if LL_WINDOWS && !LL_MESA_HEADLESS
// space navigator is marked as DI8DEVCLASS_GAMECTRL in ndof lib
U32 device_type = DI8DEVCLASS_GAMECTRL;
void* callback = &di8_list_devices_callback;
#else
// MAC doesn't support device search yet
// On MAC there is an ndof_idsearch and it is possible to specify product
// and manufacturer in NDOF_Device for ndof_init_first to pick specific one
win_calback = di8_list_devices_callback;
#elif LL_DARWIN
U32 device_type = 0;
#else
// On MAC it is possible to specify product
// and manufacturer in NDOF_Device for
// ndof_init_first to pick specific device
U32 device_type = 0;
void* callback = NULL;
#endif
if (gViewerWindow->getWindow()->getInputDevices(device_type, callback, this))
if (gViewerWindow->getWindow()->getInputDevices(device_type, addDeviceCallback, win_calback, this))
{
mHasDeviceList = true;
}
@ -418,10 +427,11 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel)
joystick->toggleFlycam();
}
}
std::string device_id = LLViewerJoystick::getInstance()->getDeviceUUIDString();
gSavedSettings.setString("JoystickDeviceUUID", device_id);
LL_DEBUGS("Joystick") << "Selected " << device_id << " as joystick." << LL_ENDL;
LLViewerJoystick::getInstance()->saveDeviceIdToSettings();
std::string device_string = LLViewerJoystick::getInstance()->getDeviceUUIDString();
LL_DEBUGS("Joystick") << "Selected " << device_string << " as joystick." << LL_ENDL;
self->refreshListOfDevices();
}

View File

@ -46,6 +46,7 @@ public:
virtual void draw();
static void setSNDefaults();
static bool addDeviceCallback(std::string &name, LLSD& value, void* userdata);
void addDevice(std::string &name, LLSD& value);
protected:

View File

@ -154,7 +154,7 @@ LLPanel * LLFloaterNotificationsTabbed::findItemByID(const LLUUID& id, std::stri
void LLFloaterNotificationsTabbed::initChannel()
{
LLNotificationsUI::LLScreenChannelBase* channel = LLNotificationsUI::LLChannelManager::getInstance()->findChannelByID(
LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
LLNotificationsUI::NOTIFICATION_CHANNEL_UUID);
mChannel = dynamic_cast<LLNotificationsUI::LLScreenChannel*>(channel);
if(NULL == mChannel)
{

View File

@ -329,9 +329,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)
void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type )
{
if ( APT_PROPERTIES == type )
if ( APT_PROPERTIES_LEGACY == type )
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( pData );
const LLAvatarLegacyData* pAvatarData = static_cast<const LLAvatarLegacyData*>( pData );
if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
{
mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH);
@ -471,9 +471,7 @@ BOOL LLFloaterPreference::postBuild()
void LLFloaterPreference::updateDeleteTranscriptsButton()
{
std::vector<std::string> list_of_transcriptions_file_names;
LLLogChat::getListOfTranscriptFiles(list_of_transcriptions_file_names);
getChild<LLButton>("delete_transcripts")->setEnabled(list_of_transcriptions_file_names.size() > 0);
getChild<LLButton>("delete_transcripts")->setEnabled(LLLogChat::transcriptFilesExist());
}
void LLFloaterPreference::onDoNotDisturbResponseChanged()
@ -638,7 +636,6 @@ void LLFloaterPreference::cancel()
void LLFloaterPreference::onOpen(const LLSD& key)
{
// this variable and if that follows it are used to properly handle do not disturb mode response message
static bool initialized = FALSE;
// if user is logged in and we haven't initialized do not disturb mode response yet, do it
@ -665,7 +662,7 @@ void LLFloaterPreference::onOpen(const LLSD& key)
(gAgent.isMature() || gAgent.isGodlike());
LLComboBox* maturity_combo = getChild<LLComboBox>("maturity_desired_combobox");
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest( gAgent.getID() );
LLAvatarPropertiesProcessor::getInstance()->sendAvatarLegacyPropertiesRequest( gAgent.getID() );
if (can_choose_maturity)
{
// if they're not adult or a god, they shouldn't see the adult selection, so delete it

View File

@ -48,12 +48,6 @@ public:
LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch"))
{
LLNotificationsUtil::add("NoSearch", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
return true;
}
const size_t parts = tokens.size();
// get the (optional) category for the search

View File

@ -129,12 +129,6 @@ public:
const std::string& grid,
LLMediaCtrl* web)
{
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap"))
{
LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
return true;
}
if (params.size() == 0)
{
// support the secondlife:///app/worldmap SLapp
@ -170,12 +164,6 @@ public:
const std::string& grid,
LLMediaCtrl* web)
{
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableWorldMap"))
{
LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
return true;
}
//Make sure we have some parameters
if (params.size() == 0)
{

View File

@ -58,6 +58,9 @@
// Longest time, in seconds, to wait for all animations to stop playing
const F32 MAX_WAIT_ANIM_SECS = 30.f;
// Longest time, in seconds, to wait for a key release.
// This should be relatively long, but not too long. 10 minutes is enough
const F32 MAX_WAIT_KEY_SECS = 60.f * 10.f;
// Lightweight constructor.
// init() does the heavy lifting.
@ -528,12 +531,13 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset
LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id);
}
void LLGestureMgr::playGesture(LLMultiGesture* gesture)
void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool fromKeyPress)
{
if (!gesture) return;
// Reset gesture to first step
gesture->mCurrentStep = 0;
gesture->mTriggeredByKey = fromKeyPress;
// Add to list of playing
gesture->mPlaying = TRUE;
@ -731,7 +735,8 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask)
if (!gesture) continue;
if (gesture->mKey == key
&& gesture->mMask == mask)
&& gesture->mMask == mask
&& gesture->mWaitingKeyRelease == FALSE)
{
matching.push_back(gesture);
}
@ -744,13 +749,38 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask)
LLMultiGesture* gesture = matching[random];
playGesture(gesture);
playGesture(gesture, TRUE);
return TRUE;
}
return FALSE;
}
BOOL LLGestureMgr::triggerGestureRelease(KEY key, MASK mask)
{
std::vector <LLMultiGesture *> matching;
item_map_t::iterator it;
// collect matching gestures
for (it = mActive.begin(); it != mActive.end(); ++it)
{
LLMultiGesture* gesture = (*it).second;
// asset data might not have arrived yet
if (!gesture) continue;
if (gesture->mKey == key
&& gesture->mMask == mask)
{
gesture->mKeyReleased = TRUE;
}
}
//If we found one, block. Otherwise tell them it's free to go.
return matching.size() > 0;
}
S32 LLGestureMgr::getPlayingCount() const
{
return mPlaying.size();
@ -899,6 +929,32 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture)
continue;
}
// If we're waiting a fixed amount of time, check for timer
// expiration.
if (gesture->mWaitingKeyRelease)
{
// We're waiting for a certain amount of time to pass
if (gesture->mKeyReleased)
{
// wait is done, continue execution
gesture->mWaitingKeyRelease = FALSE;
gesture->mCurrentStep++;
}
else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_KEY_SECS)
{
LL_INFOS("GestureMgr") << "Waited too long for key release, continuing gesture."
<< LL_ENDL;
gesture->mWaitingKeyRelease = FALSE;
gesture->mCurrentStep++;
}
else
{
// we're waiting, so execution is done for now
waiting = TRUE;
}
continue;
}
// If we're waiting on our animations to stop, poll for
// completion.
if (gesture->mWaitingAnimations)
@ -1015,7 +1071,17 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step)
case STEP_WAIT:
{
LLGestureStepWait* wait_step = (LLGestureStepWait*)step;
if (wait_step->mFlags & WAIT_FLAG_TIME)
if (gesture->mTriggeredByKey // Only wait here IF we were triggered by a key!
&& gesture->mWaitingKeyRelease == FALSE // We can only do this once! Prevent gestures infinitely running
&& wait_step->mFlags & WAIT_FLAG_KEY_RELEASE)
{
// Lets wait for the key release first so we don't hold up re-presses
gesture->mWaitingKeyRelease = TRUE;
gesture->mKeyReleased = FALSE;
// Use the wait timer as a deadlock breaker for key release waits.
gesture->mWaitTimer.reset();
}
else if (wait_step->mFlags & WAIT_FLAG_TIME)
{
gesture->mWaitingTimer = TRUE;
gesture->mWaitTimer.reset();
@ -1023,8 +1089,7 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step)
else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM)
{
gesture->mWaitingAnimations = TRUE;
// Use the wait timer as a deadlock breaker for animation
// waits.
// Use the wait timer as a deadlock breaker for animation waits.
gesture->mWaitTimer.reset();
}
else

View File

@ -102,7 +102,10 @@ public:
const item_map_t& getActiveGestures() const { return mActive; }
// Force a gesture to be played, for example, if it is being
// previewed.
void playGesture(LLMultiGesture* gesture);
void playGesture(LLMultiGesture* gesture, bool fromKeyPress);
void playGesture(LLMultiGesture* gesture) {
playGesture(gesture, FALSE);
}
void playGesture(const LLUUID& item_id);
// Stop all requested or playing anims for this gesture
@ -118,10 +121,14 @@ public:
{
mCallbackMap[inv_item_id] = cb;
}
// Trigger the first gesture that matches this key.
// Trigger a random gesture that matches this key.
// Returns TRUE if it finds a gesture bound to that key.
BOOL triggerGesture(KEY key, MASK mask);
// Trigger release wait on all gestures that matches this key.
// Returns TRUE if it finds a gesture bound to that key.
BOOL triggerGestureRelease(KEY key, MASK mask);
// Trigger all gestures referenced as substrings in this string
BOOL triggerAndReviseString(const std::string &str, std::string *revised_string = NULL);

View File

@ -88,12 +88,6 @@ public:
return true;
}
if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableGroupInfo"))
{
LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
return true;
}
if (tokens.size() < 1)
{
return false;
@ -372,7 +366,16 @@ void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id)
args["GROUP"] = gdatap->mName;
LLSD payload;
payload["group_id"] = group_id;
LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
if (gdatap->mMembershipFee > 0)
{
args["COST"] = gdatap->mMembershipFee;
LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup);
}
else
{
LLNotificationsUtil::add("GroupLeaveConfirmMemberNoFee", args, payload, onLeaveGroup);
}
}
// static
@ -404,7 +407,7 @@ void LLGroupActions::inspect(const LLUUID& group_id)
}
// static
void LLGroupActions::show(const LLUUID& group_id)
void LLGroupActions::show(const LLUUID &group_id, bool expand_notices_tab)
{
if (group_id.isNull())
return;
@ -412,6 +415,10 @@ void LLGroupActions::show(const LLUUID& group_id)
LLSD params;
params["group_id"] = group_id;
params["open_tab_name"] = "panel_group_info_sidetray";
if (expand_notices_tab)
{
params["action"] = "show_notices";
}
LLFloaterSidePanelContainer::showPanel("people", "panel_group_info_sidetray", params);
LLFloater *floater = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("people");

View File

@ -57,7 +57,7 @@ public:
/**
* Show group information panel.
*/
static void show(const LLUUID& group_id);
static void show(const LLUUID& group_id, bool expand_notices_tab = false);
/**
* Show group inspector floater.

View File

@ -303,6 +303,7 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL
item->getChildView("info_btn")->setVisible( false);
item->getChildView("profile_btn")->setVisible( false);
item->getChildView("notices_btn")->setVisible(false);
item->setGroupIconVisible(mShowIcons);
if (!mShowIcons)
{
@ -403,6 +404,7 @@ mGroupIcon(NULL),
mGroupNameBox(NULL),
mInfoBtn(NULL),
mProfileBtn(NULL),
mNoticesBtn(NULL),
mVisibilityHideBtn(NULL),
mVisibilityShowBtn(NULL),
mGroupID(LLUUID::null),
@ -435,6 +437,9 @@ BOOL LLGroupListItem::postBuild()
mProfileBtn = getChild<LLButton>("profile_btn");
mProfileBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onProfileBtnClick(); });
mNoticesBtn = getChild<LLButton>("notices_btn");
mNoticesBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onNoticesBtnClick(); });
mVisibilityHideBtn = findChild<LLButton>("visibility_hide_btn");
if (mVisibilityHideBtn)
{
@ -470,13 +475,17 @@ void LLGroupListItem::onMouseEnter(S32 x, S32 y, MASK mask)
{
mInfoBtn->setVisible(true);
mProfileBtn->setVisible(true);
if (mForAgent && mVisibilityHideBtn)
if (mForAgent)
{
LLGroupData agent_gdatap;
if (gAgent.getGroupData(mGroupID, agent_gdatap))
{
mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile);
mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile);
if (mVisibilityHideBtn)
{
mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile);
mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile);
}
mNoticesBtn->setVisible(true);
}
}
}
@ -489,6 +498,7 @@ void LLGroupListItem::onMouseLeave(S32 x, S32 y, MASK mask)
getChildView("hovered_icon")->setVisible( false);
mInfoBtn->setVisible(false);
mProfileBtn->setVisible(false);
mNoticesBtn->setVisible(false);
if (mVisibilityHideBtn)
{
mVisibilityHideBtn->setVisible(false);
@ -583,6 +593,11 @@ void LLGroupListItem::onProfileBtnClick()
LLGroupActions::show(mGroupID);
}
void LLGroupListItem::onNoticesBtnClick()
{
LLGroupActions::show(mGroupID, true);
}
void LLGroupListItem::onVisibilityBtnClick(bool new_visibility)
{
LLGroupData agent_gdatap;

View File

@ -123,6 +123,7 @@ private:
void setBold(bool bold);
void onInfoBtnClick();
void onProfileBtnClick();
void onNoticesBtnClick();
void onVisibilityBtnClick(bool new_visibility);
LLTextBox* mGroupNameBox;
@ -130,6 +131,7 @@ private:
LLGroupIconCtrl* mGroupIcon;
LLButton* mInfoBtn;
LLButton* mProfileBtn;
LLButton* mNoticesBtn;
LLButton* mVisibilityHideBtn;
LLButton* mVisibilityShowBtn;

View File

@ -54,9 +54,8 @@ LLIMHandler::~LLIMHandler()
//--------------------------------------------------------------------------
void LLIMHandler::initChannel()
{
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");
mChannel.get()->init(channel_right_bound - channel_width, channel_right_bound);
S32 channel_right_bound = gViewerWindow->getWorldViewRectScaled().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");
mChannel.get()->init(channel_right_bound - NOTIFY_BOX_WIDTH, channel_right_bound);
}
//--------------------------------------------------------------------------

View File

@ -581,6 +581,12 @@ void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from,
return;
}
if (LLApp::isExiting() || gDisconnected)
{
LL_DEBUGS("ChatHistory") << "Ignoring chat history response, shutting down" << LL_ENDL;
return;
}
// Add history to IM session
LLSD history = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT];
@ -3915,6 +3921,12 @@ public:
const LLSD& context,
const LLSD& input) const
{
if (LLApp::isExiting() || gDisconnected)
{
LL_DEBUGS("ChatHistory") << "Ignoring ChatterBox session, Shutting down" << LL_ENDL;
return;
}
LLSD body;
LLUUID temp_session_id;
LLUUID session_id;

View File

@ -45,8 +45,8 @@ LLInspect::~LLInspect()
// virtual
void LLInspect::draw()
{
static LLCachedControl<F32> FADE_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorFadeTime", 1.f);
static LLCachedControl<F32> STAY_TIME(*LLUI::getInstance()->mSettingGroups["config"], "InspectorShowTime", 1.f);
const F32 FADE_TIME = 0.5f;
const F32 STAY_TIME = 3.f;
if (mOpenTimer.getStarted())
{
LLFloater::draw();
@ -59,7 +59,7 @@ void LLInspect::draw()
}
else if (mCloseTimer.getStarted())
{
F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME(), 1.f, 0.f);
F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
LLViewDrawContext context(alpha);
LLFloater::draw();
if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)

View File

@ -261,12 +261,15 @@ void LLInspectAvatar::requestUpdate()
void LLInspectAvatar::processAvatarData(LLAvatarData* data)
{
LLStringUtil::format_map_t args;
{
std::string birth_date = LLTrans::getString("AvatarBirthDateFormat");
LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) data->born_on.secondsSinceEpoch()));
args["[BORN_ON]"] = birth_date;
}
args["[AGE]"] = LLDateUtil::ageFromDate(data->born_on, LLDate::now());
std::string birth_date = LLTrans::getString(data->hide_age ?
"AvatarBirthDateFormatShort" :
"AvatarBirthDateFormatFull");
LLStringUtil::format(birth_date, LLSD().with("datetime", (S32)data->born_on.secondsSinceEpoch()));
args["[BORN_ON]"] = birth_date;
args["[AGE]"] = data->hide_age ?
LLStringUtilBase<char>::null :
LLDateUtil::ageFromDate(data->born_on, LLDate::now());
args["[SL_PROFILE]"] = data->about_text;
args["[RW_PROFILE"] = data->fl_about_text;
args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(data);

View File

@ -60,8 +60,8 @@ private:
LLInspectToast::LLInspectToast(const LLSD& notification_id) :
LLInspect(LLSD()), mPanel(NULL)
{
LLScreenChannelBase* channel = LLChannelManager::getInstance()->findChannelByID(
LLUUID(gSavedSettings.getString("NotificationChannelUUID")));
LLScreenChannelBase* channel = LLChannelManager::getInstance()->findChannelByID(
LLNotificationsUI::NOTIFICATION_CHANNEL_UUID);
mScreenChannel = dynamic_cast<LLScreenChannel*>(channel);
if(NULL == mScreenChannel)
{

View File

@ -90,6 +90,7 @@
void copy_slurl_to_clipboard_callback_inv(const std::string& slurl);
const F32 SOUND_GAIN = 1.0f;
const F32 FOLDER_LOADING_MESSAGE_DELAY = 0.5f; // Seconds to wait before showing the LOADING... text in folder views
using namespace LLOldEvents;
@ -308,9 +309,9 @@ void LLInvFVBridge::setCreationDate(time_t creation_date_utc)
// Can be destroyed (or moved to trash)
BOOL LLInvFVBridge::isItemRemovable() const
BOOL LLInvFVBridge::isItemRemovable(bool check_worn) const
{
return get_is_item_removable(getInventoryModel(), mUUID);
return get_is_item_removable(getInventoryModel(), mUUID, check_worn);
}
// Can be moved to another folder
@ -772,9 +773,6 @@ void hide_context_entries(LLMenuGL& menu,
bool found = false;
std::string myinput;
std::vector<std::string> mylist{ "a", "b", "c" };
menuentry_vec_t::const_iterator itor2 = std::find(entries_to_show.begin(), entries_to_show.end(), name);
if (itor2 != entries_to_show.end())
{
@ -874,7 +872,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
}
items.push_back(std::string("Cut"));
if (!isItemMovable() || !isItemRemovable())
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@ -923,7 +921,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,
if(!single_folder_root)
{
items.push_back(std::string("Cut"));
if (!isItemMovable() || !isItemRemovable())
if (!isItemMovable() || !canMenuCut())
{
disabled_items.push_back(std::string("Cut"));
}
@ -1068,7 +1066,7 @@ void LLInvFVBridge::addDeleteContextMenuOptions(menuentry_vec_t &items,
items.push_back(std::string("Delete"));
if (!isItemRemovable() || isPanelActive("Favorite Items"))
if (isPanelActive("Favorite Items") || !canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@ -1224,6 +1222,16 @@ void LLInvFVBridge::addLinkReplaceMenuOption(menuentry_vec_t& items, menuentry_v
}
}
bool LLInvFVBridge::canMenuDelete()
{
return isItemRemovable(false);
}
bool LLInvFVBridge::canMenuCut()
{
return isItemRemovable(true);
}
// *TODO: remove this
BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const
{
@ -1778,7 +1786,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("show_in_main_panel" == action)
{
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE);
LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
return;
}
else if ("cut" == action)
@ -2412,48 +2420,19 @@ void LLFolderBridge::update()
}
}
// Iterate through a folder's children to determine if
// all the children are removable.
class LLIsItemRemovable : public LLFolderViewFunctor
{
public:
LLIsItemRemovable() : mPassed(TRUE) {}
virtual void doFolder(LLFolderViewFolder* folder)
{
mPassed &= folder->getViewModelItem()->isItemRemovable();
}
virtual void doItem(LLFolderViewItem* item)
{
mPassed &= item->getViewModelItem()->isItemRemovable();
}
BOOL mPassed;
};
// Can be destroyed (or moved to trash)
BOOL LLFolderBridge::isItemRemovable() const
BOOL LLFolderBridge::isItemRemovable(bool check_worn) const
{
if (!get_is_category_removable(getInventoryModel(), mUUID))
if (!get_is_category_and_children_removable(getInventoryModel(), mUUID, check_worn))
{
return FALSE;
}
LLInventoryPanel* panel = mInventoryPanel.get();
LLFolderViewFolder* folderp = dynamic_cast<LLFolderViewFolder*>(panel ? panel->getItemByID(mUUID) : NULL);
if (folderp)
{
LLIsItemRemovable folder_test;
folderp->applyFunctorToChildren(folder_test);
if (!folder_test.mPassed)
{
return FALSE;
}
}
if (isMarketplaceListingsFolder() && (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID)))
{
return FALSE;
}
if (isMarketplaceListingsFolder()
&& (!LLMarketplaceData::instance().isSLMDataFetched() || LLMarketplaceData::instance().getActivationState(mUUID)))
{
return FALSE;
}
return TRUE;
}
@ -3409,7 +3388,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("show_in_main_panel" == action)
{
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE);
LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
return;
}
else if ("cut" == action)
@ -4382,6 +4361,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
disabled_items.push_back("New Settings");
}
}
else
{
items.push_back(std::string("New Listing Folder"));
}
if (menu_items_added)
{
items.push_back(std::string("Create Separator"));
@ -4523,7 +4506,7 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t&
return;
}
if (!isItemRemovable())
if (!canMenuDelete())
{
disabled_items.push_back(std::string("Delete"));
}
@ -4894,6 +4877,192 @@ void LLFolderBridge::modifyOutfit(BOOL append)
}
}
//static
void LLFolderBridge::onCanDeleteIdle(void* user_data)
{
LLFolderBridge* self = (LLFolderBridge*)user_data;
// we really need proper onidle mechanics that returns available time
const F32 EXPIRY_SECONDS = 0.008f;
LLTimer timer;
timer.setTimerExpirySec(EXPIRY_SECONDS);
LLInventoryModel* model = self->getInventoryModel();
if (model)
{
switch (self->mCanDeleteFolderState)
{
case CDS_INIT_FOLDER_CHECK:
// Can still be expensive, split it further?
model->collectDescendents(
self->mUUID,
self->mFoldersToCheck,
self->mItemsToCheck,
LLInventoryModel::EXCLUDE_TRASH);
self->mCanDeleteFolderState = CDS_PROCESSING_ITEMS;
break;
case CDS_PROCESSING_ITEMS:
while (!timer.hasExpired() && !self->mItemsToCheck.empty())
{
LLViewerInventoryItem* item = self->mItemsToCheck.back().get();
if (item)
{
if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
{
if (get_is_item_worn(item))
{
// At the moment we disable 'cut' if category has worn items (do we need to?)
// but allow 'delete' to happen since it will prompt user to detach
self->mCanCut = false;
}
}
if (!item->getIsLinkType() && get_is_item_worn(item))
{
self->mCanCut = false;
}
}
self->mItemsToCheck.pop_back();
}
self->mCanDeleteFolderState = CDS_PROCESSING_FOLDERS;
break;
case CDS_PROCESSING_FOLDERS:
{
const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
while (!timer.hasExpired() && !self->mFoldersToCheck.empty())
{
LLViewerInventoryCategory* cat = self->mFoldersToCheck.back().get();
if (cat)
{
const LLFolderType::EType folder_type = cat->getPreferredType();
if (LLFolderType::lookupIsProtectedType(folder_type))
{
self->mCanCut = false;
self->mCanDelete = false;
self->completeDeleteProcessing();
break;
}
// Can't delete the outfit that is currently being worn.
if (folder_type == LLFolderType::FT_OUTFIT)
{
if (cat == outfit_linked_category)
{
self->mCanCut = false;
self->mCanDelete = false;
self->completeDeleteProcessing();
break;
}
}
}
self->mFoldersToCheck.pop_back();
}
}
self->mCanDeleteFolderState = CDS_DONE;
break;
case CDS_DONE:
self->completeDeleteProcessing();
break;
}
}
}
bool LLFolderBridge::canMenuDelete()
{
LLInventoryModel* model = getInventoryModel();
if (!model) return false;
LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
if (!category)
{
return false;
}
S32 version = category->getVersion();
if (mLastCheckedVersion == version)
{
return mCanDelete;
}
initCanDeleteProcessing(model, version);
return false;
}
bool LLFolderBridge::canMenuCut()
{
LLInventoryModel* model = getInventoryModel();
if (!model) return false;
LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
if (!category)
{
return false;
}
S32 version = category->getVersion();
if (mLastCheckedVersion == version)
{
return mCanCut;
}
initCanDeleteProcessing(model, version);
return false;
}
void LLFolderBridge::initCanDeleteProcessing(LLInventoryModel* model, S32 version)
{
if (mCanDeleteFolderState == CDS_DONE
|| mInProgressVersion != version)
{
if (get_is_category_removable(model, mUUID))
{
// init recursive check of content
mInProgressVersion = version;
mCanCut = true;
mCanDelete = true;
mCanDeleteFolderState = CDS_INIT_FOLDER_CHECK;
mFoldersToCheck.clear();
mItemsToCheck.clear();
gIdleCallbacks.addFunction(onCanDeleteIdle, this);
}
else
{
// no check needed
mCanDelete = false;
mCanCut = false;
mLastCheckedVersion = version;
mCanDeleteFolderState = CDS_DONE;
mFoldersToCheck.clear();
mItemsToCheck.clear();
}
}
}
void LLFolderBridge::completeDeleteProcessing()
{
LLInventoryModel* model = getInventoryModel();
LLViewerInventoryCategory* category = model ? (LLViewerInventoryCategory*)model->getCategory(mUUID) : nullptr;
if (model && category && category->getVersion() == mInProgressVersion)
{
mLastCheckedVersion = mInProgressVersion;
mCanDeleteFolderState = CDS_DONE;
gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
}
else
{
mCanDelete = false;
mCanCut = false;
mLastCheckedVersion = LLViewerInventoryCategory::VERSION_UNKNOWN;
mCanDeleteFolderState = CDS_DONE;
}
if (mRoot)
{
mRoot->updateMenu();
}
}
// +=================================================+
// | LLMarketplaceFolderBridge |
@ -4937,9 +5106,7 @@ LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(BOOL is_open) c
std::string LLMarketplaceFolderBridge::getLabelSuffix() const
{
static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f);
if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay())
if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= FOLDER_LOADING_MESSAGE_DELAY)
{
return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str());
}
@ -5057,6 +5224,27 @@ void drop_to_favorites_cb(const LLUUID& id, LLPointer<LLInventoryCallback> cb1,
cb2->fire(id);
}
LLFolderBridge::LLFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid)
: LLInvFVBridge(inventory, root, uuid)
, mCallingCards(FALSE)
, mWearables(FALSE)
, mIsLoading(false)
, mShowDescendantsCount(false)
, mCanDeleteFolderState(CDS_DONE)
, mLastCheckedVersion(S32_MIN)
, mInProgressVersion(S32_MIN)
, mCanDelete(false)
, mCanCut(false)
{
}
LLFolderBridge::~LLFolderBridge()
{
gIdleCallbacks.deleteFunction(onCanDeleteIdle, this);
}
void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb)
{
// use callback to rearrange favorite landmarks after adding
@ -6649,6 +6837,26 @@ LLInventoryObject* LLObjectBridge::getObject() const
return object;
}
LLViewerInventoryItem* LLObjectBridge::getItem() const
{
LLInventoryModel* model = getInventoryModel();
if (model)
{
return model->getItem(mUUID);
}
return NULL;
}
LLViewerInventoryCategory* LLObjectBridge::getCategory() const
{
LLInventoryModel* model = getInventoryModel();
if (model)
{
return model->getCategory(mUUID);
}
return NULL;
}
// virtual
void LLObjectBridge::performAction(LLInventoryModel* model, std::string action)
{

View File

@ -114,7 +114,7 @@ public:
virtual BOOL isItemRenameable() const { return TRUE; }
virtual BOOL isMultiPreviewAllowed() { return TRUE; }
//virtual BOOL renameItem(const std::string& new_name) {}
virtual BOOL isItemRemovable() const;
virtual BOOL isItemRemovable(bool check_worn = true) const;
virtual BOOL isItemMovable() const;
virtual BOOL isItemInTrash() const;
virtual bool isItemInOutfits() const;
@ -162,6 +162,9 @@ protected:
virtual void addLinkReplaceMenuOption(menuentry_vec_t& items,
menuentry_vec_t& disabled_items);
virtual bool canMenuDelete();
virtual bool canMenuCut();
protected:
LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid);
@ -272,14 +275,10 @@ class LLFolderBridge : public LLInvFVBridge
public:
LLFolderBridge(LLInventoryPanel* inventory,
LLFolderView* root,
const LLUUID& uuid)
: LLInvFVBridge(inventory, root, uuid),
mCallingCards(FALSE),
mWearables(FALSE),
mIsLoading(false),
mShowDescendantsCount(false)
{}
const LLUUID& uuid);
~LLFolderBridge();
BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, std::string& tooltip_msg, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, std::string& tooltip_msg, BOOL is_link = FALSE, BOOL user_confirm = TRUE, LLPointer<LLInventoryCallback> cb = NULL);
void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item);
@ -321,7 +320,7 @@ public:
void* cargo_data,
std::string& tooltip_msg);
virtual BOOL isItemRemovable() const;
virtual BOOL isItemRemovable(bool check_worn = true) const;
virtual BOOL isItemMovable() const ;
virtual BOOL isUpToDate() const;
virtual bool isItemCopyable(bool can_copy_as_link = true) const;
@ -392,6 +391,31 @@ protected:
LLTimer mTimeSinceRequestStart;
std::string mMessage;
LLRootHandle<LLFolderBridge> mHandle;
private:
// checking if folder is cutable or deletable is expensive,
// cache values and split check over frames
static void onCanDeleteIdle(void* user_data);
void initCanDeleteProcessing(LLInventoryModel* model, S32 version);
void completeDeleteProcessing();
bool canMenuDelete();
bool canMenuCut();
enum ECanDeleteState
{
CDS_INIT_FOLDER_CHECK,
CDS_PROCESSING_ITEMS,
CDS_PROCESSING_FOLDERS,
CDS_DONE,
};
ECanDeleteState mCanDeleteFolderState;
LLInventoryModel::cat_array_t mFoldersToCheck;
LLInventoryModel::item_array_t mItemsToCheck;
S32 mLastCheckedVersion;
S32 mInProgressVersion;
bool mCanDelete;
bool mCanCut;
};
class LLTextureBridge : public LLItemBridge
@ -524,6 +548,8 @@ public:
virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
virtual BOOL renameItem(const std::string& new_name);
LLInventoryObject* getObject() const;
LLViewerInventoryItem* getItem() const;
LLViewerInventoryCategory* getCategory() const;
protected:
static LLUUID sContextMenuItemID; // Only valid while the context menu is open.
U32 mAttachPt;

View File

@ -579,9 +579,8 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id)
return FALSE;
}
BOOL get_is_item_worn(const LLUUID& id)
BOOL get_is_item_worn(const LLUUID& id, const LLViewerInventoryItem* item)
{
const LLViewerInventoryItem* item = gInventory.getItem(id);
if (!item)
return FALSE;
@ -619,6 +618,21 @@ BOOL get_is_item_worn(const LLUUID& id)
return FALSE;
}
BOOL get_is_item_worn(const LLUUID& id)
{
const LLViewerInventoryItem* item = gInventory.getItem(id);
return get_is_item_worn(id, item);
}
BOOL get_is_item_worn(const LLViewerInventoryItem* item)
{
if (!item)
{
return FALSE;
}
return get_is_item_worn(item->getUUID(), item);
}
BOOL get_can_item_be_worn(const LLUUID& id)
{
const LLViewerInventoryItem* item = gInventory.getItem(id);
@ -682,39 +696,39 @@ BOOL get_can_item_be_worn(const LLUUID& id)
return FALSE;
}
BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id)
bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn)
{
if (!model)
{
return FALSE;
return false;
}
// Can't delete an item that's in the library.
if (!model->isObjectDescendentOf(id, gInventory.getRootFolderID()))
{
return FALSE;
return false;
}
// Disable delete from COF folder; have users explicitly choose "detach/take off",
// unless the item is not worn but in the COF (i.e. is bugged).
if (LLAppearanceMgr::instance().getIsProtectedCOFItem(id))
const LLViewerInventoryItem* obj = model->getItem(id);
if (LLAppearanceMgr::instance().getIsProtectedCOFItem(obj))
{
if (get_is_item_worn(id))
if (get_is_item_worn(id, obj))
{
return FALSE;
return false;
}
}
const LLInventoryObject *obj = model->getItem(id);
if (obj && obj->getIsLinkType())
{
return TRUE;
return true;
}
if (get_is_item_worn(id))
if (check_worn && get_is_item_worn(id, obj))
{
return FALSE;
return false;
}
return TRUE;
return true;
}
bool get_is_item_editable(const LLUUID& inv_item_id)
@ -805,6 +819,74 @@ BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id)
return TRUE;
}
bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn)
{
if (!get_is_category_removable(model, folder_id))
{
return false;
}
const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id))
{
return false;
}
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
model->collectDescendents(
folder_id,
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH);
if (check_worn)
{
for (LLInventoryModel::item_array_t::value_type& item : item_array)
{
// Disable delete/cut from COF folder; have users explicitly choose "detach/take off",
// unless the item is not worn but in the COF (i.e. is bugged).
if (item)
{
if (LLAppearanceMgr::instance().getIsProtectedCOFItem(item))
{
if (get_is_item_worn(item))
{
return false;
}
}
if (!item->getIsLinkType() && get_is_item_worn(item))
{
return false;
}
}
}
}
const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
LLViewerInventoryCategory* outfit_linked_category = base_outfit_link ? base_outfit_link->getLinkedCategory() : nullptr;
for (LLInventoryModel::cat_array_t::value_type& cat : cat_array)
{
const LLFolderType::EType folder_type = cat->getPreferredType();
if (LLFolderType::lookupIsProtectedType(folder_type))
{
return false;
}
// Can't delete the outfit that is currently being worn.
if (folder_type == LLFolderType::FT_OUTFIT)
{
if (cat == outfit_linked_category)
{
return false;
}
}
}
return true;
}
BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id)
{
if (!model)
@ -2759,7 +2841,7 @@ bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventory
{
if (item)
{
return !get_is_item_removable(&gInventory, item->getUUID());
return !get_is_item_removable(&gInventory, item->getUUID(), true);
}
if (cat)
{
@ -3024,6 +3106,8 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
{
const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
bool marketplacelistings_item = false;
bool has_worn = false;
bool needs_replacement = false;
LLAllDescendentsPassedFilter f;
for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(); (it != selected_items.end()) && (f.allDescendentsPassedFilter()); ++it)
{
@ -3032,14 +3116,69 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root
folder->applyFunctorRecursively(f);
}
LLFolderViewModelItemInventory * viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*it)->getViewModelItem());
if (viewModel && gInventory.isObjectDescendentOf(viewModel->getUUID(), marketplacelistings_id))
LLUUID obj_id = viewModel->getUUID();
if (viewModel && gInventory.isObjectDescendentOf(obj_id, marketplacelistings_id))
{
marketplacelistings_item = true;
break;
}
LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
if (cat)
{
LLInventoryModel::cat_array_t categories;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(obj_id, categories, items, FALSE);
for (LLInventoryModel::item_array_t::value_type& item : items)
{
if (get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
if (type == LLWearableType::WT_SHAPE
|| type == LLWearableType::WT_SKIN
|| type == LLWearableType::WT_HAIR
|| type == LLWearableType::WT_EYES)
{
needs_replacement = true;
break;
}
}
}
if (needs_replacement)
{
break;
}
}
LLViewerInventoryItem* item = gInventory.getItem(obj_id);
if (item && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
if (type == LLWearableType::WT_SHAPE
|| type == LLWearableType::WT_SKIN
|| type == LLWearableType::WT_HAIR
|| type == LLWearableType::WT_EYES)
{
needs_replacement = true;
break;
}
}
}
// Fall through to the generic confirmation if the user choose to ignore the specialized one
if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) )
if (needs_replacement)
{
LLNotificationsUtil::add("CantDeleteRequiredClothing");
}
else if (has_worn)
{
LLSD payload;
payload["has_worn"] = true;
LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
}
else if ( (!f.allDescendentsPassedFilter()) && !marketplacelistings_item && (!LLNotifications::instance().getIgnored("DeleteFilteredItems")) )
{
LLNotificationsUtil::add("DeleteFilteredItems", LLSD(), LLSD(), boost::bind(&LLInventoryAction::onItemsRemovalConfirmation, _1, _2, root->getHandle()));
}
@ -3362,11 +3501,81 @@ void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, con
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0 && !root.isDead() && !root.get()->isDead())
{
bool has_worn = notification["payload"]["has_worn"].asBoolean();
LLFolderView* folder_root = root.get();
//Need to remove item from DND before item is removed from root folder view
//because once removed from root folder view the item is no longer a selected item
removeItemFromDND(folder_root);
folder_root->removeSelectedItems();
// removeSelectedItems will change selection, collect worn items beforehand
uuid_vec_t worn;
uuid_vec_t item_deletion_list;
uuid_vec_t cat_deletion_list;
if (has_worn)
{
//Get selected items
LLFolderView::selected_items_t selectedItems = folder_root->getSelectedItems();
//If user is in DND and deletes item, make sure the notification is not displayed by removing the notification
//from DND history and .xml file. Once this is done, upon exit of DND mode the item deleted will not show a notification.
for (LLFolderView::selected_items_t::iterator it = selectedItems.begin(); it != selectedItems.end(); ++it)
{
LLFolderViewModelItemInventory* viewModel = dynamic_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem());
LLUUID obj_id = viewModel->getUUID();
LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
bool cat_has_worn = false;
if (cat)
{
LLInventoryModel::cat_array_t categories;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(obj_id, categories, items, FALSE);
for (LLInventoryModel::item_array_t::value_type& item : items)
{
if (get_is_item_worn(item))
{
worn.push_back(item->getUUID());
cat_has_worn = true;
}
}
if (cat_has_worn)
{
cat_deletion_list.push_back(obj_id);
}
}
LLViewerInventoryItem* item = gInventory.getItem(obj_id);
if (item && get_is_item_worn(item))
{
worn.push_back(obj_id);
item_deletion_list.push_back(obj_id);
}
}
}
// removeSelectedItems will check if items are worn before deletion,
// don't 'unwear' yet to prevent race conditions from unwearing
// and removing simultaneously
folder_root->removeSelectedItems();
// unwear then delete the rest
if (!worn.empty())
{
// should fire once after every item gets detached
LLAppearanceMgr::instance().removeItemsFromAvatar(worn,
[item_deletion_list, cat_deletion_list]()
{
for (const LLUUID& id : item_deletion_list)
{
remove_inventory_item(id, NULL);
}
for (const LLUUID& id : cat_deletion_list)
{
remove_inventory_category(id, NULL);
}
});
}
// Update the marketplace listings that have been affected by the operation
updateMarketplaceFolders();

View File

@ -47,17 +47,19 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id);
// Is this item or its baseitem is worn, attached, etc...
BOOL get_is_item_worn(const LLUUID& id);
BOOL get_is_item_worn(const LLViewerInventoryItem* item);
// Could this item be worn (correct type + not already being worn)
BOOL get_can_item_be_worn(const LLUUID& id);
BOOL get_is_item_removable(const LLInventoryModel* model, const LLUUID& id);
bool get_is_item_removable(const LLInventoryModel* model, const LLUUID& id, bool check_worn);
// Performs the appropiate edit action (if one exists) for this item
bool get_is_item_editable(const LLUUID& inv_item_id);
void handle_item_edit(const LLUUID& inv_item_id);
BOOL get_is_category_removable(const LLInventoryModel* model, const LLUUID& id);
bool get_is_category_and_children_removable(LLInventoryModel* model, const LLUUID& folder_id, bool check_worn);
BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id);

View File

@ -58,6 +58,7 @@
static LLPanelInjector<LLInventoryGallery> t_inventory_gallery("inventory_gallery");
const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;
const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value immediately
// Helper dnd functions
BOOL dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, BOOL drop, std::string& tooltip_msg, BOOL is_link);
@ -106,6 +107,7 @@ LLInventoryGallery::LLInventoryGallery(const LLInventoryGallery::Params& p)
mGalleryWidthFactor(p.gallery_width_factor),
mIsInitialized(false),
mRootDirty(false),
mLoadThumbnailsImmediately(true),
mNeedsArrange(false),
mSearchType(LLInventoryFilter::SEARCHTYPE_NAME),
mSortOrder(LLInventoryFilter::SO_DATE)
@ -540,6 +542,12 @@ void LLInventoryGallery::addToGallery(LLInventoryGalleryItem* item)
int n_prev = n - 1;
int row_count_prev = (n_prev % mItemsInRow) == 0 ? n_prev / mItemsInRow : n_prev / mItemsInRow + 1;
// Avoid loading too many items.
// Intent is for small folders to display all content fast
// and for large folders to load content mostly as needed
// Todo: ideally needs to unload images outside visible area
mLoadThumbnailsImmediately = mItemsAddedCount < FAST_LOAD_THUMBNAIL_TRSHOLD;
bool add_row = row_count != row_count_prev;
int pos = 0;
if (add_row)
@ -573,6 +581,8 @@ void LLInventoryGallery::removeFromGalleryLast(LLInventoryGalleryItem* item, boo
mItemsAddedCount--;
mIndexToItemMap.erase(mItemsAddedCount);
mLoadThumbnailsImmediately = mItemsAddedCount < FAST_LOAD_THUMBNAIL_TRSHOLD;
bool remove_row = row_count != row_count_prev;
removeFromLastRow(mItems[mItemsAddedCount]);
mItems.pop_back();
@ -636,6 +646,7 @@ LLInventoryGalleryItem* LLInventoryGallery::buildGalleryItem(std::string name, L
gitem->setUUID(item_id);
gitem->setGallery(this);
gitem->setType(type, inventory_type, flags, is_link);
gitem->setLoadImmediately(mLoadThumbnailsImmediately);
gitem->setThumbnail(thumbnail_id);
gitem->setWorn(is_worn);
gitem->setCreatorName(get_searchable_creator_name(&gInventory, item_id));
@ -997,6 +1008,7 @@ void LLInventoryGallery::updateItemThumbnail(LLUUID item_id)
if (mItemMap[item_id])
{
mItemMap[item_id]->setLoadImmediately(mLoadThumbnailsImmediately);
mItemMap[item_id]->setThumbnail(thumbnail_id);
bool passes_filter = checkAgainstFilters(mItemMap[item_id], mFilterSubString);
@ -1423,7 +1435,7 @@ void LLInventoryGallery::onFocusReceived()
LLInventoryGalleryItem* focus_item = NULL;
for (const LLUUID& id : mSelectedItemIDs)
{
if (mItemMap[id])
if (mItemMap[id] && !mItemMap[id]->isHidden())
{
focus_item = mItemMap[id];
focus_item->setSelected(true);
@ -1656,6 +1668,45 @@ void LLInventoryGallery::cut()
mFilterSubString.clear();
}
bool is_category_removable(const LLUUID& folder_id, bool check_worn)
{
if (!get_is_category_removable(&gInventory, folder_id))
{
return false;
}
// check children
LLInventoryModel::cat_array_t* cat_array;
LLInventoryModel::item_array_t* item_array;
gInventory.getDirectDescendentsOf(folder_id, cat_array, item_array);
for (LLInventoryModel::item_array_t::value_type& item : *item_array)
{
if (!get_is_item_removable(&gInventory, item->getUUID(), check_worn))
{
return false;
}
}
for (LLInventoryModel::cat_array_t::value_type& cat : *cat_array)
{
if (!is_category_removable(cat->getUUID(), check_worn))
{
return false;
}
}
const LLUUID mp_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
if (mp_id.notNull() && gInventory.isObjectDescendentOf(folder_id, mp_id))
{
return false;
}
return true;
}
BOOL LLInventoryGallery::canCut() const
{
if (!getVisible() || !getEnabled() || mSelectedItemIDs.empty())
@ -1668,12 +1719,12 @@ BOOL LLInventoryGallery::canCut() const
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
if (cat)
{
if (!get_is_category_removable(&gInventory, id))
if (!get_is_category_and_children_removable(&gInventory, id, true))
{
return FALSE;
}
}
else if (!get_is_item_removable(&gInventory, id))
else if (!get_is_item_removable(&gInventory, id, true))
{
return FALSE;
}
@ -1852,42 +1903,149 @@ void LLInventoryGallery::onDelete(const LLSD& notification, const LLSD& response
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
if (option == 0)
{
for (const LLUUID& id : selected_ids)
bool has_worn = notification["payload"]["has_worn"].asBoolean();
uuid_vec_t worn;
uuid_vec_t item_deletion_list;
uuid_vec_t cat_deletion_list;
for (const LLUUID& obj_id : selected_ids)
{
LLInventoryObject* obj = gInventory.getObject(id);
if (!obj)
LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
if (cat)
{
return;
}
if (obj->getType() == LLAssetType::AT_CATEGORY)
{
if (get_is_category_removable(&gInventory, id))
bool cat_has_worn = false;
if (has_worn)
{
gInventory.removeCategory(id);
LLInventoryModel::cat_array_t categories;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(obj_id, categories, items, FALSE);
for (LLInventoryModel::item_array_t::value_type& item : items)
{
if (get_is_item_worn(item))
{
worn.push_back(item->getUUID());
cat_has_worn = true;
}
}
}
if (cat_has_worn)
{
cat_deletion_list.push_back(obj_id);
}
else
{
gInventory.removeCategory(obj_id);
}
}
else
LLViewerInventoryItem* item = gInventory.getItem(obj_id);
if (item)
{
if (get_is_item_removable(&gInventory, id))
if (has_worn && get_is_item_worn(item))
{
gInventory.removeItem(id);
worn.push_back(item->getUUID());
item_deletion_list.push_back(item->getUUID());
}
else
{
gInventory.removeItem(obj_id);
}
}
}
if (!worn.empty())
{
// should fire once after every item gets detached
LLAppearanceMgr::instance().removeItemsFromAvatar(worn,
[item_deletion_list, cat_deletion_list]()
{
for (const LLUUID& id : item_deletion_list)
{
remove_inventory_item(id, NULL);
}
for (const LLUUID& id : cat_deletion_list)
{
remove_inventory_category(id, NULL);
}
});
}
}
}
void LLInventoryGallery::deleteSelection()
{
if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
bool has_worn = false;
bool needs_replacement = false;
for (const LLUUID& id : mSelectedItemIDs)
{
LLNotifications::instance().setIgnored("DeleteItems", false);
LLInventoryAction::sDeleteConfirmationDisplayed = true;
LLViewerInventoryCategory* cat = gInventory.getCategory(id);
if (cat)
{
LLInventoryModel::cat_array_t categories;
LLInventoryModel::item_array_t items;
gInventory.collectDescendents(id, categories, items, FALSE);
for (LLInventoryModel::item_array_t::value_type& item : items)
{
if (get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
if (type == LLWearableType::WT_SHAPE
|| type == LLWearableType::WT_SKIN
|| type == LLWearableType::WT_HAIR
|| type == LLWearableType::WT_EYES)
{
needs_replacement = true;
break;
}
}
}
if (needs_replacement)
{
break;
}
}
LLViewerInventoryItem* item = gInventory.getItem(id);
if (item && get_is_item_worn(item))
{
has_worn = true;
LLWearableType::EType type = item->getWearableType();
if (type == LLWearableType::WT_SHAPE
|| type == LLWearableType::WT_SKIN
|| type == LLWearableType::WT_HAIR
|| type == LLWearableType::WT_EYES)
{
needs_replacement = true;
break;
}
}
}
LLSD args;
args["QUESTION"] = LLTrans::getString("DeleteItem");
LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
if (needs_replacement)
{
LLNotificationsUtil::add("CantDeleteRequiredClothing");
}
else if (has_worn)
{
LLSD payload;
payload["has_worn"] = true;
LLNotificationsUtil::add("DeleteWornItems", LLSD(), payload, boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
}
else
{
if (!LLInventoryAction::sDeleteConfirmationDisplayed) // ask for the confirmation at least once per session
{
LLNotifications::instance().setIgnored("DeleteItems", false);
LLInventoryAction::sDeleteConfirmationDisplayed = true;
}
LLSD args;
args["QUESTION"] = LLTrans::getString("DeleteItem");
LLNotificationsUtil::add("DeleteItems", args, LLSD(), boost::bind(&LLInventoryGallery::onDelete, _1, _2, mSelectedItemIDs));
}
}
bool LLInventoryGallery::canDeleteSelection()
@ -1913,7 +2071,7 @@ bool LLInventoryGallery::canDeleteSelection()
return false;
}
}
else if (!get_is_item_removable(&gInventory, id))
else if (!get_is_item_removable(&gInventory, id, true))
{
return false;
}
@ -2557,6 +2715,7 @@ BOOL LLInventoryGalleryItem::postBuild()
{
mNameText = getChild<LLTextBox>("item_name");
mTextBgPanel = getChild<LLPanel>("text_bg_panel");
mThumbnailCtrl = getChild<LLThumbnailCtrl>("preview_thumbnail");
return TRUE;
}
@ -2632,14 +2791,19 @@ void LLInventoryGalleryItem::setThumbnail(LLUUID id)
mDefaultImage = id.isNull();
if(mDefaultImage)
{
getChild<LLThumbnailCtrl>("preview_thumbnail")->clearTexture();
mThumbnailCtrl->clearTexture();
}
else
{
getChild<LLThumbnailCtrl>("preview_thumbnail")->setValue(id);
mThumbnailCtrl->setValue(id);
}
}
void LLInventoryGalleryItem::setLoadImmediately(bool val)
{
mThumbnailCtrl->setInitImmediately(val);
}
void LLInventoryGalleryItem::draw()
{
if (isFadeItem())
@ -2654,7 +2818,7 @@ void LLInventoryGalleryItem::draw()
// Draw border
LLUIColor border_color = LLUIColorTable::instance().getColor(mSelected ? "MenuItemHighlightBgColor" : "TextFgTentativeColor", LLColor4::white);
LLRect border = getChildView("preview_thumbnail")->getRect();
LLRect border = mThumbnailCtrl->getRect();
border.mRight = border.mRight + 1;
border.mTop = border.mTop + 1;
gl_rect_2d(border, border_color.get(), FALSE);
@ -2876,7 +3040,7 @@ void LLInventoryGalleryItem::updateNameText()
mNameText->setFont(getTextFont());
mNameText->setText(mItemName + mPermSuffix + mWornSuffix);
mNameText->setToolTip(mItemName + mPermSuffix + mWornSuffix);
getChild<LLThumbnailCtrl>("preview_thumbnail")->setToolTip(mItemName + mPermSuffix + mWornSuffix);
mThumbnailCtrl->setToolTip(mItemName + mPermSuffix + mWornSuffix);
}
bool LLInventoryGalleryItem::isFadeItem()

View File

@ -39,6 +39,7 @@ class LLInventoryGalleryItem;
class LLScrollContainer;
class LLTextBox;
class LLThumbnailsObserver;
class LLThumbnailCtrl;
class LLGalleryGestureObserver;
class LLInventoryGalleryContextMenu;
@ -246,6 +247,7 @@ private:
int mRowCount;
int mItemsAddedCount;
bool mGalleryCreated;
bool mLoadThumbnailsImmediately;
bool mNeedsArrange;
/* Params */
@ -342,6 +344,7 @@ public:
LLAssetType::EType getAssetType() { return mType; }
void setThumbnail(LLUUID id);
void setGallery(LLInventoryGallery* gallery) { mGallery = gallery; }
void setLoadImmediately(bool val);
bool isFolder() { return mIsFolder; }
bool isLink() { return mIsLink; }
EInventorySortGroup getSortGroup() { return mSortGroup; }
@ -354,6 +357,7 @@ private:
LLUUID mUUID;
LLTextBox* mNameText;
LLPanel* mTextBgPanel;
LLThumbnailCtrl* mThumbnailCtrl;
bool mSelected;
bool mWorn;
bool mDefaultImage;

View File

@ -495,7 +495,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
}
items.push_back(std::string("Purge Item"));
if (is_folder && !get_is_category_removable(&gInventory, selected_id))
if (is_folder && !get_is_category_and_children_removable(&gInventory, selected_id, true))
{
disabled_items.push_back(std::string("Purge Item"));
}
@ -542,11 +542,16 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
}
items.push_back(std::string("Cut"));
items.push_back(std::string("Delete"));
if(!get_is_category_removable(&gInventory, selected_id))
if(!get_is_category_and_children_removable(&gInventory, selected_id, false))
{
disabled_items.push_back(std::string("Delete"));
disabled_items.push_back(std::string("Cut"));
}
else if (!get_is_category_and_children_removable(&gInventory, selected_id, true))
{
disabled_items.push_back(std::string("Cut"));
}
if(!is_inbox)
{
@ -577,11 +582,15 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men
{
items.push_back(std::string("Delete"));
}
if(!get_is_item_removable(&gInventory, selected_id))
if (!get_is_item_removable(&gInventory, selected_id, false))
{
disabled_items.push_back(std::string("Delete"));
disabled_items.push_back(std::string("Cut"));
}
else if(!get_is_item_removable(&gInventory, selected_id, true))
{
disabled_items.push_back(std::string("Cut"));
}
if (selected_item && (selected_item->getInventoryType() != LLInventoryType::IT_CALLINGCARD) && !is_inbox && selected_item->getPermissions().allowOperationBy(PERM_MODIFY, gAgent.getID()))
{

View File

@ -240,7 +240,7 @@ void LLInventoryItemsList::refresh()
case REFRESH_LIST_SORT:
{
// Filter, sort, rearrange and notify parent about shape changes
filterItems();
filterItems(true, true);
if (mAddedItems.size() == 0)
{

View File

@ -51,20 +51,20 @@ public:
/**
* Let list know items need to be refreshed in next doIdle()
*/
void setNeedsRefresh(bool needs_refresh){ mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; }
void setNeedsRefresh(bool needs_refresh) { mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; }
U32 getNeedsRefresh(){ return mRefreshState; }
U32 getNeedsRefresh() { return mRefreshState; }
/**
* Sets the flag indicating that the list needs to be refreshed even if it is
* not currently visible.
*/
void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; }
void setForceRefresh(bool force_refresh) { mForceRefresh = force_refresh; }
/**
* If refreshes when invisible.
*/
bool getForceRefresh(){ return mForceRefresh; }
bool getForceRefresh() { return mForceRefresh; }
virtual bool selectItemByValue(const LLSD& value, bool select = true);

View File

@ -1887,46 +1887,52 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
}
//static
void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL use_main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
void LLInventoryPanel::openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id,
bool use_main_panel, bool take_keyboard_focus, bool reset_filter)
{
LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
sidepanel_inventory->showInventoryPanel();
bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)));
if (!in_inbox && (use_main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
bool in_inbox = gInventory.isObjectDescendentOf(obj_id, cat_id);
if (!in_inbox && use_main_panel)
{
sidepanel_inventory->selectAllItemsPanel();
}
LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
if(!auto_open && inventory_floater && inventory_floater->getVisible())
if (!auto_open)
{
LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
if(main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
if (inventory_floater && inventory_floater->getVisible())
{
LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
main_panel->setGallerySelection(obj_id);
return;
LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
if (main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
{
LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
main_panel->setGallerySelection(obj_id);
return;
}
}
}
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && main_inventory->isSingleFolderMode()
&& use_main_panel)
if (use_main_panel)
{
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj)
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && main_inventory->isSingleFolderMode())
{
LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
main_inventory->setGallerySelection(obj_id);
return;
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj)
{
LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
main_inventory->setGallerySelection(obj_id);
return;
}
}
}
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
if (active_panel)
{
LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL;
@ -1938,11 +1944,8 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
if (in_inbox)
{
LLInventoryPanel * inventory_panel = NULL;
sidepanel_inventory->openInbox();
inventory_panel = sidepanel_inventory->getInboxPanel();
LLInventoryPanel* inventory_panel = sidepanel_inventory->getInboxPanel();
if (inventory_panel)
{
inventory_panel->setSelection(obj_id, take_keyboard_focus);
@ -1967,7 +1970,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
{
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)
{

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