diff --git a/doc/contributions.txt b/doc/contributions.txt index bcd60aa21c..f0b41298ee 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -225,6 +225,7 @@ Ansariel Hiller MAINT-8723 SL-10385 SL-10891 + SL-10675 SL-13364 SL-13858 SL-13697 @@ -827,6 +828,7 @@ Jonathan Yap Kadah Coba STORM-1060 STORM-1843 + SL-10675 Jondan Lundquist Joosten Briebers MAINT-7074 diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index cf42793d3a..f3a38fc52e 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -276,6 +276,7 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) mMinHeight(p.min_height), mHeaderHeight(p.header_height), mLegacyHeaderHeight(p.legacy_header_height), + mDefaultRectForGroup(true), mMinimized(FALSE), mForeground(FALSE), mFirstLook(TRUE), @@ -994,7 +995,10 @@ bool LLFloater::applyRectControl() // // other floaters in our group, position ourselves relative to them and don't save the rect - mRectControl.clear(); + if (mDefaultRectForGroup) + { + mRectControl.clear(); + } mPositioning = LLFloaterEnums::POSITIONING_CASCADE_GROUP; } else @@ -3854,8 +3858,15 @@ void LLFloater::stackWith(LLFloater& other) } next_rect.translate(floater_offset, -floater_offset); - next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); - + const LLRect& rect = getControlGroup()->getRect(mRectControl); + if (rect.notEmpty() && !mDefaultRectForGroup && mResizable) + { + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + } + else + { + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, getRect().getWidth(), getRect().getHeight()); + } setShape(next_rect); if (!other.getHost()) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 9dfab9f8e1..ea8ca8ea95 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -477,6 +477,7 @@ public: protected: bool mSaveRect; + bool mDefaultRectForGroup; std::string mRectControl; std::string mPosXControl; std::string mPosYControl; diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 82b01e705d..e01aba402e 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -35,6 +35,7 @@ #include "llui.h" #include "lluictrlfactory.h" #include "lluiimage.h" +#include "llwindow.h" static LLDefaultChildRegistry::Register r("icon"); @@ -42,6 +43,7 @@ LLIconCtrl::Params::Params() : image("image_name"), color("color"), use_draw_context_alpha("use_draw_context_alpha", true), + interactable("interactable", false), scale_image("scale_image"), min_width("min_width", 0), min_height("min_height", 0) @@ -52,6 +54,7 @@ LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) mColor(p.color()), mImagep(p.image), mUseDrawContextAlpha(p.use_draw_context_alpha), + mInteractable(p.interactable), mPriority(0), mMinWidth(p.min_width), mMinHeight(p.min_height), @@ -81,6 +84,16 @@ void LLIconCtrl::draw() LLUICtrl::draw(); } +BOOL LLIconCtrl::handleHover(S32 x, S32 y, MASK mask) +{ + if (mInteractable && getEnabled()) + { + getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; + } + return LLUICtrl::handleHover(x, y, mask); +} + // virtual // value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value) diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index dd83e78fd3..9c3b517bca 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -48,7 +48,8 @@ public: { Optional image; Optional color; - Optional use_draw_context_alpha; + Optional use_draw_context_alpha, + interactable; Optional min_width, min_height; Ignored scale_image; @@ -67,6 +68,9 @@ public: // llview overrides virtual void draw(); + // llview overrides + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + // lluictrl overrides virtual void setValue(const LLSD& value ); @@ -88,6 +92,7 @@ protected: // If set to true (default), use the draw context transparency. // If false, will use transparency returned by getCurrentTransparency(). See STORM-698. bool mUseDrawContextAlpha; + bool mInteractable; private: LLUIColor mColor; diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 303afcda15..583704418b 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -40,6 +40,7 @@ void LLMenuButton::MenuPositions::declareValues() declare("topleft", MP_TOP_LEFT); declare("topright", MP_TOP_RIGHT); declare("bottomleft", MP_BOTTOM_LEFT); + declare("bottomright", MP_BOTTOM_RIGHT); } LLMenuButton::Params::Params() @@ -212,6 +213,13 @@ void LLMenuButton::updateMenuOrigin() mY = rect.mBottom; break; } + case MP_BOTTOM_RIGHT: + { + const LLRect& menu_rect = menu->getRect(); + mX = rect.mRight - menu_rect.getWidth(); + mY = rect.mBottom; + break; + } } } diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 67ec1983b3..e42f8f53bd 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -41,7 +41,8 @@ public: { MP_TOP_LEFT, MP_TOP_RIGHT, - MP_BOTTOM_LEFT + MP_BOTTOM_LEFT, + MP_BOTTOM_RIGHT } EMenuPosition; struct MenuPositions diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index cc6b4a6beb..0a04ae36ac 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -431,12 +431,13 @@ void LLTabContainer::draw() S32 cur_scroll_pos = getScrollPos(); if (cur_scroll_pos > 0) { -// S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - if (!mIsVertical) + if (mIsVertical) + { + target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad); + } + else { -// [SL:KB] - Patch: Control-TabContainer | Checked: 2014-03-17 (Catznip-3.6) S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); -// [/SL:KB] for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { if (cur_scroll_pos == 0) @@ -455,12 +456,6 @@ void LLTabContainer::draw() // clamp so that rightmost tab never leaves right side of screen target_pixel_scroll = llmin(mTotalTabWidth - available_width_with_arrows, target_pixel_scroll); } -// [SL:KB] - Patch: Control-TabContainer | Checked: 2014-03-17 (Catznip-3.6) - else - { - target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad); - } -// [/SL:KB] } // [SL:KB] - Patch: Control-TabContainer | Checked: 2014-03-17 (Catznip-3.6) @@ -1339,16 +1334,15 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) sendChildToFront(mNextArrowBtn); sendChildToFront(mJumpPrevArrowBtn); sendChildToFront(mJumpNextArrowBtn); - - if( select ) - { -// [SL:KB] - Patch: Control-TabContainer | Checked: 2012-08-10 (Catznip-3.3) - selectTabPanel(child); -// [/SL:KB] -// selectLastTab(); - } updateMaxScrollPos(); + + if( select ) + { + selectLastTab(); + mScrollPos = mMaxScrollPos; + } + } void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label) @@ -2331,9 +2325,9 @@ void LLTabContainer::updateMaxScrollPos() if( tab_total_height > available_height ) { static LLUICachedControl tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); - S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad); + S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom; S32 additional_needed = tab_total_height - available_height_with_arrows; - setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) ); + setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) ); no_scroll = FALSE; } } diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index b74f2bf00a..d8bd718da5 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -182,6 +182,7 @@ LLTextBase::Params::Params() font_shadow("font_shadow"), wrap("wrap"), trusted_content("trusted_content", true), + always_show_icons("always_show_icons", false), use_ellipses("use_ellipses", false), // Optional icon position icon_positioning("icon_positioning", LLTextBaseEnums::RIGHT), @@ -237,6 +238,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mClip(p.clip), mClipPartial(p.clip_partial && !p.allow_scroll), mTrustedContent(p.trusted_content), + mAlwaysShowIcons(p.always_show_icons), mTrackEnd( p.track_end ), mScrollIndex(-1), mSelectionStart( 0 ), @@ -523,8 +525,48 @@ void LLTextBase::drawHighlightsBackground(const highlight_list_t& highlights, co ++rect_it) { LLRect selection_rect = *rect_it; - selection_rect = *rect_it; - selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); + if (mScroller) + { + // If scroller is On content_display_rect has correct rect and safe to use as is + // Note: we might need to account for border + selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); + } + else + { + // If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position + // and we have to acount for offset depending on position + S32 v_delta = 0; + S32 h_delta = 0; + switch (mVAlign) + { + case LLFontGL::TOP: + v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad; + break; + case LLFontGL::VCENTER: + v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2; + break; + case LLFontGL::BOTTOM: + v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom; + break; + default: + break; + } + switch (mHAlign) + { + case LLFontGL::LEFT: + h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad; + break; + case LLFontGL::HCENTER: + h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2; + break; + case LLFontGL::RIGHT: + h_delta = mVisibleTextRect.mRight - content_display_rect.mRight; + break; + default: + break; + } + selection_rect.translate(h_delta, v_delta); + } gl_rect_2d(selection_rect, selection_color); } } @@ -2285,7 +2327,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para LLUrlMatch match; std::string text = new_text; while ( LLUrlRegistry::instance().findUrl(text, match, - boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted())) + boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons)) { start = match.getStart(); end = match.getEnd()+1; @@ -2317,14 +2359,14 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para // add icon before url if need // Optional icon position - //LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); + //LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons); //if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) //{ // setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); //} - if (mIconPositioning == LLTextBaseEnums::LEFT || match.isTrusted()) + if (mIconPositioning == LLTextBaseEnums::LEFT || match.isTrusted() || mAlwaysShowIcons) { - LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); + LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted() || mAlwaysShowIcons); if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) { setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); @@ -2368,7 +2410,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } // Optional icon position - if (mIconPositioning == LLTextBaseEnums::RIGHT && !match.isTrusted()) + if (mIconPositioning == LLTextBaseEnums::RIGHT && !match.isTrusted() && !mAlwaysShowIcons) { LLTextUtil::processUrlMatch(&match,this,isContentTrusted()); } diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 27004be3f6..de3d766acc 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -345,7 +345,8 @@ public: parse_highlights, clip, clip_partial, - trusted_content; + trusted_content, + always_show_icons; Optional v_pad, h_pad; @@ -396,9 +397,7 @@ public: virtual void onFocusReceived(); virtual void onFocusLost(); -// - void setParseHTML(bool parse_html) { mParseHTML = parse_html; } -// + void setParseHTML(bool parse_html) { mParseHTML = parse_html; } // LLSpellCheckMenuHandler overrides /*virtual*/ bool getSpellCheck() const; @@ -764,6 +763,8 @@ protected: bool mAutoIndent; S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes bool mSkipTripleClick; + bool mAlwaysShowIcons; + bool mSkipLinkUnderline; // support widgets diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8165fe5070..88daec8951 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -174,7 +174,6 @@ set(viewer_SOURCE_FILES fsfloaterpartialinventory.cpp fsfloaterplacedetails.cpp fsfloaterposestand.cpp - fsfloaterprofile.cpp fsfloaterprotectedfolders.cpp fsfloaterradar.cpp fsfloatersearch.cpp @@ -196,13 +195,10 @@ set(viewer_SOURCE_FILES fsnearbychathub.cpp fsnearbychatvoicemonitor.cpp fspanelblocklist.cpp - fspanelclassified.cpp fspanelcontactsets.cpp fspanelimcontrolpanel.cpp fspanellogin.cpp fspanelprefs.cpp - fspanelprofile.cpp - fspanelprofileclassifieds.cpp fspanelradar.cpp fsparticipantlist.cpp fspose.cpp @@ -349,6 +345,7 @@ set(viewer_SOURCE_FILES llfloatercamera.cpp llfloatercamerapresets.cpp llfloaterchatvoicevolume.cpp + llfloaterclassified.cpp llfloatercolorpicker.cpp llfloaterconversationlog.cpp llfloaterconversationpreview.cpp @@ -413,10 +410,12 @@ set(viewer_SOURCE_FILES fsfloaterperformance.cpp llfloaterperms.cpp llfloaterpostprocess.cpp + llfloaterprofile.cpp llfloaterpreference.cpp # llfloaterpreferencesgraphicsadvanced.cpp llfloaterpreferenceviewadvanced.cpp llfloaterpreviewtrash.cpp + llfloaterprofiletexture.cpp llfloaterproperties.cpp llfloaterregiondebugconsole.cpp llfloaterregioninfo.cpp @@ -450,7 +449,6 @@ set(viewer_SOURCE_FILES llfloatervoiceeffect.cpp llfloatervoicevolume.cpp llfloaterwebcontent.cpp - llfloaterwebprofile.cpp llfloaterwhitelistentry.cpp llfloaterwindowsize.cpp llfloaterworldmap.cpp @@ -599,7 +597,6 @@ set(viewer_SOURCE_FILES llpanelmediasettingsgeneral.cpp llpanelmediasettingspermissions.cpp llpanelmediasettingssecurity.cpp - llpanelme.cpp llpanelnearbymedia.cpp llpanelobject.cpp llpanelobjectinventory.cpp @@ -609,8 +606,6 @@ set(viewer_SOURCE_FILES llpanelpeople.cpp llpanelpeoplemenus.cpp llpanelpermissions.cpp - llpanelpick.cpp - llpanelpicks.cpp llpanelplaceinfo.cpp llpanelplaceprofile.cpp llpanelplaces.cpp @@ -619,6 +614,8 @@ set(viewer_SOURCE_FILES llpanelpresetspulldown.cpp llpanelprimmediacontrols.cpp llpanelprofile.cpp + llpanelprofileclassifieds.cpp + llpanelprofilepicks.cpp llpanelsnapshot.cpp llpanelsnapshotinventory.cpp llpanelsnapshotlocal.cpp @@ -955,7 +952,6 @@ set(viewer_HEADER_FILES fsfloaterpartialinventory.h fsfloaterplacedetails.h fsfloaterposestand.h - fsfloaterprofile.h fsfloaterprotectedfolders.h fsfloaterradar.h fsfloatersearch.h @@ -979,12 +975,9 @@ set(viewer_HEADER_FILES fsnearbychatvoicemonitor.h fspanelblocklist.h fspanelcontactsets.h - fspanelclassified.h fspanelimcontrolpanel.h fspanellogin.h fspanelprefs.h - fspanelprofile.h - fspanelprofileclassifieds.h fspanelradar.h fsparticipantlist.h fspose.h @@ -1133,6 +1126,7 @@ set(viewer_HEADER_FILES llfloatercamerapresets.h llfloatercamera.h llfloaterchatvoicevolume.h + llfloaterclassified.h llfloatercolorpicker.h llfloaterconversationlog.h llfloaterconversationpreview.h @@ -1200,10 +1194,12 @@ set(viewer_HEADER_FILES fsfloaterperformance.h llfloaterperms.h llfloaterpostprocess.h + llfloaterprofile.h llfloaterpreference.h # llfloaterpreferencesgraphicsadvanced.h llfloaterpreferenceviewadvanced.h llfloaterpreviewtrash.h + llfloaterprofiletexture.h llfloaterproperties.h llfloaterregiondebugconsole.h llfloaterregioninfo.h @@ -1237,7 +1233,6 @@ set(viewer_HEADER_FILES llfloatervoiceeffect.h llfloatervoicevolume.h llfloaterwebcontent.h - llfloaterwebprofile.h llfloaterwhitelistentry.h llfloaterwindowsize.h llfloaterworldmap.h @@ -1376,7 +1371,6 @@ set(viewer_HEADER_FILES llpanelmediasettingsgeneral.h llpanelmediasettingspermissions.h llpanelmediasettingssecurity.h - llpanelme.h llpanelnearbymedia.h llpanelobject.h llpanelobjectinventory.h @@ -1386,8 +1380,6 @@ set(viewer_HEADER_FILES llpanelpeople.h llpanelpeoplemenus.h llpanelpermissions.h - llpanelpick.h - llpanelpicks.h llpanelplaceinfo.h llpanelplaceprofile.h llpanelplaces.h @@ -1396,6 +1388,8 @@ set(viewer_HEADER_FILES llpanelpresetspulldown.h llpanelprimmediacontrols.h llpanelprofile.h + llpanelprofileclassifieds.h + llpanelprofilepicks.h llpanelsnapshot.h llpanelteleporthistory.h llpaneltiptoast.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index d31cf19a55..6c902f1eb2 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -179,10 +179,8 @@ icon="Command_Picks_Icon" label_ref="Command_Picks_Label" tooltip_ref="Command_Picks_Tooltip" - execute_function="Floater.Toggle" - execute_parameters="picks" - is_running_function="Floater.IsOpen" - is_running_parameters="picks" + execute_function="Avatar.TogglePicks" + is_running_function="Avatar.IsPicksTabOpen" /> Value 0 - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - FSTPHistoryTZ Comment diff --git a/indra/newview/app_settings/settings_firestorm.xml b/indra/newview/app_settings/settings_firestorm.xml index 7155de5791..61d0229fee 100644 --- a/indra/newview/app_settings/settings_firestorm.xml +++ b/indra/newview/app_settings/settings_firestorm.xml @@ -243,18 +243,6 @@ 1 - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - - FSFolderViewItemHeight Comment diff --git a/indra/newview/app_settings/settings_hybrid.xml b/indra/newview/app_settings/settings_hybrid.xml index d276eea8ae..740041322a 100644 --- a/indra/newview/app_settings/settings_hybrid.xml +++ b/indra/newview/app_settings/settings_hybrid.xml @@ -219,18 +219,6 @@ 1 - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - - FSFolderViewItemHeight Comment diff --git a/indra/newview/app_settings/settings_phoenix.xml b/indra/newview/app_settings/settings_phoenix.xml index 08180920ef..8b9ade85b9 100644 --- a/indra/newview/app_settings/settings_phoenix.xml +++ b/indra/newview/app_settings/settings_phoenix.xml @@ -231,18 +231,6 @@ 1 - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - - FSFolderViewItemHeight Comment diff --git a/indra/newview/app_settings/settings_text.xml b/indra/newview/app_settings/settings_text.xml index 393ec2e00e..5fe6615319 100644 --- a/indra/newview/app_settings/settings_text.xml +++ b/indra/newview/app_settings/settings_text.xml @@ -207,18 +207,6 @@ 1 - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 0 - - FSFolderViewItemHeight Comment diff --git a/indra/newview/app_settings/settings_v3.xml b/indra/newview/app_settings/settings_v3.xml index 6c89031e12..6b42c8f47a 100644 --- a/indra/newview/app_settings/settings_v3.xml +++ b/indra/newview/app_settings/settings_v3.xml @@ -254,18 +254,6 @@ Value 0 - - FSUseWebProfiles - - Comment - Shows web profiles instead of the v1-style profile floater - Persist - 1 - Type - Boolean - Value - 1 - FSFontChatLineSpacingPixels diff --git a/indra/newview/fsdispatchclassifiedclickthrough.h b/indra/newview/fsdispatchclassifiedclickthrough.h index aa85b653d6..0816a74e79 100644 --- a/indra/newview/fsdispatchclassifiedclickthrough.h +++ b/indra/newview/fsdispatchclassifiedclickthrough.h @@ -28,7 +28,7 @@ #ifndef FS_DISPATCHCLASSIFIEDCLICKTHROUGH_H #define FS_DISPATCHCLASSIFIEDCLICKTHROUGH_H -#include "fspanelclassified.h" +#include "llpanelprofileclassifieds.h" #include "lldispatcher.h" // "classifiedclickthrough" @@ -51,7 +51,7 @@ public: S32 map_clicks = atoi(strings[2].c_str()); S32 profile_clicks = atoi(strings[3].c_str()); - FSPanelClassifiedInfo::setClickThrough( + LLPanelProfileClassified::setClickThrough( classified_id, teleport_clicks, map_clicks, profile_clicks, false); return true; diff --git a/indra/newview/fsdroptarget.cpp b/indra/newview/fsdroptarget.cpp index 99957ed6d7..8e6a4bcf5f 100644 --- a/indra/newview/fsdroptarget.cpp +++ b/indra/newview/fsdroptarget.cpp @@ -34,7 +34,6 @@ #include "llviewerinventory.h" static LLDefaultChildRegistry::Register r1("fs_copytrans_inventory_drop_target"); -static LLDefaultChildRegistry::Register r2("profile_drop_target"); static LLDefaultChildRegistry::Register r3("fs_embedded_item_drop_target"); @@ -70,29 +69,6 @@ BOOL FSCopyTransInventoryDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, return TRUE; } - -FSDropTarget::FSDropTarget(const FSDropTarget::Params& p) - : LLView(p), - mAgentID(p.agent_id) -{} - -BOOL FSDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - if (getParent()) - { - LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop, - cargo_type, cargo_data, accept); - - return TRUE; - } - - return FALSE; -} - BOOL FSEmbeddedItemDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, diff --git a/indra/newview/fsdroptarget.h b/indra/newview/fsdroptarget.h index f676cc4eb8..a5cc32fb3f 100644 --- a/indra/newview/fsdroptarget.h +++ b/indra/newview/fsdroptarget.h @@ -70,37 +70,6 @@ private: }; -class FSDropTarget : public LLView -{ -public: - struct Params : public LLInitParam::Block - { - Optional agent_id; - Params() - : agent_id("agent_id") - { - changeDefault(mouse_opaque, false); - changeDefault(follows.flags, FOLLOWS_ALL); - } - }; - - FSDropTarget(const Params&); - ~FSDropTarget() {} - - // LLView functionality - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - void setAgentID(const LLUUID &agent_id) { mAgentID = agent_id; } - -protected: - LLUUID mAgentID; -}; - - class FSEmbeddedItemDropTarget : public LLTextBox { public: diff --git a/indra/newview/fsfloaterplacedetails.cpp b/indra/newview/fsfloaterplacedetails.cpp index 12c025f537..8eb45a8aac 100644 --- a/indra/newview/fsfloaterplacedetails.cpp +++ b/indra/newview/fsfloaterplacedetails.cpp @@ -46,7 +46,6 @@ #include "lllandmarkactions.h" #include "lllandmarklist.h" #include "llnotificationsutil.h" -#include "llpanelpick.h" #include "llpanelplaceprofile.h" #include "llpanellandmarkinfo.h" #include "llparcel.h" @@ -191,8 +190,7 @@ FSFloaterPlaceDetails::FSFloaterPlaceDetails(const LLSD& seed) mIsInEditMode(false), mIsInCreateMode(false), mGlobalPos(), - mDisplayInfo(NONE), - mPickPanel(NULL) + mDisplayInfo(NONE) { mParcelObserver = new FSPlaceDetailsPlacesParcelObserver(this); mRemoteParcelObserver = new FSPlaceDetailsRemoteParcelInfoObserver(this); @@ -566,14 +564,6 @@ void FSFloaterPlaceDetails::setItem(LLInventoryItem* item) } } -void FSFloaterPlaceDetails::togglePickPanel(BOOL visible) -{ - if (mPickPanel) - { - mPickPanel->setVisible(visible); - } -} - // static void FSFloaterPlaceDetails::showPlaceDetails(const LLSD& key) { @@ -785,19 +775,6 @@ void FSFloaterPlaceDetails::onOverflowMenuItemClicked(const LLSD& param) } else if (item == "pick") { - if (mPickPanel == NULL) - { - mPickPanel = LLPanelPickEdit::create(); - addChild(mPickPanel); - - mPickPanel->setExitCallback(boost::bind(&FSFloaterPlaceDetails::togglePickPanel, this, FALSE)); - mPickPanel->setCancelCallback(boost::bind(&FSFloaterPlaceDetails::togglePickPanel, this, FALSE)); - mPickPanel->setSaveCallback(boost::bind(&FSFloaterPlaceDetails::togglePickPanel, this, FALSE)); - } - - togglePickPanel(TRUE); - mPickPanel->onOpen(LLSD()); - LLPanelPlaceInfo* panel = mPanelPlaceInfo; if (mDisplayInfo == LANDMARK) { @@ -806,11 +783,7 @@ void FSFloaterPlaceDetails::onOverflowMenuItemClicked(const LLSD& param) if (panel) { - panel->createPick(mGlobalPos, mPickPanel); - - LLRect rect = panel->getRect(); - mPickPanel->reshape(rect.getWidth(), rect.getHeight()); - mPickPanel->setRect(rect); + panel->createPick(mGlobalPos); } } else if (item == "add_to_favbar") diff --git a/indra/newview/fsfloaterplacedetails.h b/indra/newview/fsfloaterplacedetails.h index d25eeae55c..c86f5b0ee0 100644 --- a/indra/newview/fsfloaterplacedetails.h +++ b/indra/newview/fsfloaterplacedetails.h @@ -39,7 +39,6 @@ class LLLandmark; class LLMenuButton; class LLPanelLandmarkInfo; -class LLPanelPickEdit; class LLPanelPlaceProfile; struct LLParcelData; class LLToggleableMenu; @@ -61,7 +60,6 @@ public: void changedGlobalPos(const LLVector3d& global_pos); void changedParcelSelection(); void processParcelDetails(const LLParcelData& parcel_details); - void togglePickPanel(BOOL visible); static void showPlaceDetails(const LLSD& key); @@ -95,7 +93,6 @@ private: void setItem(LLInventoryItem* item); void onSLURLBuilt(std::string& slurl); - LLPanelPickEdit* mPickPanel; LLPanelLandmarkInfo* mPanelLandmarkInfo; LLPanelPlaceProfile* mPanelPlaceInfo; diff --git a/indra/newview/fsfloaterprofile.cpp b/indra/newview/fsfloaterprofile.cpp deleted file mode 100644 index 4249e45e7a..0000000000 --- a/indra/newview/fsfloaterprofile.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file fsfloaterprofile.cpp - * @brief Legacy Profile Floater - * - * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2012, Kadah Coba - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "fsfloaterprofile.h" - -#include "fspanelprofile.h" -#include "llagent.h" //gAgent - -static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; - -FSFloaterProfile::FSFloaterProfile(const LLSD& key) - : LLFloater(key), - mAvatarId(key["id"].asUUID()), - mNameCallbackConnection() -{ -} - -FSFloaterProfile::~FSFloaterProfile() -{ - if (mNameCallbackConnection.connected()) - { - mNameCallbackConnection.disconnect(); - } -} - -void FSFloaterProfile::onOpen(const LLSD& key) -{ - FSPanelProfile* panel_profile = findChild(PANEL_PROFILE_VIEW); - panel_profile->onOpen(mAvatarId); - - if (mAvatarId == gAgentID) - { - getChild("ok_btn")->setVisible(TRUE); - getChild("cancel_btn")->setVisible(TRUE); - } - - // Update the avatar name. - mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&FSFloaterProfile::onAvatarNameCache, this, _1, _2)); -} - -BOOL FSFloaterProfile::postBuild() -{ - childSetAction("ok_btn", boost::bind(&FSFloaterProfile::onOKBtn, this)); - childSetAction("cancel_btn", boost::bind(&FSFloaterProfile::onCancelBtn, this)); - - return TRUE; -} - -void FSFloaterProfile::onOKBtn() -{ - if (mAvatarId == gAgentID) - { - FSPanelProfile* panel_profile = findChild(PANEL_PROFILE_VIEW); - panel_profile->apply(); - } - - closeFloater(); -} - -void FSFloaterProfile::onCancelBtn() -{ - closeFloater(); -} - -void FSFloaterProfile::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - mNameCallbackConnection.disconnect(); - setTitle(av_name.getCompleteName()); -} - -// eof diff --git a/indra/newview/fsfloaterprofile.h b/indra/newview/fsfloaterprofile.h deleted file mode 100644 index de96ce851b..0000000000 --- a/indra/newview/fsfloaterprofile.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file fsfloaterprofile.h - * @brief Legacy Profile Floater - * - * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2012, Kadah Coba - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ - -#ifndef FS_FLOATERPROFILE_H -#define FS_FLOATERPROFILE_H - -#include "llavatarnamecache.h" -#include "llfloater.h" - -class FSFloaterProfile : public LLFloater -{ - LOG_CLASS(FSFloaterProfile); -public: - FSFloaterProfile(const LLSD& key); - virtual ~FSFloaterProfile(); - - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ BOOL postBuild(); - -protected: - void onOKBtn(); - void onCancelBtn(); - -private: - LLAvatarNameCache::callback_connection_t mNameCallbackConnection; - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - - LLUUID mAvatarId; -}; - -#endif // FS_FLOATERPROFILE_H diff --git a/indra/newview/fsfloatersearch.cpp b/indra/newview/fsfloatersearch.cpp index d4b308c727..3379508eee 100644 --- a/indra/newview/fsfloatersearch.cpp +++ b/indra/newview/fsfloatersearch.cpp @@ -31,8 +31,6 @@ #include "fsavatarsearchmenu.h" #include "fsdispatchclassifiedclickthrough.h" -#include "fspanelclassified.h" -#include "fspanelprofile.h" #include "fsscrolllistctrl.h" #include "lfsimfeaturehandler.h" #include "llagent.h" @@ -53,7 +51,8 @@ #include "llloadingindicator.h" #include "lllogininstance.h" #include "llnotificationsutil.h" -#include "llpanelclassified.h" +#include "llpanelprofile.h" +#include "llpanelprofileclassifieds.h" #include "llparcel.h" #include "llproductinforequest.h" #include "llqueryflags.h" @@ -183,7 +182,7 @@ public: LL_INFOS("Search") << "Classified stat request via capability" << LL_ENDL; LLSD body; body["classified_id"] = c_info->classified_id; - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, c_info->classified_id, _1)); + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, boost::bind(&LLPanelProfileClassified::handleSearchStatResponse, c_info->classified_id, _1)); } } } @@ -309,15 +308,6 @@ BOOL FSFloaterSearch::postBuild() mPanelClassifieds = findChild("panel_ls_classifieds"); mPanelWeb = findChild("panel_ls_web"); - // If skin has legacy full profile view, use it - mPanelProfile = mPanelPeople->findChild("panel_profile_view"); - if (mPanelProfile) - { - mPanelProfile->setVisible(false); - mPanelProfile->setEmbedded(true); - mPanelPeople->childSetAction("people_profile_btn", boost::bind(&FSFloaterSearch::onBtnPeopleProfile, this)); - } - mDetailsPanel = getChild("panel_ls_details"); mDetailTitle = getChild("title"); mDetailDesc = getChild("desc"); @@ -354,12 +344,7 @@ void FSFloaterSearch::onTabChange() mDetailsPanel->setVisible(false); mPanelWeb->resetFocusOnLoad(); } - // If on legacy people search and skin uses full profile preview, hide preview panel - else if (active_panel == mPanelPeople && mPanelProfile) - { - mDetailsPanel->setVisible(false); - } - else + else if (active_panel == mPanelPeople) { mDetailsPanel->setVisible(mHasSelection); } @@ -402,19 +387,8 @@ void FSFloaterSearch::onSelectedItem(const LLUUID& selected_item, ESearchCategor switch (type) { case SC_AVATAR: - { - // If skin has legacy full profile view, use it - if (mPanelProfile) - { - mPanelProfile->setVisible(true); - mPanelProfile->onOpen(selected_item); - } - else - { - LLAvatarPropertiesProcessor::getInstance()->addObserver(selected_item, mAvatarPropertiesObserver); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(selected_item); - } - } + LLAvatarPropertiesProcessor::getInstance()->addObserver(selected_item, mAvatarPropertiesObserver); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(selected_item); break; case SC_GROUP: mGroupPropertiesRequest = new FSSearchGroupInfoObserver(selected_item, this); diff --git a/indra/newview/fsfloatersearch.h b/indra/newview/fsfloatersearch.h index 8ef70656e7..35158980d0 100644 --- a/indra/newview/fsfloatersearch.h +++ b/indra/newview/fsfloatersearch.h @@ -48,7 +48,7 @@ class LLGroupMgrObserver; class LLSearchEditor; class LLSearchComboBox; class FSFloaterSearch; -class FSPanelProfile; +class LLPanelProfile; class FSScrollListCtrl; struct SearchQuery : public LLInitParam::Block @@ -412,7 +412,6 @@ private: LLTextureCtrl* mDetailSnapshotParcel; LLIconCtrl* mDetailMaturity; LLTabContainer* mTabContainer; - FSPanelProfile* mPanelProfile; }; #endif // FS_FLOATERSEARCH_H diff --git a/indra/newview/fspanelclassified.cpp b/indra/newview/fspanelclassified.cpp deleted file mode 100644 index 034fef0903..0000000000 --- a/indra/newview/fspanelclassified.cpp +++ /dev/null @@ -1,1157 +0,0 @@ -/** - * @file fspanelclassified.cpp - * @brief FSPanelClassified class implementation - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Display of a classified used both for the global view in the -// Find directory, and also for each individual user's classified in their -// profile. - -#include "llviewerprecompiledheaders.h" - -#include "fspanelclassified.h" - -#include "llfloaterreg.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llparcel.h" - -#include "fsdispatchclassifiedclickthrough.h" -#include "llagent.h" -#include "llclassifiedflags.h" -#include "lliconctrl.h" -#include "lllineeditor.h" -#include "llcombobox.h" -#include "lltexturectrl.h" -#include "lltexteditor.h" -#include "llviewerparcelmgr.h" -#include "llfloaterworldmap.h" -#include "llviewergenericmessage.h" // send_generic_message -#include "llviewerregion.h" -#include "lltrans.h" -#include "llscrollcontainer.h" -#include "llstatusbar.h" -#include "llviewertexture.h" -#include "llpanelclassified.h" - -#ifdef OPENSIM -#include "llviewernetwork.h" -#endif // OPENSIM - -const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ - -//static -FSPanelClassifiedInfo::panel_list_t FSPanelClassifiedInfo::sAllPanels; - -static FSDispatchClassifiedClickThrough sClassifiedClickThrough; - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelClassifiedInfo::FSPanelClassifiedInfo() - : LLPanel() - , mInfoLoaded(false) - , mScrollingPanel(NULL) - , mScrollContainer(NULL) - , mScrollingPanelMinHeight(0) - , mScrollingPanelWidth(0) - , mSnapshotStreched(false) - , mTeleportClicksOld(0) - , mMapClicksOld(0) - , mProfileClicksOld(0) - , mTeleportClicksNew(0) - , mMapClicksNew(0) - , mProfileClicksNew(0) - , mSnapshotCtrl(NULL) -{ - sAllPanels.push_back(this); -} - -FSPanelClassifiedInfo::~FSPanelClassifiedInfo() -{ - sAllPanels.remove(this); -// [SL:KB] - Patch : UI-ProfileGroupFloater | Checked: 2010-11-28 (Catznip-2.4.0g) | Added: Catznip-2.4.0g - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - } -// [/SL:KB] -} - -// static -FSPanelClassifiedInfo* FSPanelClassifiedInfo::create() -{ - FSPanelClassifiedInfo* panel = new FSPanelClassifiedInfo(); - panel->buildFromFile("panel_classified_info.xml"); - return panel; -} - -BOOL FSPanelClassifiedInfo::postBuild() -{ - childSetAction("back_btn", boost::bind(&FSPanelClassifiedInfo::onExit, this)); - childSetAction("show_on_map_btn", boost::bind(&FSPanelClassifiedInfo::onMapClick, this)); - childSetAction("teleport_btn", boost::bind(&FSPanelClassifiedInfo::onTeleportClick, this)); - - mScrollingPanel = getChild("scroll_content_panel"); - mScrollContainer = getChild("profile_scroll"); - - mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); - mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); - - mSnapshotCtrl = getChild("classified_snapshot"); - mSnapshotRect = getDefaultSnapshotRect(); - - return TRUE; -} - -void FSPanelClassifiedInfo::setExitCallback(const commit_callback_t& cb) -{ - getChild("back_btn")->setClickedCallback(cb); -} - -void FSPanelClassifiedInfo::setEditClassifiedCallback(const commit_callback_t& cb) -{ - getChild("edit_btn")->setClickedCallback(cb); -} - -void FSPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) -{ - LLPanel::reshape(width, height, called_from_parent); - - if (!mScrollContainer || !mScrollingPanel) - return; - - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - S32 scroll_height = mScrollContainer->getRect().getHeight(); - if (mScrollingPanelMinHeight >= scroll_height) - { - mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight); - } - else - { - mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); - } - - mSnapshotRect = getDefaultSnapshotRect(); - stretchSnapshot(); -} - -void FSPanelClassifiedInfo::onOpen(const LLSD& key) -{ - LLUUID avatar_id = key["classified_creator_id"]; - if(avatar_id.isNull()) - { - return; - } - - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - } - - setAvatarId(avatar_id); - - resetData(); - resetControls(); - scrollToTop(); - - setClassifiedId(key["classified_id"]); - setClassifiedName(key["classified_name"]); - setDescription(key["classified_desc"]); - setSnapshotId(key["classified_snapshot_id"]); - setFromSearch(key["from_search"]); - - LL_INFOS("FSPanelClassifiedInfo") << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; - - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - updateData(); - gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); - - // While we're at it let's get the stats from the new table if that - // capability exists. - std::string url = gAgent.getRegionCapability("SearchStatRequest"); - if (!url.empty()) - { - LL_INFOS("FSPanelClassifiedInfo") << "Classified stat request via capability" << LL_ENDL; - LLSD body; - body["classified_id"] = getClassifiedId(); - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, getClassifiedId(), _1)); - } - - // Update classified click stats. - // *TODO: Should we do this when opening not from search? - sendClickMessage("profile"); - - setInfoLoaded(false); -} - -void FSPanelClassifiedInfo::updateData() -{ - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); -} - -void FSPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO == type) - { - LLAvatarClassifiedInfo* c_info = static_cast(data); - if(c_info && getClassifiedId() == c_info->classified_id) - { - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setParcelId(c_info->parcel_id); - setPosGlobal(c_info->pos_global); - setSimName(c_info->sim_name); - - setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - getChild("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]); - - static std::string mature_str = getString("type_mature"); - static std::string pg_str = getString("type_pg"); - static LLUIString price_str = getString("l$_price"); - static std::string date_fmt = getString("date_fmt"); - - bool mature = is_cf_mature(c_info->flags); - getChild("content_type")->setValue(mature ? mature_str : pg_str); - getChild("content_type_moderate")->setVisible(mature); - getChild("content_type_general")->setVisible(!mature); - - std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? - getString("auto_renew_on") : getString("auto_renew_off"); - getChild("auto_renew")->setValue(auto_renew_str); - - price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); - getChild("price_for_listing")->setValue(LLSD(price_str)); - - std::string date_str = date_fmt; - LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); - getChild("creation_date")->setValue(date_str); - - setInfoLoaded(true); - } - } -} - -void FSPanelClassifiedInfo::resetData() -{ - setClassifiedName(LLStringUtil::null); - setDescription(LLStringUtil::null); - setClassifiedLocation(LLStringUtil::null); - setClassifiedId(LLUUID::null); - setSnapshotId(LLUUID::null); - setPosGlobal(LLVector3d::zero); - setParcelId(LLUUID::null); - setSimName(LLStringUtil::null); - setFromSearch(false); - - // reset click stats - mTeleportClicksOld = 0; - mMapClicksOld = 0; - mProfileClicksOld = 0; - mTeleportClicksNew = 0; - mMapClicksNew = 0; - mProfileClicksNew = 0; - - getChild("category")->setValue(LLStringUtil::null); - getChild("content_type")->setValue(LLStringUtil::null); - getChild("click_through_text")->setValue(LLStringUtil::null); - getChild("price_for_listing")->setValue(LLStringUtil::null); - getChild("auto_renew")->setValue(LLStringUtil::null); - getChild("creation_date")->setValue(LLStringUtil::null); - getChild("click_through_text")->setValue(LLStringUtil::null); - getChild("content_type_moderate")->setVisible(FALSE); - getChild("content_type_general")->setVisible(FALSE); -} - -void FSPanelClassifiedInfo::resetControls() -{ - bool is_self = getAvatarId() == gAgent.getID(); - - getChildView("edit_btn")->setEnabled(is_self); - getChildView("edit_btn")->setVisible( is_self); - getChildView("price_layout_panel")->setVisible( is_self); - getChildView("clickthrough_layout_panel")->setVisible( is_self); -} - -void FSPanelClassifiedInfo::setClassifiedName(const std::string& name) -{ - getChild("classified_name")->setValue(name); -} - -std::string FSPanelClassifiedInfo::getClassifiedName() -{ - return getChild("classified_name")->getValue().asString(); -} - -void FSPanelClassifiedInfo::setDescription(const std::string& desc) -{ - getChild("classified_desc")->setValue(desc); -} - -std::string FSPanelClassifiedInfo::getDescription() -{ - return getChild("classified_desc")->getValue().asString(); -} - -void FSPanelClassifiedInfo::setClassifiedLocation(const std::string& location) -{ - getChild("classified_location")->setValue(location); -} - -std::string FSPanelClassifiedInfo::getClassifiedLocation() -{ - return getChild("classified_location")->getValue().asString(); -} - -void FSPanelClassifiedInfo::setSnapshotId(const LLUUID& id) -{ - mSnapshotCtrl->setValue(id); - mSnapshotStreched = false; -} - -void FSPanelClassifiedInfo::draw() -{ - LLPanel::draw(); - - // Stretch in draw because it takes some time to load a texture, - // going to try to stretch snapshot until texture is loaded - if(!mSnapshotStreched) - { - stretchSnapshot(); - } -} - -LLUUID FSPanelClassifiedInfo::getSnapshotId() -{ - return getChild("classified_snapshot")->getValue().asUUID(); -} - -// static -void FSPanelClassifiedInfo::setClickThrough( - const LLUUID& classified_id, - S32 teleport, - S32 map, - S32 profile, - bool from_new_table) -{ - LL_INFOS("FSPanelClassifiedInfo") << "Click-through data for classified " << classified_id << " arrived: [" - << teleport << ", " << map << ", " << profile << "] (" - << (from_new_table ? "new" : "old") << ")" << LL_ENDL; - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - FSPanelClassifiedInfo* self = *iter; - if (self->getClassifiedId() != classified_id) - { - continue; - } - - // *HACK: Skip FSPanelClassifiedEdit instances: they don't display clicks data. - // Those instances should not be in the list at all. - if (typeid(*self) != typeid(FSPanelClassifiedInfo)) - { - continue; - } - - LL_INFOS("FSPanelClassifiedInfo") << "Updating classified info panel" << LL_ENDL; - - // We need to check to see if the data came from the new stat_table - // or the old classified table. We also need to cache the data from - // the two separate sources so as to display the aggregate totals. - - if (from_new_table) - { - self->mTeleportClicksNew = teleport; - self->mMapClicksNew = map; - self->mProfileClicksNew = profile; - } - else - { - self->mTeleportClicksOld = teleport; - self->mMapClicksOld = map; - self->mProfileClicksOld = profile; - } - - static LLUIString ct_str = self->getString("click_through_text_fmt"); - - ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); - ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); - ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); - - self->getChild("click_through_text")->setValue(ct_str.getString()); - // *HACK: remove this when there is enough room for click stats in the info panel - self->getChildView("click_through_text")->setToolTip(ct_str.getString()); - - LL_INFOS("FSPanelClassifiedInfo") << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) - << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) - << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) - << LL_ENDL; - } -} - -// static -std::string FSPanelClassifiedInfo::createLocationText( - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global) -{ - std::string location_text; - - location_text.append(original_name); - - if (!sim_name.empty()) - { - if (!location_text.empty()) - location_text.append(", "); - location_text.append(sim_name); - } - - if (!location_text.empty()) - location_text.append(" "); - - if (!pos_global.isNull()) - { - S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = ll_round((F32)pos_global.mdV[VZ]); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - } - - return location_text; -} - -void FSPanelClassifiedInfo::stretchSnapshot() -{ - // *NOTE dzaporozhan - // Could be moved to LLTextureCtrl - - LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture(); - - if(!texture) - { - return; - } - - if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight()) - { - // looks like texture is not loaded yet - return; - } - - LLRect rc = mSnapshotRect; - // *HACK dzaporozhan - // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes - // drawn texture to be smaller than expected. (see LLTextureCtrl::draw()) - // Lets increase texture height to force texture look as expected. - rc.mBottom -= BTN_HEIGHT_SMALL; - - F32 t_width = texture->getFullWidth(); - F32 t_height = texture->getFullHeight(); - - F32 ratio = llmin( (rc.getWidth() / t_width), (rc.getHeight() / t_height) ); - - t_width *= ratio; - t_height *= ratio; - - rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height)); - mSnapshotCtrl->setShape(rc); - - mSnapshotStreched = true; -} - -LLRect FSPanelClassifiedInfo::getDefaultSnapshotRect() -{ - // Using scroll container makes getting default rect a hard task - // because rect in postBuild() and in first reshape() is not the same. - // Using snapshot_panel makes it easier to reshape snapshot. - return getChild("snapshot_panel")->getLocalRect(); -} - -void FSPanelClassifiedInfo::scrollToTop() -{ - LLScrollContainer* scrollContainer = findChild("profile_scroll"); - if (scrollContainer) - scrollContainer->goToTop(); -} - -// static -// *TODO: move out of the panel -void FSPanelClassifiedInfo::sendClickMessage( - const std::string& type, - bool from_search, - const LLUUID& classified_id, - const LLUUID& parcel_id, - const LLVector3d& global_pos, - const std::string& sim_name) -{ - // You're allowed to click on your own ads to reassure yourself - // that the system is working. - LLSD body; - body["type"] = type; - body["from_search"] = from_search; - body["classified_id"] = classified_id; - body["parcel_id"] = parcel_id; - body["dest_pos_global"] = global_pos.getValue(); - body["region_name"] = sim_name; - - std::string url = gAgent.getRegionCapability("SearchStatTracking"); - LL_INFOS("FSPanelClassifiedInfo") << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; - LL_INFOS("FSPanelClassifiedInfo") << "body: [" << body << "]" << LL_ENDL; - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body ); -} - -void FSPanelClassifiedInfo::sendClickMessage(const std::string& type) -{ - sendClickMessage( - type, - fromSearch(), - getClassifiedId(), - getParcelId(), - getPosGlobal(), - getSimName()); -} - -void FSPanelClassifiedInfo::onMapClick() -{ - sendClickMessage("map"); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - LLFloaterReg::showInstance("world_map", "center"); -} - -void FSPanelClassifiedInfo::onTeleportClick() -{ - if (!getPosGlobal().isExactlyZero()) - { - sendClickMessage("teleport"); - gAgent.teleportViaLocation(getPosGlobal()); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - } -} - -void FSPanelClassifiedInfo::onExit() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -static const S32 CB_ITEM_MATURE = 0; -static const S32 CB_ITEM_PG = 1; - -FSPanelClassifiedEdit::FSPanelClassifiedEdit() - : FSPanelClassifiedInfo() - , mIsNew(false) - , mIsNewWithErrors(false) - , mCanClose(false) - , mPublishFloater(NULL) -{ -} - -FSPanelClassifiedEdit::~FSPanelClassifiedEdit() -{ -} - -//static -FSPanelClassifiedEdit* FSPanelClassifiedEdit::create() -{ - FSPanelClassifiedEdit* panel = new FSPanelClassifiedEdit(); - panel->buildFromFile("panel_edit_classified.xml"); - return panel; -} - -BOOL FSPanelClassifiedEdit::postBuild() -{ - FSPanelClassifiedInfo::postBuild(); - - LLTextureCtrl* snapshot = getChild("classified_snapshot"); - LLUICtrl* edit_icon = getChild("edit_icon"); - snapshot->setMouseEnterCallback(boost::bind(&FSPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon)); - snapshot->setMouseLeaveCallback(boost::bind(&FSPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon)); - edit_icon->setVisible(false); - - LLLineEditor* line_edit = getChild("classified_name"); - line_edit->setKeystrokeCallback(boost::bind(&FSPanelClassifiedEdit::onChange, this), NULL); - - LLTextEditor* text_edit = getChild("classified_desc"); - text_edit->setKeystrokeCallback(boost::bind(&FSPanelClassifiedEdit::onChange, this)); - - LLComboBox* combobox = getChild( "category"); - LLClassifiedInfo::cat_map::iterator iter; - for (iter = LLClassifiedInfo::sCategories.begin(); - iter != LLClassifiedInfo::sCategories.end(); - iter++) - { - combobox->add(LLTrans::getString(iter->second)); - } - - combobox->setCommitCallback(boost::bind(&FSPanelClassifiedEdit::onChange, this)); - - childSetCommitCallback("content_type", boost::bind(&FSPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("price_for_listing", boost::bind(&FSPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("auto_renew", boost::bind(&FSPanelClassifiedEdit::onChange, this), NULL); - - childSetAction("save_changes_btn", boost::bind(&FSPanelClassifiedEdit::onSaveClick, this)); - childSetAction("set_to_curr_location_btn", boost::bind(&FSPanelClassifiedEdit::onSetLocationClick, this)); - - mSnapshotCtrl->setOnSelectCallback(boost::bind(&FSPanelClassifiedEdit::onTextureSelected, this)); - - return TRUE; -} - -void FSPanelClassifiedEdit::fillIn(const LLSD& key) -{ - setAvatarId(gAgent.getID()); - - if(key.isUndefined()) - { - setPosGlobal(gAgent.getPositionGlobal()); - - LLUUID snapshot_id = LLUUID::null; - std::string desc; - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if(parcel) - { - desc = parcel->getDesc(); - snapshot_id = parcel->getSnapshotID(); - } - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - getChild("classified_name")->setValue(makeClassifiedName()); - getChild("classified_desc")->setValue(desc); - setSnapshotId(snapshot_id); - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - // server will set valid parcel id - setParcelId(LLUUID::null); - } - else - { - setClassifiedId(key["classified_id"]); - setClassifiedName(key["name"]); - setDescription(key["desc"]); - setSnapshotId(key["snapshot_id"]); - setCategory((U32)key["category"].asInteger()); - setContentType((U32)key["content_type"].asInteger()); - setClassifiedLocation(key["location_text"]); - getChild("auto_renew")->setValue(key["auto_renew"]); - getChild("price_for_listing")->setValue(key["price_for_listing"].asInteger()); - } -} - -void FSPanelClassifiedEdit::onOpen(const LLSD& key) -{ - mIsNew = key.isUndefined(); - - scrollToTop(); - - // classified is not created yet - bool is_new = isNew() || isNewWithErrors(); - - if(is_new) - { - resetData(); - resetControls(); - - fillIn(key); - - if(isNew()) - { - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - } - } - else - { - FSPanelClassifiedInfo::onOpen(key); - } - - std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label"); - getChild("save_changes_btn")->setLabelArg("[LABEL]", save_btn_label); - - enableVerbs(is_new); - enableEditing(is_new); - showEditing(!is_new); - resetDirty(); - setInfoLoaded(false); -} - -void FSPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO == type) - { - LLAvatarClassifiedInfo* c_info = static_cast(data); - if(c_info && getClassifiedId() == c_info->classified_id) - { - // see FSPanelClassifiedEdit::sendUpdate() for notes - mIsNewWithErrors = false; - // for just created classified - panel will probably be closed when we get here. - if(!getVisible()) - { - return; - } - - enableEditing(true); - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setParcelId(c_info->parcel_id); - setPosGlobal(c_info->pos_global); - - setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - // *HACK see FSPanelClassifiedEdit::sendUpdate() - setCategory(c_info->category - 1); - - bool mature = is_cf_mature(c_info->flags); - bool auto_renew = is_cf_auto_renew(c_info->flags); - - setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG); - getChild("auto_renew")->setValue(auto_renew); - getChild("price_for_listing")->setValue(c_info->price_for_listing); - getChildView("price_for_listing")->setEnabled(isNew()); - - resetDirty(); - setInfoLoaded(true); - enableVerbs(false); - - // for just created classified - in case user opened edit panel before processProperties() callback - getChild("save_changes_btn")->setLabelArg("[LABEL]", getString("save_label")); - } - } -} - -BOOL FSPanelClassifiedEdit::isDirty() const -{ - if(mIsNew) - { - return TRUE; - } - - BOOL dirty = false; - - dirty |= FSPanelClassifiedInfo::isDirty(); - dirty |= getChild("classified_snapshot")->isDirty(); - dirty |= getChild("classified_name")->isDirty(); - dirty |= getChild("classified_desc")->isDirty(); - dirty |= getChild("category")->isDirty(); - dirty |= getChild("content_type")->isDirty(); - dirty |= getChild("auto_renew")->isDirty(); - dirty |= getChild("price_for_listing")->isDirty(); - - return dirty; -} - -void FSPanelClassifiedEdit::resetDirty() -{ - FSPanelClassifiedInfo::resetDirty(); - getChild("classified_snapshot")->resetDirty(); - getChild("classified_name")->resetDirty(); - - LLTextEditor* desc = getChild("classified_desc"); - // call blockUndo() to really reset dirty(and make isDirty work as intended) - desc->blockUndo(); - desc->resetDirty(); - - getChild("category")->resetDirty(); - getChild("content_type")->resetDirty(); - getChild("auto_renew")->resetDirty(); - getChild("price_for_listing")->resetDirty(); -} - -void FSPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb) -{ - mSaveButtonClickedSignal.connect(cb); -} - -void FSPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -void FSPanelClassifiedEdit::resetControls() -{ - FSPanelClassifiedInfo::resetControls(); - - getChild("category")->setCurrentByIndex(0); - getChild("content_type")->setCurrentByIndex(0); - getChild("auto_renew")->setValue(false); -// FIRE-9814 - Don't hardcode a classified listing fee - //getChild("price_for_listing")->setValue(MINIMUM_PRICE_FOR_LISTING); - getChild("price_for_listing")->setValue(getClassifiedFee()); -// - getChildView("price_for_listing")->setEnabled(TRUE); -} - -// FIRE-9814 - Don't hardcode a classified listing fee -S32 FSPanelClassifiedEdit::getClassifiedFee() -{ - S32 fee = MINIMUM_PRICE_FOR_LISTING; -#ifdef OPENSIM - if (LLGridManager::getInstance()->isInOpenSim()) - { - fee = LLGridManager::getInstance()->getClassifiedFee(); - } -#endif // OPENSIM - return fee; -} -// - -bool FSPanelClassifiedEdit::canClose() -{ - return mCanClose; -} - -void FSPanelClassifiedEdit::draw() -{ - LLPanel::draw(); - - // Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback - // does not trigger callbacks when user navigates through images. - stretchSnapshot(); -} - -void FSPanelClassifiedEdit::stretchSnapshot() -{ - FSPanelClassifiedInfo::stretchSnapshot(); - - getChild("edit_icon")->setShape(mSnapshotCtrl->getRect()); -} - -U32 FSPanelClassifiedEdit::getContentType() -{ - LLComboBox* ct_cb = getChild("content_type"); - return ct_cb->getCurrentIndex(); -} - -void FSPanelClassifiedEdit::setContentType(U32 content_type) -{ - LLComboBox* ct_cb = getChild("content_type"); - ct_cb->setCurrentByIndex(content_type); - ct_cb->resetDirty(); -} - -bool FSPanelClassifiedEdit::getAutoRenew() -{ - return getChild("auto_renew")->getValue().asBoolean(); -} - -void FSPanelClassifiedEdit::sendUpdate() -{ - LLAvatarClassifiedInfo c_data; - - if(getClassifiedId().isNull()) - { - setClassifiedId(LLUUID::generateNewID()); - } - - c_data.agent_id = gAgent.getID(); - c_data.classified_id = getClassifiedId(); - // *HACK - // Categories on server start with 1 while combo-box index starts with 0 - c_data.category = getCategory() + 1; - c_data.name = getClassifiedName(); - c_data.description = getDescription(); - c_data.parcel_id = getParcelId(); - c_data.snapshot_id = getSnapshotId(); - c_data.pos_global = getPosGlobal(); - c_data.flags = getFlags(); - c_data.price_for_listing = getPriceForListing(); - - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); - - if(isNew()) - { - // Lets assume there will be some error. - // Successful sendClassifiedInfoUpdate will trigger processProperties and - // let us know there was no error. - mIsNewWithErrors = true; - } -} - -U32 FSPanelClassifiedEdit::getCategory() -{ - LLComboBox* cat_cb = getChild("category"); - return cat_cb->getCurrentIndex(); -} - -void FSPanelClassifiedEdit::setCategory(U32 category) -{ - LLComboBox* cat_cb = getChild("category"); - cat_cb->setCurrentByIndex(category); - cat_cb->resetDirty(); -} - -U8 FSPanelClassifiedEdit::getFlags() -{ - bool auto_renew = getChild("auto_renew")->getValue().asBoolean(); - - LLComboBox* content_cb = getChild("content_type"); - bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE; - - return pack_classified_flags_request(auto_renew, false, mature, false); -} - -void FSPanelClassifiedEdit::enableVerbs(bool enable) -{ - getChildView("save_changes_btn")->setEnabled(enable); -} - -void FSPanelClassifiedEdit::enableEditing(bool enable) -{ - getChildView("classified_snapshot")->setEnabled(enable); - getChildView("classified_name")->setEnabled(enable); - getChildView("classified_desc")->setEnabled(enable); - getChildView("set_to_curr_location_btn")->setEnabled(enable); - getChildView("category")->setEnabled(enable); - getChildView("content_type")->setEnabled(enable); - getChildView("price_for_listing")->setEnabled(enable); - getChildView("auto_renew")->setEnabled(enable); -} - -void FSPanelClassifiedEdit::showEditing(bool show) -{ - getChildView("price_for_listing_label")->setVisible( show); - getChildView("price_for_listing")->setVisible( show); -} - -std::string FSPanelClassifiedEdit::makeClassifiedName() -{ - std::string name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(parcel) - { - name = parcel->getName(); - } - - if(!name.empty()) - { - return name; - } - - LLViewerRegion* region = gAgent.getRegion(); - if(region) - { - name = region->getName(); - } - - return name; -} - -S32 FSPanelClassifiedEdit::getPriceForListing() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void FSPanelClassifiedEdit::setPriceForListing(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -void FSPanelClassifiedEdit::onSetLocationClick() -{ - setPosGlobal(gAgent.getPositionGlobal()); - setParcelId(LLUUID::null); - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - - // mark classified as dirty - setValue(LLSD()); - - onChange(); -} - -void FSPanelClassifiedEdit::onChange() -{ - enableVerbs(isDirty()); -} - -void FSPanelClassifiedEdit::onSaveClick() -{ - mCanClose = false; - - if(!isValidName()) - { - notifyInvalidName(); - return; - } - if(isNew() || isNewWithErrors()) - { - if(gStatusBar->getBalance() < getPriceForListing()) - { - LLNotificationsUtil::add("ClassifiedInsufficientFunds"); - return; - } - - mPublishFloater = LLFloaterReg::findTypedInstance( - "publish_classified_fs", LLSD()); - - if(!mPublishFloater) - { - mPublishFloater = LLFloaterReg::getTypedInstance( - "publish_classified_fs", LLSD()); - - mPublishFloater->setPublishClickedCallback(boost::bind - (&FSPanelClassifiedEdit::onPublishFloaterPublishClicked, this)); - } - - // set spinner value before it has focus or value wont be set - mPublishFloater->setPrice(getPriceForListing()); - mPublishFloater->openFloater(mPublishFloater->getKey()); - mPublishFloater->center(); - } - else - { - doSave(); - } -} - -void FSPanelClassifiedEdit::doSave() -{ - mCanClose = true; - sendUpdate(); - resetDirty(); - - mSaveButtonClickedSignal(this, LLSD()); -} - -void FSPanelClassifiedEdit::onPublishFloaterPublishClicked() -{ - setPriceForListing(mPublishFloater->getPrice()); - - doSave(); -} - -std::string FSPanelClassifiedEdit::getLocationNotice() -{ - static std::string location_notice = getString("location_notice"); - return location_notice; -} - -bool FSPanelClassifiedEdit::isValidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - return false; - } - if (!isalnum(name[0])) - { - return false; - } - - return true; -} - -void FSPanelClassifiedEdit::notifyInvalidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - LLNotificationsUtil::add("BlankClassifiedName"); - } - else if (!isalnum(name[0])) - { - LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric"); - } -} - -void FSPanelClassifiedEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl) -{ - ctrl->setVisible(TRUE); -} - -void FSPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) -{ - ctrl->setVisible(FALSE); -} - -void FSPanelClassifiedEdit::onTextureSelected() -{ - setSnapshotId(mSnapshotCtrl->getValue().asUUID()); - onChange(); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPublishClassifiedFloater::FSPublishClassifiedFloater(const LLSD& key) - : LLFloater(key) -{ -} - -FSPublishClassifiedFloater::~FSPublishClassifiedFloater() -{ -} - -BOOL FSPublishClassifiedFloater::postBuild() -{ - LLFloater::postBuild(); - - childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); - childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); - - return TRUE; -} - -void FSPublishClassifiedFloater::setPrice(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -S32 FSPublishClassifiedFloater::getPrice() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void FSPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("publish_btn")->setClickedCallback(cb); -} - -void FSPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -//EOF diff --git a/indra/newview/fspanelclassified.h b/indra/newview/fspanelclassified.h deleted file mode 100644 index 243f56e17a..0000000000 --- a/indra/newview/fspanelclassified.h +++ /dev/null @@ -1,300 +0,0 @@ -/** - * @file fspanelclassified.h - * @brief FSPanelClassified class definition - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Display of a classified used both for the global view in the -// Find directory, and also for each individual user's classified in their -// profile. - -#ifndef FS_PANELCLASSIFIED_H -#define FS_PANELCLASSIFIED_H - -#include "llavatarpropertiesprocessor.h" -#include "llclassifiedinfo.h" -#include "llfloater.h" -#include "llpanel.h" -#include "llrect.h" -#include "lluuid.h" -#include "v3dmath.h" - -class LLScrollContainer; -class LLTextureCtrl; -class LLUICtrl; - -class FSPublishClassifiedFloater : public LLFloater -{ -public: - FSPublishClassifiedFloater(const LLSD& key); - virtual ~FSPublishClassifiedFloater(); - - /*virtual*/ BOOL postBuild(); - - void setPrice(S32 price); - S32 getPrice(); - - void setPublishClickedCallback(const commit_signal_t::slot_type& cb); - void setCancelClickedCallback(const commit_signal_t::slot_type& cb); - -private: -}; - -class FSPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver -{ - LOG_CLASS(FSPanelClassifiedInfo); -public: - - static FSPanelClassifiedInfo* create(); - - virtual ~FSPanelClassifiedInfo(); - - /*virtual*/ void onOpen(const LLSD& key); - - void updateData(); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } - - LLUUID& getAvatarId() { return mAvatarId; } - - void setSnapshotId(const LLUUID& id); - - LLUUID getSnapshotId(); - - void setClassifiedId(const LLUUID& id) { mClassifiedId = id; } - - LLUUID& getClassifiedId() { return mClassifiedId; } - - void setClassifiedName(const std::string& name); - - std::string getClassifiedName(); - - void setDescription(const std::string& desc); - - std::string getDescription(); - - void setClassifiedLocation(const std::string& location); - - std::string getClassifiedLocation(); - - void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - - LLVector3d& getPosGlobal() { return mPosGlobal; } - - void setParcelId(const LLUUID& id) { mParcelId = id; } - - LLUUID getParcelId() { return mParcelId; } - - void setSimName(const std::string& sim_name) { mSimName = sim_name; } - - std::string getSimName() { return mSimName; } - - void setFromSearch(bool val) { mFromSearch = val; } - - bool fromSearch() { return mFromSearch; } - - bool getInfoLoaded() { return mInfoLoaded; } - - void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } - - static void setClickThrough( - const LLUUID& classified_id, - S32 teleport, - S32 map, - S32 profile, - bool from_new_table); - - static void sendClickMessage( - const std::string& type, - bool from_search, - const LLUUID& classified_id, - const LLUUID& parcel_id, - const LLVector3d& global_pos, - const std::string& sim_name); - - void setExitCallback(const commit_callback_t& cb); - - void setEditClassifiedCallback(const commit_callback_t& cb); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - /*virtual*/ void draw(); - -protected: - - FSPanelClassifiedInfo(); - - virtual void resetData(); - - virtual void resetControls(); - - static std::string createLocationText( - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global); - - void stretchSnapshot(); - void sendClickMessage(const std::string& type); - - LLRect getDefaultSnapshotRect(); - - void scrollToTop(); - - void onMapClick(); - void onTeleportClick(); - void onExit(); - - bool mSnapshotStreched; - LLRect mSnapshotRect; - LLTextureCtrl* mSnapshotCtrl; - -private: - - LLUUID mAvatarId; - LLUUID mClassifiedId; - LLVector3d mPosGlobal; - LLUUID mParcelId; - std::string mSimName; - bool mFromSearch; - bool mInfoLoaded; - - LLScrollContainer* mScrollContainer; - LLPanel* mScrollingPanel; - - S32 mScrollingPanelMinHeight; - S32 mScrollingPanelWidth; - - // Needed for stat tracking - S32 mTeleportClicksOld; - S32 mMapClicksOld; - S32 mProfileClicksOld; - S32 mTeleportClicksNew; - S32 mMapClicksNew; - S32 mProfileClicksNew; - - typedef std::list panel_list_t; - static panel_list_t sAllPanels; -}; - -class FSPanelClassifiedEdit : public FSPanelClassifiedInfo -{ - LOG_CLASS(FSPanelClassifiedEdit); -public: - - static FSPanelClassifiedEdit* create(); - - virtual ~FSPanelClassifiedEdit(); - - /*virtual*/ BOOL postBuild(); - - void fillIn(const LLSD& key); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL isDirty() const; - - /*virtual*/ void resetDirty(); - - void setSaveCallback(const commit_signal_t::slot_type& cb); - - void setCancelCallback(const commit_signal_t::slot_type& cb); - - /*virtual*/ void resetControls(); - - bool isNew() { return mIsNew; } - - bool isNewWithErrors() { return mIsNewWithErrors; } - - bool canClose(); - - void draw(); - - void stretchSnapshot(); - - U32 getCategory(); - - void setCategory(U32 category); - - U32 getContentType(); - - void setContentType(U32 content_type); - - bool getAutoRenew(); - - S32 getPriceForListing(); - -protected: - - FSPanelClassifiedEdit(); - - void sendUpdate(); - - void enableVerbs(bool enable); - - void enableEditing(bool enable); - - void showEditing(bool show); - - std::string makeClassifiedName(); - - void setPriceForListing(S32 price); - - U8 getFlags(); - - std::string getLocationNotice(); - - bool isValidName(); - - void notifyInvalidName(); - - void onSetLocationClick(); - void onChange(); - void onSaveClick(); - - void doSave(); - - void onPublishFloaterPublishClicked(); - - void onTexturePickerMouseEnter(LLUICtrl* ctrl); - void onTexturePickerMouseLeave(LLUICtrl* ctrl); - - void onTextureSelected(); - -private: - S32 getClassifiedFee(); // FIRE-9814 - Don't hardcode a classified listing fee - bool mIsNew; - bool mIsNewWithErrors; - bool mCanClose; - - FSPublishClassifiedFloater* mPublishFloater; - - commit_signal_t mSaveButtonClickedSignal; -}; - -#endif // FS_PANELCLASSIFIED_H diff --git a/indra/newview/fspanelprofile.cpp b/indra/newview/fspanelprofile.cpp deleted file mode 100644 index d4081fb6d5..0000000000 --- a/indra/newview/fspanelprofile.cpp +++ /dev/null @@ -1,2223 +0,0 @@ -/** - * @file fspanelprofile.cpp - * @brief Legacy Profile Floater - * - * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2012, Kadah Coba - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "fspanelprofile.h" - -// Common -#include "llavatarnamecache.h" -#include "llslurl.h" -#include "lldateutil.h" //ageFromDate - -// UI -#include "llavatariconctrl.h" -#include "llclipboard.h" //gClipboard -#include "llcheckboxctrl.h" -#include "lllineeditor.h" -#include "llloadingindicator.h" -#include "llmenubutton.h" -#include "lltabcontainer.h" -#include "lltextbox.h" -#include "lltexteditor.h" -#include "lltexturectrl.h" -#include "lltoggleablemenu.h" -#include "llgrouplist.h" - -// Newview -#include "fsdata.h" -#include "fsdroptarget.h" -#include "fspanelprofileclassifieds.h" -#include "llagent.h" //gAgent -#include "llagentbenefits.h" -#include "llagentpicksinfo.h" -#include "llavataractions.h" -#include "llavatarpropertiesprocessor.h" -#include "llcallingcard.h" -#include "llfloaterreg.h" -#include "llfloaterworldmap.h" -#include "llfirstuse.h" -#include "llgroupactions.h" -#include "llnotificationsutil.h" -#include "llpanelprofile.h" -#include "llparcel.h" -#include "lltrans.h" -#include "llviewercontrol.h" -#include "llviewermenu.h" -#include "llviewernetwork.h" //LLGridManager -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include "llvoiceclient.h" - -static LLPanelInjector t_panel_fs_profile_secondlife("panel_fs_profile_secondlife"); -static LLPanelInjector t_panel_fs_web("panel_fs_profile_web"); -static LLPanelInjector t_panel_fs_interests("panel_fs_profile_interests"); -static LLPanelInjector t_panel_fs_picks("panel_fs_profile_picks"); -static LLPanelInjector t_panel_fs_firstlife("panel_fs_profile_firstlife"); -static LLPanelInjector t_panel_fs_notes("panel_fs_profile_notes"); -static LLPanelInjector t_panel_fs_profile("panel_fs_profile"); - -static const std::string PANEL_SECONDLIFE = "panel_profile_secondlife"; -static const std::string PANEL_WEB = "panel_profile_web"; -static const std::string PANEL_INTERESTS = "panel_profile_interests"; -static const std::string PANEL_PICKS = "panel_profile_picks"; -static const std::string PANEL_CLASSIFIEDS = "panel_profile_classified"; -static const std::string PANEL_FIRSTLIFE = "panel_profile_firstlife"; -static const std::string PANEL_NOTES = "panel_profile_notes"; - - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelProfileTab::FSPanelProfileTab() -: LLPanel() -, mAvatarId(LLUUID::null) -, mLoading(false) -, mLoaded(false) -, mEmbedded(false) -, mSelfProfile(false) -{ -} - -FSPanelProfileTab::~FSPanelProfileTab() -{ - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } -} - -void FSPanelProfileTab::setAvatarId(const LLUUID& id) -{ - if (id.notNull()) - { - if (getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId, this); - } - mAvatarId = id; - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - - mSelfProfile = (getAvatarId() == gAgentID); - } -} - -void FSPanelProfileTab::onOpen(const LLSD& key) -{ - // Update data even if we are viewing same avatar profile as some data might been changed. - setAvatarId(key.asUUID()); - - setApplyProgress(true); -} - -void FSPanelProfileTab::enableControls() -{ - setApplyProgress(false); - - mLoaded = true; -} - -void FSPanelProfileTab::setApplyProgress(bool started) -{ - LLLoadingIndicator* indicator = findChild("progress_indicator"); - - if (indicator) - { - indicator->setVisible(started); - - if (started) - { - indicator->start(); - } - else - { - indicator->stop(); - } - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelProfileSecondLife::FSPanelProfileSecondLife() - : FSPanelProfileTab() - , mStatusText(NULL) - , mRlvBehaviorCallbackConnection() -{ -} - -FSPanelProfileSecondLife::~FSPanelProfileSecondLife() -{ - if (getAvatarId().notNull()) - { - LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); - } - - if (LLVoiceClient::instanceExists()) - { - LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); - } - - if (mRlvBehaviorCallbackConnection.connected()) - { - mRlvBehaviorCallbackConnection.disconnect(); - } -} - -BOOL FSPanelProfileSecondLife::postBuild() -{ - mStatusText = getChild("status"); - mGroupList = getChild("group_list"); - mShowInSearchCheckbox = getChild("show_in_search_checkbox"); - mSecondLifePic = getChild("2nd_life_pic"); - mDescriptionEdit = getChild("sl_description_edit"); - mTeleportButton = getChild("teleport"); - mShowOnMapButton = getChild("show_on_map_btn"); - mBlockButton = getChild("block"); - mUnblockButton = getChild("unblock"); - mDisplayNameButton = getChild("set_name"); - mAddFriendButton = getChild("add_friend"); - mGroupInviteButton = getChild("group_invite"); - mPayButton = getChild("pay"); - mIMButton = getChild("im"); - mOverflowButton = getChild("overflow_btn"); - - mStatusText->setVisible(FALSE); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; - registrar.add("Profile.Call", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::startCall(getAvatarId()); }); - registrar.add("Profile.AddToContactSet", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::addToContactSet(getAvatarId()); }); - registrar.add("Profile.Share", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::share(getAvatarId()); }); - registrar.add("Profile.Kick", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::kick(getAvatarId()); }); - registrar.add("Profile.Freeze", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::freeze(getAvatarId()); }); - registrar.add("Profile.Unfreeze", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::unfreeze(getAvatarId()); }); - registrar.add("Profile.CSR", [this](LLUICtrl*, const LLSD&) { LLAvatarName av_name; LLAvatarNameCache::get(getAvatarId(), &av_name); std::string name = av_name.getUserName(); LLAvatarActions::csr(getAvatarId(), name); }); - registrar.add("Profile.CopyNameToClipboard", [this](LLUICtrl*, const LLSD&) { onCopyToClipboard(); }); - registrar.add("Profile.CopyURI", [this](LLUICtrl*, const LLSD&) { onCopyURI(); }); - registrar.add("Profile.CopyKey", [this](LLUICtrl*, const LLSD&) { LLClipboard::instance().copyToClipboard(utf8str_to_wstring(getAvatarId().asString()), 0, getAvatarId().asString().size() ); }); - registrar.add("Profile.Report", [this](LLUICtrl*, const LLSD&) { LLAvatarActions::report(getAvatarId()); }); - - mAddFriendButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onAddFriendButtonClick, this)); - mIMButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onIMButtonClick, this)); - mTeleportButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onTeleportButtonClick, this)); - mShowOnMapButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onMapButtonClick, this)); - mPayButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::pay, this)); - mBlockButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::toggleBlock,this)); - mUnblockButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::toggleBlock,this)); - mGroupInviteButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onGroupInvite,this)); - mDisplayNameButton->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onClickSetName, this)); - - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable; - enable.add("Profile.EnableCall", [this](LLUICtrl*, const LLSD&) { return mVoiceStatus; }); - enable.add("Profile.EnableGod", [](LLUICtrl*, const LLSD&) { return gAgent.isGodlike(); }); - - mGroupList->setDoubleClickCallback(boost::bind(&FSPanelProfileSecondLife::openGroupProfile, this)); - mGroupList->setReturnCallback(boost::bind(&FSPanelProfileSecondLife::openGroupProfile, this)); - - LLToggleableMenu* profile_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - mOverflowButton->setMenu(profile_menu, LLMenuButton::MP_TOP_RIGHT); - - // allow skins to have copy buttons for name and avatar URI -Zi - LLButton* copy_uri_button = findChild("copy_uri_button"); - LLButton* copy_name_button = findChild("copy_name_button"); - // FIRE-21241 - Allow copy URI to appear only on the self profile in certain skins - // First we check for a all purpose copy_uri_button, if that was not defined - // then we do a second lookup for copy_own_uri_button. - if (!copy_uri_button) - { - // extended check to allow skins to have a copy button only on the self tab - copy_uri_button = findChild("copy_own_uri_button"); - } - // Same for name - if (!copy_name_button){ - copy_name_button = findChild("copy_own_name_button"); - } - // - if (copy_uri_button) - { - copy_uri_button->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onCopyURI, this)); - } - if (copy_name_button) - { - copy_name_button->setCommitCallback(boost::bind(&FSPanelProfileSecondLife::onCopyToClipboard, this)); - } - - - LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); - - mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&FSPanelProfileSecondLife::updateRlvRestrictions, this, _1)); - - return TRUE; -} - -void FSPanelProfileSecondLife::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); - - LLUUID avatar_id = getAvatarId(); - LLAvatarPropertiesProcessor::getInstance()->addObserver(avatar_id, this); - - BOOL own_profile = getSelfProfile(); - - mGroupInviteButton->setVisible(!own_profile); - mShowOnMapButton->setVisible(!own_profile); - mPayButton->setVisible(!own_profile); - mTeleportButton->setVisible(!own_profile); - mIMButton->setVisible(!own_profile); - mAddFriendButton->setVisible(!own_profile); - mBlockButton->setVisible(!own_profile); - mUnblockButton->setVisible(!own_profile); - mOverflowButton->setVisible(!own_profile); - mGroupList->setShowNone(!own_profile); - - if (own_profile && !getEmbedded()) - { - // Group list control cannot toggle ForAgent loading - // Less than ideal, but viewing own profile via search is edge case - mGroupList->enableForAgent(false); - } - - if (own_profile && LLAvatarName::useDisplayNames() && !getEmbedded()) - { - mDisplayNameButton->setVisible(TRUE); - mDisplayNameButton->setEnabled(TRUE); - } - - mDescriptionEdit->setParseHTML(!own_profile && !getEmbedded()); - - FSDropTarget* drop_target = getChild("drop_target"); - drop_target->setVisible(!own_profile); - drop_target->setEnabled(!own_profile); - - // FIRE-21241 - Allow copy URI to appear only on the self profile in certain skins - // extended check to allow skins to have a copy button only on the self tab - LLButton* copy_uri_button = findChild("copy_own_uri_button"); - LLButton* copy_name_button = findChild("copy_own_name_button"); - if (copy_uri_button) - { - copy_uri_button->setVisible(own_profile); - copy_uri_button->setEnabled(own_profile); - } - if (copy_name_button) - { - copy_name_button->setVisible(own_profile); - copy_name_button->setEnabled(own_profile); - } - // - - if (!own_profile) - { - mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : TRUE); - drop_target->setAgentID(avatar_id); - updateOnlineStatus(); - } - - updateButtons(); - - getChild("user_key")->setValue(avatar_id.asString()); -} - -void FSPanelProfileSecondLife::apply(LLAvatarData* data) -{ - if (getIsLoaded() && getSelfProfile()) - { - data->image_id = mSecondLifePic->getImageAssetID(); - data->about_text = mDescriptionEdit->getValue().asString(); - data->allow_publish = mShowInSearchCheckbox->getValue(); - - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(data); - } -} - -void FSPanelProfileSecondLife::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getIsLoading() && avatar_id.notNull() && !(getSelfProfile() && !getEmbedded())) - { - setIsLoading(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id); - } -} - -void FSPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_PROPERTIES == type) - { - const LLAvatarData* avatar_data = static_cast(data); - if(avatar_data && getAvatarId() == avatar_data->avatar_id) - { - processProfileProperties(avatar_data); - enableControls(); - } - } - else if (APT_GROUPS == type) - { - LLAvatarGroups* avatar_groups = static_cast(data); - if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) - { - processGroupProperties(avatar_groups); - } - } -} - -void FSPanelProfileSecondLife::resetData() -{ - resetLoading(); - // No real need to reset user_key - getChild("complete_name")->setValue(LLStringUtil::null); - getChild("register_date")->setValue(LLStringUtil::null); - getChild("acc_status_text")->setValue(LLStringUtil::null); - getChild("partner_text")->setValue(LLStringUtil::null); - mSecondLifePic->setValue(mSecondLifePic->getDefaultImageAssetID()); - mDescriptionEdit->setValue(LLStringUtil::null); - mStatusText->setVisible(FALSE); - mGroups.clear(); - mGroupList->setGroups(mGroups); -} - -void FSPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) -{ - LLUUID avatar_id = getAvatarId(); - if (!LLAvatarActions::isFriend(avatar_id) && !getSelfProfile()) - { - // this is non-friend avatar. Status will be updated from LLAvatarPropertiesProcessor. - // in FSPanelProfileSecondLife::processOnlineStatus() - - // subscribe observer to get online status. Request will be sent by FSPanelProfileSecondLife itself. - // do not subscribe for friend avatar because online status can be wrong overridden - // via LLAvatarData::flags if Preferences: "Only Friends & Groups can see when I am online" is set. - processOnlineStatus(avatar_data->flags & AVATAR_ONLINE); - } - - fillCommonData(avatar_data); - - fillPartnerData(avatar_data); - - fillAccountStatus(avatar_data); -} - -void FSPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups) -{ - //KC: the group_list ctrl can handle all this for us on our own profile - if (getSelfProfile() && !getEmbedded()) - { - return; - } - - // *NOTE dzaporozhan - // Group properties may arrive in two callbacks, we need to save them across - // different calls. We can't do that in textbox as textbox may change the text. - - LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); - const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end(); - - for (; it_end != it; ++it) - { - LLAvatarGroups::LLGroupData group_data = *it; - mGroups[group_data.group_name] = group_data.group_id; - } - - mGroupList->setGroups(mGroups); -} - -void FSPanelProfileSecondLife::openGroupProfile() -{ - LLUUID group_id = mGroupList->getSelectedUUID(); - LLGroupActions::show(group_id); -} - -void FSPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - getChild("complete_name")->setValue( av_name.getCompleteName() ); -} - -void FSPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) -{ - // Refresh avatar id in cache with new info to prevent re-requests - // and to make sure icons in text will be up to date - LLAvatarIconIDCache::getInstance()->add(avatar_data->avatar_id, avatar_data->image_id); - - LLStringUtil::format_map_t args; - { - std::string birth_date = LLTrans::getString("AvatarBirthDateFormat"); - LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) avatar_data->born_on.secondsSinceEpoch())); - args["[REG_DATE]"] = birth_date; - } - - args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now()); - args["[AGEDAYS]"] = LLSD((S32) (LLDate::now().secondsSinceEpoch() - avatar_data->born_on.secondsSinceEpoch()) / 86400).asString(); - std::string register_date = getString("RegisterDateFormat", args); - getChild("register_date")->setValue(register_date ); - mDescriptionEdit->setValue(avatar_data->about_text); - mSecondLifePic->setValue(avatar_data->image_id); - - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id); - if (!imagep->getFullHeight()) - { - imagep->forceToRefetchTexture(); - } - - if (getSelfProfile()) - { - mShowInSearchCheckbox->setValue((BOOL)(avatar_data->flags & AVATAR_ALLOW_PUBLISH)); - } -} - -void FSPanelProfileSecondLife::fillPartnerData(const LLAvatarData* avatar_data) -{ - LLTextBox* partner_text = getChild("partner_text"); - if (avatar_data->partner_id.notNull()) - { - partner_text->setText(LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString()); - } - else - { - partner_text->setText(getString("no_partner_text")); - } -} - -void FSPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data) -{ - LLStringUtil::format_map_t args; - args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(avatar_data); - args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(avatar_data); - // *NOTE: AVATAR_AGEVERIFIED not currently getting set in - // dataserver/lldataavatar.cpp for privacy considerations - //...so why didn't they comment this out too and take it out of - // the XML, too? Argh. -- TS - // args["[AGEVERIFICATION]"] = ""; - - args["[FIRESTORM]"] = ""; - args["[FSSUPP]"] = ""; - args["[FSDEV]"] = ""; - args["[FSQA]"] = ""; - args["[FSGW]"] = ""; - S32 flags = FSData::getInstance()->getAgentFlags(avatar_data->avatar_id); - if (flags != -1) - { - bool separator = false; - std::string text; - if (flags & (FSData::DEVELOPER | FSData::SUPPORT | FSData::QA | FSData::GATEWAY)) - { - args["[FIRESTORM]"] = LLTrans::getString("APP_NAME"); - } - - if (flags & FSData::DEVELOPER) - { - text = getString("FSDev"); - args["[FSDEV]"] = text; - separator = true; - } - - if (flags & FSData::SUPPORT) - { - text = getString("FSSupp"); - if (separator) - { - text = " /" + text; - } - args["[FSSUPP]"] = text; - separator = true; - } - - if (flags & FSData::QA) - { - text = getString("FSQualityAssurance"); - if (separator) - { - text = " /" + text; - } - args["[FSQA]"] = text; - separator = true; - } - - if (flags & FSData::GATEWAY) - { - text = getString("FSGW"); - if (separator) - { - text = " /" + text; - } - args["[FSGW]"] = text; - } - } - - std::string caption_text = getString("CaptionTextAcctInfo", args); - getChild("acc_status_text")->setValue(caption_text); -} - -void FSPanelProfileSecondLife::onMapButtonClick() -{ - LLAvatarActions::showOnMap(getAvatarId()); -} - -void FSPanelProfileSecondLife::pay() -{ - LLAvatarActions::pay(getAvatarId()); -} - -void FSPanelProfileSecondLife::toggleBlock() -{ - LLAvatarActions::toggleBlock(getAvatarId()); - - updateButtons(); -} - -void FSPanelProfileSecondLife::onAddFriendButtonClick() -{ - LLAvatarActions::requestFriendshipDialog(getAvatarId()); -} - -void FSPanelProfileSecondLife::onIMButtonClick() -{ - LLAvatarActions::startIM(getAvatarId()); -} - -void FSPanelProfileSecondLife::onTeleportButtonClick() -{ - LLAvatarActions::offerTeleport(getAvatarId()); -} - -void FSPanelProfileSecondLife::onCopyToClipboard() -{ - std::string name = getChild("complete_name")->getValue().asString(); - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(name), 0, name.size() ); -} - -void FSPanelProfileSecondLife::onCopyURI() -{ - std::string name = LLSLURL("agent", getAvatarId(), "about").getSLURLString(); - LLClipboard::instance().copyToClipboard(utf8str_to_wstring(name), 0, name.size() ); -} - -void FSPanelProfileSecondLife::onGroupInvite() -{ - LLAvatarActions::inviteToGroup(getAvatarId()); -} - -// virtual, called by LLAvatarTracker -void FSPanelProfileSecondLife::changed(U32 mask) -{ - updateOnlineStatus(); - updateButtons(); -} - -// virtual, called by LLVoiceClient -void FSPanelProfileSecondLife::onChange(EStatusType status, const std::string &channelURI, bool proximal) -{ - if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) - { - return; - } - - mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(getAvatarId()) ? LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) : TRUE); -} - -void FSPanelProfileSecondLife::setAvatarId(const LLUUID& id) -{ - if (id.notNull()) - { - if (getAvatarId().notNull()) - { - LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); - } - - FSPanelProfileTab::setAvatarId(id); - - if (LLAvatarActions::isFriend(getAvatarId())) - { - LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this); - } - } -} - -bool FSPanelProfileSecondLife::isGrantedToSeeOnlineStatus() -{ - // set text box visible to show online status for non-friends who has not set in Preferences - // "Only Friends & Groups can see when I am online" - if (!LLAvatarActions::isFriend(getAvatarId())) - { - return true; - } - - // *NOTE: GRANT_ONLINE_STATUS is always set to false while changing any other status. - // When avatar disallow me to see her online status processOfflineNotification Message is received by the viewer - // see comments for ChangeUserRights template message. EXT-453. - // If GRANT_ONLINE_STATUS flag is changed it will be applied when viewer restarts. EXT-3880 - const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); - return relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS); -} - -// method was disabled according to EXT-2022. Re-enabled & improved according to EXT-3880 -void FSPanelProfileSecondLife::updateOnlineStatus() -{ - if (!LLAvatarActions::isFriend(getAvatarId())) return; - // For friend let check if he allowed me to see his status - const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); - bool online = relationship->isOnline(); - processOnlineStatus(online); -} - -void FSPanelProfileSecondLife::processOnlineStatus(bool online) -{ - mStatusText->setVisible(isGrantedToSeeOnlineStatus()); - - std::string status = getString(online ? "status_online" : "status_offline"); - - mStatusText->setValue(status); - mStatusText->setColor(online ? - LLUIColorTable::instance().getColor("StatusUserOnline") : - LLUIColorTable::instance().getColor("StatusUserOffline")); -} - -void FSPanelProfileSecondLife::enableControls() -{ - FSPanelProfileTab::enableControls(); - - if (getSelfProfile() && !getEmbedded()) - { - mShowInSearchCheckbox->setVisible(TRUE); - mShowInSearchCheckbox->setEnabled(TRUE); - mDescriptionEdit->setEnabled(TRUE); - mSecondLifePic->setEnabled(TRUE); - } -} - -void FSPanelProfileSecondLife::updateButtons() -{ - LLUUID av_id = getAvatarId(); - bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()); - - if (LLAvatarActions::isFriend(av_id)) - { - const LLRelationship* friend_status = LLAvatarTracker::instance().getBuddyInfo(av_id); - bool can_offer_tp = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) || - (gRlvHandler.isException(RLV_BHVR_TPLURE, av_id, ERlvExceptionCheck::Permissive) || - friend_status->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))); - - mTeleportButton->setEnabled(is_buddy_online && can_offer_tp); - //Disable "Add Friend" button for friends. - mAddFriendButton->setEnabled(false); - } - else - { - bool can_offer_tp = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) || - gRlvHandler.isException(RLV_BHVR_TPLURE, av_id, ERlvExceptionCheck::Permissive)); - mTeleportButton->setEnabled(can_offer_tp); - mAddFriendButton->setEnabled(true); - } - - bool enable_map_btn = ((is_buddy_online && is_agent_mappable(av_id)) || gAgent.isGodlike()) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); - mShowOnMapButton->setEnabled(enable_map_btn); - - bool enable_block_btn = LLAvatarActions::canBlock(av_id) && !LLAvatarActions::isBlocked(av_id); - mBlockButton->setVisible(enable_block_btn); - - bool enable_unblock_btn = LLAvatarActions::isBlocked(av_id); - mUnblockButton->setVisible(enable_unblock_btn); -} - -void FSPanelProfileSecondLife::onClickSetName() -{ - LLAvatarNameCache::get(getAvatarId(), boost::bind(&FSPanelProfileSecondLife::onAvatarNameCacheSetName, this, _1, _2)); - - LLFirstUse::setDisplayName(false); -} - -void FSPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - if (av_name.getDisplayName().empty()) - { - // something is wrong, tell user to try again later - LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); - return; - } - - LL_INFOS("LegacyProfile") << "name-change now " << LLDate::now() << " next_update " - << LLDate(av_name.mNextUpdate) << LL_ENDL; - F64 now_secs = LLDate::now().secondsSinceEpoch(); - - if (now_secs < av_name.mNextUpdate) - { - // if the update time is more than a year in the future, it means updates have been blocked - // show a more general message - static const S32 YEAR = 60*60*24*365; - if (now_secs + YEAR < av_name.mNextUpdate) - { - LLNotificationsUtil::add("SetDisplayNameBlocked"); - return; - } - } - - LLFloaterReg::showInstance("display_name"); -} - -void FSPanelProfileSecondLife::updateRlvRestrictions(ERlvBehaviour behavior) -{ - if (behavior == RLV_BHVR_SHOWLOC || - behavior == RLV_BHVR_SHOWWORLDMAP) - { - updateButtons(); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelProfileWeb::FSPanelProfileWeb() - : FSPanelProfileTab() - , mWebBrowser(NULL) -{ -} - -FSPanelProfileWeb::~FSPanelProfileWeb() -{ -} - -void FSPanelProfileWeb::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); -} - -BOOL FSPanelProfileWeb::postBuild() -{ - mWebProfileButton = getChild("web_profile"); - mLoadButton = getChild("load"); - mUrlEdit = getChild("url_edit"); - - mLoadButton->setCommitCallback(boost::bind(&FSPanelProfileWeb::onCommitLoad, this, _1)); - - mWebProfileButton->setCommitCallback(boost::bind(&FSPanelProfileWeb::onCommitWebProfile, this, _1)); - mWebProfileButton->setVisible(LLGridManager::getInstance()->isInSecondLife()); - - mWebBrowser = getChild("profile_html"); - mWebBrowser->addObserver(this); - mWebBrowser->setHomePageUrl("about:blank"); - - mUrlEdit->setEnabled(FALSE); - - return TRUE; -} - -void FSPanelProfileWeb::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_PROPERTIES == type) - { - const LLAvatarData* avatar_data = static_cast(data); - if (avatar_data && getAvatarId() == avatar_data->avatar_id) - { - mURLHome = avatar_data->profile_url; - mUrlEdit->setValue(mURLHome); - mLoadButton->setEnabled(mURLHome.length() > 0); - enableControls(); - } - } -} - -void FSPanelProfileWeb::resetData() -{ - mURLHome = LLStringUtil::null; - mUrlEdit->setValue(mURLHome); - mWebBrowser->navigateHome(); -} - -void FSPanelProfileWeb::apply(LLAvatarData* data) -{ - data->profile_url = mUrlEdit->getValue().asString(); -} - -void FSPanelProfileWeb::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getIsLoading() && avatar_id.notNull()) - { - setIsLoading(); - - if (!mURLWebProfile.empty()) - { - mWebBrowser->setVisible(TRUE); - mPerformanceTimer.start(); - mWebBrowser->navigateTo(mURLWebProfile, HTTP_CONTENT_TEXT_HTML); - } - } -} - -void FSPanelProfileWeb::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - std::string username = av_name.getAccountName(); - if (username.empty()) - { - username = LLCacheName::buildUsername(av_name.getDisplayName()); - } - else - { - LLStringUtil::replaceChar(username, ' ', '.'); - } - - mURLWebProfile = getProfileURL(username); - if (mURLWebProfile.empty()) - { - return; - } - mWebProfileButton->setEnabled(TRUE); - - if (getIsLoading()) //if the tab was opened before name was resolved, load the panel now - { - updateData(); - } -} - -void FSPanelProfileWeb::onCommitLoad(LLUICtrl* ctrl) -{ - if (!mURLHome.empty()) - { - LLSD::String valstr = ctrl->getValue().asString(); - if (valstr.empty()) - { - mWebBrowser->setVisible(TRUE); - mPerformanceTimer.start(); - mWebBrowser->navigateTo( mURLHome, HTTP_CONTENT_TEXT_HTML ); - } - else if (valstr == "popout") - { - // open in viewer's browser, new window - LLWeb::loadURLInternal(mURLHome); - } - else if (valstr == "external") - { - // open in external browser - LLWeb::loadURLExternal(mURLHome); - } - } -} - -void FSPanelProfileWeb::onCommitWebProfile(LLUICtrl* ctrl) -{ - if (!mURLWebProfile.empty()) - { - LLSD::String valstr = ctrl->getValue().asString(); - if (valstr.empty()) - { - mWebBrowser->setVisible(TRUE); - mPerformanceTimer.start(); - mWebBrowser->navigateTo( mURLWebProfile, HTTP_CONTENT_TEXT_HTML ); - } - else if (valstr == "popout") - { - // open the web profile floater - LLAvatarActions::showProfileWeb(getAvatarId()); - } - else if (valstr == "external") - { - // open in external browser - LLWeb::loadURLExternal(mURLWebProfile); - } - } -} - -void FSPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) -{ - switch(event) - { - case MEDIA_EVENT_STATUS_TEXT_CHANGED: - childSetValue("status_text", LLSD( self->getStatusText() ) ); - break; - - case MEDIA_EVENT_LOCATION_CHANGED: - // don't set this or user will set there url to profile url - // when clicking ok on there own profile. - // childSetText("url_edit", self->getLocation() ); - break; - - case MEDIA_EVENT_NAVIGATE_BEGIN: - { - if (mFirstNavigate) - { - mFirstNavigate = false; - } - else - { - mPerformanceTimer.start(); - } - } - break; - - case MEDIA_EVENT_NAVIGATE_COMPLETE: - { - LLStringUtil::format_map_t args; - args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32()); - childSetValue("status_text", LLSD( getString("LoadTime", args)) ); - } - break; - - default: - // Having a default case makes the compiler happy. - break; - } -} - -void FSPanelProfileWeb::enableControls() -{ - FSPanelProfileTab::enableControls(); - - if (getSelfProfile() && !getEmbedded()) - { - mUrlEdit->setEnabled(TRUE); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -static const S32 WANT_CHECKS = 8; -static const S32 SKILL_CHECKS = 6; - -FSPanelProfileInterests::FSPanelProfileInterests() - : FSPanelProfileTab() -{ -} - -FSPanelProfileInterests::~FSPanelProfileInterests() -{ -} - -void FSPanelProfileInterests::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); -} - -BOOL FSPanelProfileInterests::postBuild() -{ - mWantToEditor = getChild("want_to_edit"); - mSkillsEditor = getChild("skills_edit"); - mLanguagesEditor = getChild("languages_edit"); - - for (S32 i = 0; i < WANT_CHECKS; ++i) - { - std::string check_name = llformat("chk%d", i); - mWantChecks[i] = getChild(check_name); - } - - for (S32 i = 0; i < SKILL_CHECKS; ++i) - { - std::string check_name = llformat("schk%d", i); - mSkillChecks[i] = getChild(check_name); - } - - //FS:KC - Due to a bug with LLLineEditor, it cannot be disabled from XUI - // It won't properly enable from code if it is. - mWantToEditor->setEnabled(FALSE); - mSkillsEditor->setEnabled(FALSE); - mLanguagesEditor->setEnabled(FALSE); - - return TRUE; -} - - -void FSPanelProfileInterests::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_INTERESTS_INFO == type) - { - const FSInterestsData* interests_data = static_cast(data); - if (interests_data && getAvatarId() == interests_data->avatar_id) - { - for (S32 i = 0; i < WANT_CHECKS; ++i) - { - if (interests_data->want_to_mask & (1<setValue(TRUE); - } - else - { - mWantChecks[i]->setValue(FALSE); - } - } - - for (S32 i = 0; i < SKILL_CHECKS; ++i) - { - if (interests_data->skills_mask & (1<setValue(TRUE); - } - else - { - mSkillChecks[i]->setValue(FALSE); - } - } - - mWantToEditor->setText(interests_data->want_to_text); - mSkillsEditor->setText(interests_data->skills_text); - mLanguagesEditor->setText(interests_data->languages_text); - - enableControls(); - } - } -} - -void FSPanelProfileInterests::resetData() -{ - mWantToEditor->setValue(LLStringUtil::null); - mSkillsEditor->setValue(LLStringUtil::null); - mLanguagesEditor->setValue(LLStringUtil::null); - - for (S32 i = 0; i < WANT_CHECKS; ++i) - { - mWantChecks[i]->setValue(FALSE); - } - - for (S32 i = 0; i < SKILL_CHECKS; ++i) - { - mSkillChecks[i]->setValue(FALSE); - } -} - -void FSPanelProfileInterests::apply() -{ - if (getIsLoaded() && getSelfProfile()) - { - FSInterestsData interests_data = FSInterestsData(); - - interests_data.want_to_mask = 0; - for (S32 i = 0; i < WANT_CHECKS; ++i) - { - if (mWantChecks[i]->getValue().asBoolean()) - { - interests_data.want_to_mask |= (1 << i); - } - } - - interests_data.skills_mask = 0; - for (S32 i = 0; i < SKILL_CHECKS; ++i) - { - if (mSkillChecks[i]->getValue().asBoolean()) - { - interests_data.skills_mask |= (1 << i); - } - } - - interests_data.want_to_text = mWantToEditor->getText(); - interests_data.skills_text = mSkillsEditor->getText(); - interests_data.languages_text = mLanguagesEditor->getText(); - - LLAvatarPropertiesProcessor::getInstance()->sendInterestsInfoUpdate(&interests_data); - } - -} - -void FSPanelProfileInterests::enableControls() -{ - FSPanelProfileTab::enableControls(); - - if (getSelfProfile() && !getEmbedded()) - { - mWantToEditor->setEnabled(TRUE); - mSkillsEditor->setEnabled(TRUE); - mLanguagesEditor->setEnabled(TRUE); - - for (S32 i = 0; i < WANT_CHECKS; ++i) - { - mWantChecks[i]->setEnabled(TRUE); - } - - for (S32 i = 0; i < SKILL_CHECKS; ++i) - { - mSkillChecks[i]->setEnabled(TRUE); - } - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelPick::FSPanelPick() - : FSPanelProfileTab() - , LLRemoteParcelInfoObserver() - , mSnapshotCtrl(NULL) - , mPickId(LLUUID::null) - , mParcelId(LLUUID::null) - , mRequestedId(LLUUID::null) - , mLocationChanged(false) - , mNewPick(false) - , mCurrentPickDescription("") - , mIsEditing(false) -{ -} - -//static -FSPanelPick* FSPanelPick::create() -{ - FSPanelPick* panel = new FSPanelPick(); - panel->buildFromFile("panel_fs_profile_pick.xml"); - return panel; -} - -FSPanelPick::~FSPanelPick() -{ - if (mParcelId.notNull()) - { - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); - } -} - -void FSPanelPick::setAvatarId(const LLUUID& avatar_id) -{ - if (avatar_id.isNull()) - { - return; - } - FSPanelProfileTab::setAvatarId(avatar_id); - - // creating new Pick - if (getPickId().isNull() && getSelfProfile()) - { - mNewPick = true; - - setPosGlobal(gAgent.getPositionGlobal()); - - LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null; - std::string pick_name, pick_desc, region_name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (parcel) - { - parcel_id = parcel->getID(); - pick_name = parcel->getName(); - pick_desc = parcel->getDesc(); - snapshot_id = parcel->getSnapshotID(); - } - - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - setParcelID(parcel_id); - setPickName(pick_name.empty() ? region_name : pick_name); - setPickDesc(pick_desc); - setSnapshotId(snapshot_id); - setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal())); - - enableSaveButton(TRUE); - } - else - { - LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId()); - - enableSaveButton(FALSE); - } - - resetDirty(); - - if (getSelfProfile() && !getEmbedded()) - { - mPickName->setEnabled(TRUE); - mPickDescription->setEnabled(TRUE); - mSetCurrentLocationButton->setVisible(TRUE); - } -} - -BOOL FSPanelPick::postBuild() -{ - mPickName = getChild("pick_name"); - mPickDescription = getChild("pick_desc"); - mSaveButton = getChild("save_changes_btn"); - mSetCurrentLocationButton = getChild("set_to_curr_location_btn"); - - mSnapshotCtrl = getChild("pick_snapshot"); - mSnapshotCtrl->setCommitCallback(boost::bind(&FSPanelPick::onSnapshotChanged, this)); - - childSetAction("teleport_btn", boost::bind(&FSPanelPick::onClickTeleport, this)); - childSetAction("show_on_map_btn", boost::bind(&FSPanelPick::onClickMap, this)); - - mSaveButton->setCommitCallback(boost::bind(&FSPanelPick::onClickSave, this)); - mSetCurrentLocationButton->setCommitCallback(boost::bind(&FSPanelPick::onClickSetLocation, this)); - - mPickName->setKeystrokeCallback(boost::bind(&FSPanelPick::onPickChanged, this, _1), NULL); - mPickName->setEnabled(FALSE); - - mPickDescription->setKeystrokeCallback(boost::bind(&FSPanelPick::onPickChanged, this, _1)); - mPickDescription->setFocusReceivedCallback(boost::bind(&FSPanelPick::onDescriptionFocusReceived, this)); - - getChild("pick_location")->setEnabled(FALSE); - - return TRUE; -} - -void FSPanelPick::onDescriptionFocusReceived() -{ - if (!mIsEditing && getSelfProfile()) - { - mIsEditing = true; - mPickDescription->setParseHTML(false); - setPickDesc(mCurrentPickDescription); - } -} - -void FSPanelPick::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_PICK_INFO != type) - { - return; - } - - LLPickData* pick_info = static_cast(data); - if (!pick_info - || pick_info->creator_id != getAvatarId() - || pick_info->pick_id != getPickId()) - { - return; - } - - mIsEditing = false; - mPickDescription->setParseHTML(true); - mParcelId = pick_info->parcel_id; - setSnapshotId(pick_info->snapshot_id); - if (!getSelfProfile() || getEmbedded()) - { - mSnapshotCtrl->setEnabled(FALSE); - } - setPickName(pick_info->name); - setPickDesc(pick_info->desc); - setPosGlobal(pick_info->pos_global); - mCurrentPickDescription = pick_info->desc; - - // Send remote parcel info request to get parcel name and sim (region) name. - sendParcelInfoRequest(); - - // *NOTE dzaporozhan - // We want to keep listening to APT_PICK_INFO because user may - // edit the Pick and we have to update Pick info panel. - // revomeObserver is called from onClickBack - - enableControls(); -} - -void FSPanelPick::setSnapshotId(const LLUUID& id) -{ - mSnapshotCtrl->setImageAssetID(id); - mSnapshotCtrl->setValid(TRUE); -} - -void FSPanelPick::setPickName(const std::string& name) -{ - mPickName->setValue(name); -} - -const std::string FSPanelPick::getPickName() -{ - return mPickName->getValue().asString(); -} - -void FSPanelPick::setPickDesc(const std::string& desc) -{ - mPickDescription->setValue(desc); -} - -void FSPanelPick::setPickLocation(const std::string& location) -{ - getChild("pick_location")->setValue(location); -} - -void FSPanelPick::onClickMap() -{ - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - LLFloaterReg::showInstance("world_map", "center"); -} - -void FSPanelPick::onClickTeleport() -{ - if (!getPosGlobal().isExactlyZero()) - { - gAgent.teleportViaLocation(getPosGlobal()); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - } -} - -void FSPanelPick::enableSaveButton(BOOL enable) -{ - mSaveButton->setEnabled(enable); - mSaveButton->setVisible(enable); -} - -void FSPanelPick::onSnapshotChanged() -{ - enableSaveButton(TRUE); -} - -void FSPanelPick::onPickChanged(LLUICtrl* ctrl) -{ - if (ctrl && ctrl == mPickName) - { - updateTabLabel(mPickName->getText()); - } - - enableSaveButton(isDirty()); -} - -void FSPanelPick::resetDirty() -{ - LLPanel::resetDirty(); - - mPickName->resetDirty(); - mPickDescription->resetDirty(); - mSnapshotCtrl->resetDirty(); - mLocationChanged = false; -} - -BOOL FSPanelPick::isDirty() const -{ - if (mNewPick - || LLPanel::isDirty() - || mLocationChanged - || mSnapshotCtrl->isDirty() - || mPickName->isDirty() - || mPickDescription->isDirty()) - { - return TRUE; - } - return FALSE; -} - -void FSPanelPick::onClickSetLocation() -{ - // Save location for later use. - setPosGlobal(gAgent.getPositionGlobal()); - - std::string parcel_name, region_name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (parcel) - { - mParcelId = parcel->getID(); - parcel_name = parcel->getName(); - } - - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal())); - - mLocationChanged = true; - enableSaveButton(TRUE); -} - -void FSPanelPick::onClickSave() -{ - sendUpdate(); - - mLocationChanged = false; -} - -void FSPanelPick::apply() -{ - if ((mNewPick || getIsLoaded()) && isDirty()) - { - sendUpdate(); - } -} - -std::string FSPanelPick::getLocationNotice() -{ - static const std::string notice = getString("location_notice"); - return notice; -} - -void FSPanelPick::sendParcelInfoRequest() -{ - if (mParcelId != mRequestedId) - { - if (mRequestedId.notNull()) - { - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this); - } - LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this); - LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId); - - mRequestedId = mParcelId; - } -} - -void FSPanelPick::processParcelInfo(const LLParcelData& parcel_data) -{ - setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name, parcel_data.sim_name, getPosGlobal())); - - // We have received parcel info for the requested ID so clear it now. - mRequestedId.setNull(); - - if (mParcelId.notNull()) - { - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); - } -} - -void FSPanelPick::sendUpdate() -{ - LLPickData pick_data; - - // If we don't have a pick id yet, we'll need to generate one, - // otherwise we'll keep overwriting pick_id 00000 in the database. - if (getPickId().isNull()) - { - getPickId().generate(); - } - - pick_data.agent_id = gAgentID; - pick_data.session_id = gAgent.getSessionID(); - pick_data.pick_id = getPickId(); - pick_data.creator_id = gAgentID;; - - //legacy var need to be deleted - pick_data.top_pick = FALSE; - pick_data.parcel_id = mParcelId; - pick_data.name = getPickName(); - pick_data.desc = mPickDescription->getValue().asString(); - pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); - pick_data.pos_global = getPosGlobal(); - pick_data.sort_order = 0; - pick_data.enabled = TRUE; - - LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data); - - if(mNewPick) - { - // Assume a successful create pick operation, make new number of picks - // available immediately. Actual number of picks will be requested in - // LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond. - LLAgentPicksInfo::getInstance()->incrementNumberOfPicks(); - } -} - -// static -std::string FSPanelPick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global) -{ - std::string location_text(owner_name); - if (!original_name.empty()) - { - if (!location_text.empty()) - { - location_text.append(", "); - } - location_text.append(original_name); - - } - - if (!sim_name.empty()) - { - if (!location_text.empty()) - { - location_text.append(", "); - } - location_text.append(sim_name); - } - - if (!location_text.empty()) - { - location_text.append(" "); - } - - if (!pos_global.isNull()) - { - S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = ll_round((F32)pos_global.mdV[VZ]); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - } - return location_text; -} - -void FSPanelPick::updateTabLabel(const std::string& title) -{ - setLabel(title); - LLTabContainer* parent = dynamic_cast(getParent()); - if (parent) - { - parent->setCurrentTabName(title); - } -} - -////////////////////////////////////////////////////////////////////////// - -FSPanelProfilePicks::FSPanelProfilePicks() - : FSPanelProfileTab(), - mRlvBehaviorCallbackConnection() -{ -} - -FSPanelProfilePicks::~FSPanelProfilePicks() -{ - if (mRlvBehaviorCallbackConnection.connected()) - { - mRlvBehaviorCallbackConnection.disconnect(); - } -} - -void FSPanelProfilePicks::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); - - if (getSelfProfile() && !getEmbedded()) - { - mNewButton->setVisible(TRUE); - mNewButton->setEnabled(FALSE); - - mDeleteButton->setVisible(TRUE); - mDeleteButton->setEnabled(FALSE); - } -} - -BOOL FSPanelProfilePicks::postBuild() -{ - mTabContainer = getChild("tab_picks"); - mNoItemsLabel = getChild("picks_panel_text"); - mNewButton = getChild("new_btn"); - mDeleteButton = getChild("delete_btn"); - - mNewButton->setCommitCallback(boost::bind(&FSPanelProfilePicks::onClickNewBtn, this)); - mDeleteButton->setCommitCallback(boost::bind(&FSPanelProfilePicks::onClickDelete, this)); - - mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&FSPanelProfilePicks::updateRlvRestrictions, this, _1, _2)); - - mNewButton->setEnabled(canAddNewPick()); - mDeleteButton->setEnabled(canDeletePick()); - - LLTextBox* intro_txt = getChild("Tell everyone about your favorite places in Second Life."); - intro_txt->setTextArg("[GRID]", LLTrans::getString("SECOND_LIFE")); - - return TRUE; -} - -void FSPanelProfilePicks::onClickNewBtn() -{ - mNoItemsLabel->setVisible(FALSE); - FSPanelPick* pick_panel = FSPanelPick::create(); - pick_panel->setAvatarId(getAvatarId()); - mTabContainer->addTabPanel( - LLTabContainer::TabPanelParams(). - panel(pick_panel). - select_tab(true). - label(pick_panel->getPickName())); - mNewButton->setEnabled(canAddNewPick()); - mDeleteButton->setEnabled(canDeletePick()); -} - -void FSPanelProfilePicks::onClickDelete() -{ - FSPanelPick* pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); - if (pick_panel) - { - LLUUID pick_id = pick_panel->getPickId(); - LLSD args; - args["PICK"] = pick_panel->getPickName(); - LLSD payload; - payload["pick_id"] = pick_id; - payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); - LLNotificationsUtil::add("DeleteAvatarPick", args, payload, boost::bind(&FSPanelProfilePicks::callbackDeletePick, this, _1, _2)); - } -} - -void FSPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - LLUUID pick_id = notification["payload"]["pick_id"].asUUID(); - S32 tab_idx = notification["payload"]["tab_idx"].asInteger(); - - FSPanelPick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); - if (pick_panel && pick_panel->getPickId() == pick_id) - { - mTabContainer->removeTabPanel(pick_panel); - } - - if (pick_id.notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id); - } - - mNewButton->setEnabled(canAddNewPick()); - mDeleteButton->setEnabled(canDeletePick()); - } -} - -void FSPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_PICKS == type) - { - LLAvatarPicks* avatar_picks = static_cast(data); - if (avatar_picks && getAvatarId() == avatar_picks->target_id) - { - - LLUUID selected_id = LLUUID::null; - if (mTabContainer->getTabCount() > 0) - { - FSPanelPick* active_pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); - if (active_pick_panel) - { - selected_id = active_pick_panel->getPickId(); - } - } - - mTabContainer->deleteAllTabs(); - - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); - for (; avatar_picks->picks_list.end() != it; ++it) - { - LLUUID pick_id = it->first; - std::string pick_name = it->second; - - FSPanelPick* pick_panel = FSPanelPick::create(); - - pick_panel->setPickId(pick_id); - pick_panel->setPickName(pick_name); - pick_panel->setAvatarId(getAvatarId()); - - mTabContainer->addTabPanel( - LLTabContainer::TabPanelParams(). - panel(pick_panel). - select_tab(selected_id == pick_id). - label(pick_name)); - } - - mNewButton->setEnabled(canAddNewPick()); - mDeleteButton->setEnabled(canDeletePick()); - - BOOL no_data = !mTabContainer->getTabCount(); - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if(getSelfProfile()) - { - mNoItemsLabel->setValue(LLTrans::getString("NoPicksText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText")); - } - } - else if (selected_id.isNull()) - { - mTabContainer->selectFirstTab(); - } - - enableControls(); - } - } -} - -void FSPanelProfilePicks::resetData() -{ - resetLoading(); - mTabContainer->deleteAllTabs(); -} - -void FSPanelProfilePicks::apply() -{ - if (getIsLoaded()) - { - for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) - { - FSPanelPick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); - if (pick_panel) - { - pick_panel->apply(); - } - } - } -} - -void FSPanelProfilePicks::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getIsLoading() && avatar_id.notNull()) - { - setIsLoading(); - mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); - mNoItemsLabel->setVisible(TRUE); - - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); - } -} - -void FSPanelProfilePicks::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) -{ - if (behavior == RLV_BHVR_SHOWLOC) - { - mNewButton->setEnabled(canAddNewPick()); - } -} - -bool FSPanelProfilePicks::canAddNewPick() -{ - return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() && - mTabContainer->getTabCount() < LLAgentBenefitsMgr::current().getPicksLimit() && - !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); -} - -bool FSPanelProfilePicks::canDeletePick() -{ - return (mTabContainer->getTabCount() > 0); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelProfileFirstLife::FSPanelProfileFirstLife() - : FSPanelProfileTab(), - mIsEditing(false) -{ -} - -FSPanelProfileFirstLife::~FSPanelProfileFirstLife() -{ -} - -BOOL FSPanelProfileFirstLife::postBuild() -{ - mDescriptionEdit = getChild("fl_description_edit"); - mPicture = getChild("real_world_pic"); - - mDescriptionEdit->setFocusReceivedCallback(boost::bind(&FSPanelProfileFirstLife::onDescriptionFocusReceived, this)); - - return TRUE; -} - -void FSPanelProfileFirstLife::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); -} - - -void FSPanelProfileFirstLife::onDescriptionFocusReceived() -{ - if (!mIsEditing && getSelfProfile()) - { - mIsEditing = true; - mDescriptionEdit->setParseHTML(false); - mDescriptionEdit->setText(mCurrentDescription); - } -} - -void FSPanelProfileFirstLife::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_PROPERTIES == type) - { - const LLAvatarData* avatar_data = static_cast(data); - if (avatar_data && getAvatarId() == avatar_data->avatar_id) - { - mCurrentDescription = avatar_data->fl_about_text; - mDescriptionEdit->setValue(mCurrentDescription); - mPicture->setValue(avatar_data->fl_image_id); - enableControls(); - } - } -} - -void FSPanelProfileFirstLife::resetData() -{ - mDescriptionEdit->setValue(LLStringUtil::null); - mPicture->setValue(mPicture->getDefaultImageAssetID()); -} - -void FSPanelProfileFirstLife::apply(LLAvatarData* data) -{ - data->fl_image_id = mPicture->getImageAssetID(); - data->fl_about_text = mDescriptionEdit->getValue().asString(); -} - -void FSPanelProfileFirstLife::enableControls() -{ - FSPanelProfileTab::enableControls(); - - if (getSelfProfile() && !getEmbedded()) - { - mDescriptionEdit->setEnabled(TRUE); - mPicture->setEnabled(TRUE); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelAvatarNotes::FSPanelAvatarNotes() -: FSPanelProfileTab() -{ - -} - -void FSPanelAvatarNotes::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getIsLoading() && avatar_id.notNull()) - { - setIsLoading(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(avatar_id); - } -} - -BOOL FSPanelAvatarNotes::postBuild() -{ - mOnlineStatus = getChild("status_check"); - mMapRights = getChild("map_check"); - mEditObjectRights = getChild("objects_check"); - mNotesEditor = getChild("notes_edit"); - - mOnlineStatus->setCommitCallback(boost::bind(&FSPanelAvatarNotes::onCommitRights, this)); - mMapRights->setCommitCallback(boost::bind(&FSPanelAvatarNotes::onCommitRights, this)); - mEditObjectRights->setCommitCallback(boost::bind(&FSPanelAvatarNotes::onCommitRights, this)); - - mNotesEditor->setCommitCallback(boost::bind(&FSPanelAvatarNotes::onCommitNotes,this)); - mNotesEditor->setCommitOnFocusLost(TRUE); - - return TRUE; -} - -void FSPanelAvatarNotes::onOpen(const LLSD& key) -{ - FSPanelProfileTab::onOpen(key); - - resetData(); - - fillRightsData(); -} - -void FSPanelAvatarNotes::apply() -{ - onCommitNotes(); -} - -void FSPanelAvatarNotes::fillRightsData() -{ - mOnlineStatus->setValue(FALSE); - mMapRights->setValue(FALSE); - mEditObjectRights->setValue(FALSE); - - const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); - // If true - we are viewing friend's profile, enable check boxes and set values. - if(relation) - { - S32 rights = relation->getRightsGrantedTo(); - - mOnlineStatus->setValue(LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE); - mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); - mEditObjectRights->setValue(LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE); - } - - enableCheckboxes(NULL != relation); -} - -void FSPanelAvatarNotes::onCommitNotes() -{ - if (getIsLoaded()) - { - std::string notes = mNotesEditor->getValue().asString(); - LLAvatarPropertiesProcessor::getInstance()->sendNotes(getAvatarId(),notes); - } -} - -void FSPanelAvatarNotes::rightsConfirmationCallback(const LLSD& notification, - const LLSD& response, S32 rights) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(), rights); - } - else - { - mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE); - } -} - -void FSPanelAvatarNotes::confirmModifyRights(bool grant, S32 rights) -{ - LLSD args; - args["NAME"] = LLSLURL("agent", getAvatarId(), "completename").getSLURLString(); - - if (grant) - { - LLNotificationsUtil::add("GrantModifyRights", args, LLSD(), - boost::bind(&FSPanelAvatarNotes::rightsConfirmationCallback, this, - _1, _2, rights)); - } - else - { - LLNotificationsUtil::add("RevokeModifyRights", args, LLSD(), - boost::bind(&FSPanelAvatarNotes::rightsConfirmationCallback, this, - _1, _2, rights)); - } -} - -void FSPanelAvatarNotes::onCommitRights() -{ - const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); - - if (!buddy_relationship) - { - // Lets have a warning log message instead of having a crash. EXT-4947. - LL_WARNS("LegacyProfile") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL; - return; - } - - S32 rights = 0; - - if (mOnlineStatus->getValue().asBoolean()) - { - rights |= LLRelationship::GRANT_ONLINE_STATUS; - } - if (mMapRights->getValue().asBoolean()) - { - rights |= LLRelationship::GRANT_MAP_LOCATION; - } - if (mEditObjectRights->getValue().asBoolean()) - { - rights |= LLRelationship::GRANT_MODIFY_OBJECTS; - } - - bool allow_modify_objects = mEditObjectRights->getValue().asBoolean(); - - // if modify objects checkbox clicked - if (buddy_relationship->isRightGrantedTo( - LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) - { - confirmModifyRights(allow_modify_objects, rights); - } - // only one checkbox can trigger commit, so store the rest of rights - else - { - LLAvatarPropertiesProcessor::getInstance()->sendFriendRights( - getAvatarId(), rights); - } -} - -void FSPanelAvatarNotes::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_NOTES == type) - { - LLAvatarNotes* avatar_notes = static_cast(data); - if (avatar_notes && getAvatarId() == avatar_notes->target_id) - { - mNotesEditor->setValue(avatar_notes->notes); - mNotesEditor->setEnabled(TRUE); - enableControls(); - - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } - } -} - -void FSPanelAvatarNotes::resetData() -{ - resetLoading(); - mNotesEditor->setValue(LLStringUtil::null); - mOnlineStatus->setValue(FALSE); - mMapRights->setValue(FALSE); - mEditObjectRights->setValue(FALSE); -} - -void FSPanelAvatarNotes::enableCheckboxes(bool enable) -{ - mOnlineStatus->setEnabled(enable); - mMapRights->setEnabled(enable); - mEditObjectRights->setEnabled(enable); -} - -FSPanelAvatarNotes::~FSPanelAvatarNotes() -{ - if (getAvatarId().notNull()) - { - LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); - } -} - -// virtual, called by LLAvatarTracker -void FSPanelAvatarNotes::changed(U32 mask) -{ - // update rights to avoid have checkboxes enabled when friendship is terminated. EXT-4947. - fillRightsData(); -} - -void FSPanelAvatarNotes::setAvatarId(const LLUUID& id) -{ - if (id.notNull()) - { - if (getAvatarId().notNull()) - { - LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); - } - FSPanelProfileTab::setAvatarId(id); - LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this); - } -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSPanelProfile::FSPanelProfile() - : FSPanelProfileTab(), - mAvatarNameCacheConnection() -{ -} - -FSPanelProfile::~FSPanelProfile() -{ - if (mAvatarNameCacheConnection.connected()) - { - mAvatarNameCacheConnection.disconnect(); - } -} - -BOOL FSPanelProfile::postBuild() -{ - return TRUE; -} - -void FSPanelProfile::processProperties(void* data, EAvatarProcessorType type) -{ - mTabContainer = getChild("panel_profile_tabs"); - if (mTabContainer) - { - mTabContainer->setCommitCallback(boost::bind(&FSPanelProfile::onTabChange, this)); - } - - // Load data on currently opened tab as well - onTabChange(); -} - -void FSPanelProfile::onTabChange() -{ - FSPanelProfileTab* active_panel = dynamic_cast(mTabContainer->getCurrentPanel()); - if (active_panel) - { - active_panel->updateData(); - } -} - -void FSPanelProfile::onOpen(const LLSD& key) -{ - // don't reload the same profile - if (getAvatarId() == key.asUUID()) - { - return; - } - - FSPanelProfileTab::onOpen(key); - - mPanelSecondlife = findChild(PANEL_SECONDLIFE); - mPanelWeb = findChild(PANEL_WEB); - mPanelInterests = findChild(PANEL_INTERESTS); - mPanelPicks = findChild(PANEL_PICKS); - mPanelClassifieds = findChild(PANEL_CLASSIFIEDS); - mPanelFirstlife = findChild(PANEL_FIRSTLIFE); - mPanelNotes = findChild(PANEL_NOTES); - - mPanelSecondlife->onOpen(getAvatarId()); - mPanelWeb->onOpen(getAvatarId()); - mPanelInterests->onOpen(getAvatarId()); - mPanelPicks->onOpen(getAvatarId()); - mPanelClassifieds->onOpen(getAvatarId()); - mPanelFirstlife->onOpen(getAvatarId()); - mPanelNotes->onOpen(getAvatarId()); - - mPanelSecondlife->setEmbedded(getEmbedded()); - mPanelWeb->setEmbedded(getEmbedded()); - mPanelInterests->setEmbedded(getEmbedded()); - mPanelPicks->setEmbedded(getEmbedded()); - mPanelClassifieds->setEmbedded(getEmbedded()); - mPanelFirstlife->setEmbedded(getEmbedded()); - mPanelNotes->setEmbedded(getEmbedded()); - - // Always request the base profile info - resetLoading(); - updateData(); - - // Only show commit buttons on own profile on floater version - if (getSelfProfile() && !getEmbedded()) - { - getChild("ok_btn")->setVisible(TRUE); - getChild("cancel_btn")->setVisible(TRUE); - } - - mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&FSPanelProfile::onAvatarNameCache, this, _1, _2)); -} - -void FSPanelProfile::updateData() -{ - LLUUID avatar_id = getAvatarId(); - if (!getIsLoading() && avatar_id.notNull()) - { - setIsLoading(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); - } -} - -void FSPanelProfile::apply() -{ - if (getSelfProfile()) - { - //KC - Avatar data is spread over 3 different panels - // collect data from the last 2 and give to the first to save - LLAvatarData data = LLAvatarData(); - data.avatar_id = gAgentID; - mPanelFirstlife->apply(&data); - mPanelWeb->apply(&data); - mPanelSecondlife->apply(&data); - - mPanelInterests->apply(); - mPanelPicks->apply(); - mPanelNotes->apply(); - } -} - -void FSPanelProfile::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - mAvatarNameCacheConnection.disconnect(); - - mPanelSecondlife->onAvatarNameCache(agent_id, av_name); - mPanelWeb->onAvatarNameCache(agent_id, av_name); -} diff --git a/indra/newview/fspanelprofile.h b/indra/newview/fspanelprofile.h deleted file mode 100644 index a403f805ef..0000000000 --- a/indra/newview/fspanelprofile.h +++ /dev/null @@ -1,665 +0,0 @@ -/** - * @file fspanelprofile.h - * @brief Legacy Profile Floater - * - * $LicenseInfo:firstyear=2012&license=fsviewerlgpl$ - * Phoenix Firestorm Viewer Source Code - * Copyright (C) 2012, Kadah Coba - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA - * http://www.firestormviewer.org - * $/LicenseInfo$ - */ - -#ifndef FS_PANELPROFILE_H -#define FS_PANELPROFILE_H - -#include "llfloater.h" -#include "llavatarpropertiesprocessor.h" -#include "llcallingcard.h" -#include "llvoiceclient.h" -#include "llmediactrl.h" -#include "llremoteparcelrequest.h" -#include "rlvhandler.h" - -class LLAvatarName; -class LLCheckBoxCtrl; -class LLTabContainer; -class LLTextBox; -class LLTextureCtrl; -class LLMediaCtrl; -class LLGroupList; -class LLTextBase; -class LLMenuButton; -class LLLineEditor; -class LLTextEditor; -class FSPanelClassifieds; - -/** -* Base class for any Profile View or My Profile Panel. -*/ -class FSPanelProfileTab - : public LLPanel - , public LLAvatarPropertiesObserver -{ -public: - - /** - * Sets avatar ID, sets panel as observer of avatar related info replies from server. - */ - virtual void setAvatarId(const LLUUID& id); - - /** - * Sends update data request to server. - */ - virtual void updateData() { } - - /** - * Processes data received from server. - */ - virtual void processProperties(void* data, EAvatarProcessorType type) = 0; - - /** - * Returns avatar ID. - */ - const LLUUID& getAvatarId() { return mAvatarId; } - - /** - * Clears panel data if viewing avatar info for first time and sends update data request. - */ - virtual void onOpen(const LLSD& key); - - /*virtual*/ ~FSPanelProfileTab(); - - void setEmbedded(bool embedded) { mEmbedded = embedded; } - -protected: - - FSPanelProfileTab(); - - virtual void enableControls(); - - // mLoading: false: Initial state, can request - // true: Data requested, skip duplicate requests (happens due to LLUI's habit of repeated callbacks) - // mLoaded: false: Initial state, show loading indicator - // true: Data recieved, which comes in a single message, hide indicator - bool getIsLoading() { return mLoading; } - void setIsLoading() { mLoading = true; } - bool getIsLoaded() { return mLoaded; } - void resetLoading() { mLoading = false; mLoaded = false; } - - const bool getEmbedded() const { return mEmbedded; } - - const bool getSelfProfile() const { return mSelfProfile; } - - void setApplyProgress(bool started); - -private: - - LLUUID mAvatarId; - bool mLoading; - bool mLoaded; - bool mEmbedded; - bool mSelfProfile; -}; - - -/** -* Panel for displaying Avatar's second life related info. -*/ -class FSPanelProfileSecondLife - : public FSPanelProfileTab - , public LLFriendObserver - , public LLVoiceClientStatusObserver -{ -public: - FSPanelProfileSecondLife(); - /*virtual*/ ~FSPanelProfileSecondLife(); - - /*virtual*/ void onOpen(const LLSD& key); - - /** - * Saves changes. - */ - void apply(LLAvatarData* data); - - /** - * LLFriendObserver trigger - */ - virtual void changed(U32 mask); - - // Implements LLVoiceClientStatusObserver::onChange() to enable the call - // button when voice is available - /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - - /*virtual*/ void setAvatarId(const LLUUID& id); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /** - * Sends update data request to server. - */ - /*virtual*/ void updateData(); - - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - -protected: - /** - * Process profile related data received from server. - */ - virtual void processProfileProperties(const LLAvatarData* avatar_data); - - /** - * Processes group related data received from server. - */ - virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); - - /** - * Fills common for Avatar profile and My Profile fields. - */ - virtual void fillCommonData(const LLAvatarData* avatar_data); - - /** - * Fills partner data. - */ - virtual void fillPartnerData(const LLAvatarData* avatar_data); - - /** - * Fills account status. - */ - virtual void fillAccountStatus(const LLAvatarData* avatar_data); - - void onMapButtonClick(); - - /** - * Opens "Pay Resident" dialog. - */ - void pay(); - - /** - * Add/remove resident to/from your block list. - */ - void toggleBlock(); - - void updateButtons(); - - void onAddFriendButtonClick(); - void onIMButtonClick(); - void onTeleportButtonClick(); - - void onCopyToClipboard(); - void onCopyURI(); - void onGroupInvite(); - - bool isGrantedToSeeOnlineStatus(); - - /** - * Displays avatar's online status if possible. - * - * Requirements from EXT-3880: - * For friends: - * - Online when online and privacy settings allow to show - * - Offline when offline and privacy settings allow to show - * - Else: nothing - * For other avatars: - * - Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online" - * - Else: Offline - */ - void updateOnlineStatus(); - void processOnlineStatus(bool online); - - virtual void enableControls(); - -private: - void onClickSetName(); - void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name); - -private: - typedef std::map group_map_t; - group_map_t mGroups; - void openGroupProfile(); - - LLTextBox* mStatusText; - LLGroupList* mGroupList; - LLCheckBoxCtrl* mShowInSearchCheckbox; - LLTextureCtrl* mSecondLifePic; - LLTextBase* mDescriptionEdit; - LLButton* mTeleportButton; - LLButton* mShowOnMapButton; - LLButton* mBlockButton; - LLButton* mUnblockButton; - LLButton* mDisplayNameButton; - LLButton* mAddFriendButton; - LLButton* mGroupInviteButton; - LLButton* mPayButton; - LLButton* mIMButton; - LLMenuButton* mOverflowButton; - - bool mVoiceStatus; - - boost::signals2::connection mRlvBehaviorCallbackConnection; - void updateRlvRestrictions(ERlvBehaviour behavior); -}; - - -/** -* Panel for displaying Avatar's web profile and home page. -*/ -class FSPanelProfileWeb - : public FSPanelProfileTab - , public LLViewerMediaObserver -{ -public: - FSPanelProfileWeb(); - /*virtual*/ ~FSPanelProfileWeb(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /** - * Saves changes. - */ - void apply(LLAvatarData* data); - - /** - * Loads web profile. - */ - /*virtual*/ void updateData(); - - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); - - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - - virtual void enableControls(); - -protected: - void onCommitLoad(LLUICtrl* ctrl); - void onCommitWebProfile(LLUICtrl* ctrl); - -private: - std::string mURLHome; - std::string mURLWebProfile; - LLMediaCtrl* mWebBrowser; - LLUICtrl* mWebProfileButton; - LLUICtrl* mLoadButton; - LLLineEditor* mUrlEdit; - - LLFrameTimer mPerformanceTimer; - bool mFirstNavigate; -}; - -/** -* Panel for displaying Avatar's interests. -*/ -class FSPanelProfileInterests - : public FSPanelProfileTab -{ -public: - FSPanelProfileInterests(); - /*virtual*/ ~FSPanelProfileInterests(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /** - * Saves changes. - */ - virtual void apply(); - -protected: - virtual void enableControls(); - -private: - LLCheckBoxCtrl* mWantChecks[8]; - LLCheckBoxCtrl* mSkillChecks[6]; - LLLineEditor* mWantToEditor; - LLLineEditor* mSkillsEditor; - LLLineEditor* mLanguagesEditor; -}; - - -/** -* Panel for displaying Avatar's picks. -*/ - -class FSPanelPick - : public FSPanelProfileTab - , public LLRemoteParcelInfoObserver -{ -public: - - // Creates new panel - static FSPanelPick* create(); - - /*virtual*/ ~FSPanelPick(); - - /*virtual*/ BOOL postBuild(); - - void setAvatarId(const LLUUID& avatar_id); - - void setPickId(const LLUUID& id) { mPickId = id; } - virtual LLUUID& getPickId() { return mPickId; } - - virtual void setPickName(const std::string& name); - const std::string getPickName(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /** - * Saves changes. - */ - virtual void apply(); - - void updateTabLabel(const std::string& title); - - //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing - /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); - /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } - /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; - -protected: - - FSPanelPick(); - - /** - * Sends remote parcel info request to resolve parcel name from its ID. - */ - void sendParcelInfoRequest(); - - /** - * "Location text" is actually the owner name, the original - * name that owner gave the parcel, and the location. - */ - static std::string createLocationText( - const std::string& owner_name, - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global); - - /** - * Sets snapshot id. - * - * Will mark snapshot control as valid if id is not null. - * Will mark snapshot control as invalid if id is null. If null id is a valid value, - * you have to manually mark snapshot is valid. - */ - virtual void setSnapshotId(const LLUUID& id); - virtual void setPickDesc(const std::string& desc); - virtual void setPickLocation(const std::string& location); - - virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - virtual LLVector3d& getPosGlobal() { return mPosGlobal; } - - /** - * Callback for "Map" button, opens Map - */ - void onClickMap(); - - /** - * Callback for "Teleport" button, teleports user to Pick location. - */ - void onClickTeleport(); - - /** - * Enables/disables "Save" button - */ - void enableSaveButton(BOOL enable); - - /** - * Called when snapshot image changes. - */ - void onSnapshotChanged(); - - /** - * Callback for Pick snapshot, name and description changed event. - */ - void onPickChanged(LLUICtrl* ctrl); - - /** - * Resets panel and all cantrols to unedited state - */ - /*virtual*/ void resetDirty(); - - /** - * Returns true if any of Pick properties was changed by user. - */ - /*virtual*/ BOOL isDirty() const; - - /** - * Callback for "Set Location" button click - */ - void onClickSetLocation(); - - /** - * Callback for "Save" button click - */ - void onClickSave(); - - std::string getLocationNotice(); - - /** - * Sends Pick properties to server. - */ - void sendUpdate(); - -protected: - - LLTextureCtrl* mSnapshotCtrl; - LLLineEditor* mPickName; - LLTextEditor* mPickDescription; - LLButton* mSetCurrentLocationButton; - LLButton* mSaveButton; - - LLVector3d mPosGlobal; - LLUUID mParcelId; - LLUUID mPickId; - LLUUID mRequestedId; - - bool mLocationChanged; - bool mNewPick; - bool mIsEditing; - - std::string mCurrentPickDescription; - - void onDescriptionFocusReceived(); -}; - -class FSPanelProfilePicks - : public FSPanelProfileTab -{ -public: - FSPanelProfilePicks(); - /*virtual*/ ~FSPanelProfilePicks(); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /** - * Saves changes. - */ - virtual void apply(); - - /** - * Sends update data request to server. - */ - /*virtual*/ void updateData(); - -private: - void onClickNewBtn(); - void onClickDelete(); - void callbackDeletePick(const LLSD& notification, const LLSD& response); - - boost::signals2::connection mRlvBehaviorCallbackConnection; - void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type); - - bool canAddNewPick(); - bool canDeletePick(); - - LLTabContainer* mTabContainer; - LLUICtrl* mNoItemsLabel; - LLButton* mNewButton; - LLButton* mDeleteButton; -}; - - - -/** -* Panel for displaying Avatar's first life related info. -*/ -class FSPanelProfileFirstLife - : public FSPanelProfileTab -{ -public: - FSPanelProfileFirstLife(); - /*virtual*/ ~FSPanelProfileFirstLife(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /** - * Saves changes. - */ - void apply(LLAvatarData* data); - -protected: - virtual void enableControls(); - void onDescriptionFocusReceived(); - - LLTextEditor* mDescriptionEdit; - LLTextureCtrl* mPicture; - - bool mIsEditing; - std::string mCurrentDescription; -}; - -/** - * Panel for displaying Avatar's notes and modifying friend's rights. - */ -class FSPanelAvatarNotes - : public FSPanelProfileTab - , public LLFriendObserver -{ -public: - FSPanelAvatarNotes(); - /*virtual*/ ~FSPanelAvatarNotes(); - - virtual void setAvatarId(const LLUUID& id); - - /** - * LLFriendObserver trigger - */ - virtual void changed(U32 mask); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void resetData(); - - /*virtual*/ void updateData(); - - /** - * Saves changes. - */ - virtual void apply(); - -protected: - /** - * Fills rights data for friends. - */ - void fillRightsData(); - - void rightsConfirmationCallback(const LLSD& notification, const LLSD& response, S32 rights); - void confirmModifyRights(bool grant, S32 rights); - void onCommitRights(); - void onCommitNotes(); - void enableCheckboxes(bool enable); - - LLCheckBoxCtrl* mOnlineStatus; - LLCheckBoxCtrl* mMapRights; - LLCheckBoxCtrl* mEditObjectRights; - LLTextEditor* mNotesEditor; -}; - - -/* -* -* Container panel for the profile tabs -*/ -class FSPanelProfile - : public FSPanelProfileTab -{ -public: - FSPanelProfile(); - /*virtual*/ ~FSPanelProfile(); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void updateData(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ void onOpen(const LLSD& key); - - /** - * Saves changes. - */ - void apply(); - -private: - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); - void onTabChange(); - - FSPanelProfileSecondLife* mPanelSecondlife; - FSPanelProfileWeb* mPanelWeb; - FSPanelProfileInterests* mPanelInterests; - FSPanelProfilePicks* mPanelPicks; - FSPanelClassifieds* mPanelClassifieds; - FSPanelProfileFirstLife* mPanelFirstlife; - FSPanelAvatarNotes* mPanelNotes; - LLTabContainer* mTabContainer; - - boost::signals2::connection mAvatarNameCacheConnection; -}; - -#endif // FS_PANELPROFILE_H diff --git a/indra/newview/fspanelprofileclassifieds.cpp b/indra/newview/fspanelprofileclassifieds.cpp deleted file mode 100644 index b709ed9d04..0000000000 --- a/indra/newview/fspanelprofileclassifieds.cpp +++ /dev/null @@ -1,781 +0,0 @@ -/** - * @file fspanelprofileclassifieds.cpp - * @brief FSPanelClassifieds and related class implementations - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "fspanelprofileclassifieds.h" - -#include "llagent.h" -#include "llflatlistview.h" -#include "llfloaterreg.h" -#include "llfloaterworldmap.h" -#include "llnotificationsutil.h" -#include "lltrans.h" -#include "llmenugl.h" -#include "llviewermenu.h" -#include "llviewergenericmessage.h" -#include "llregistry.h" - -#include "llavatarpropertiesprocessor.h" -#include "fsdispatchclassifiedclickthrough.h" -#include "fspanelprofile.h" -#include "fspanelclassified.h" - -static const std::string XML_BTN_NEW = "new_btn"; -static const std::string XML_BTN_DELETE = "trash_btn"; -static const std::string XML_BTN_INFO = "info_btn"; -static const std::string XML_BTN_TELEPORT = "teleport_btn"; -static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; - -static const std::string PICK_ID("pick_id"); -static const std::string PICK_CREATOR_ID("pick_creator_id"); -static const std::string PICK_NAME("pick_name"); - -static const std::string CLASSIFIED_ID("classified_id"); -static const std::string CLASSIFIED_NAME("classified_name"); - -static FSDispatchClassifiedClickThrough sClassifiedClickThrough; - -static LLPanelInjector t_panel_fs_classifieds("panel_fs_profile_classified"); - -////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -// FSPanelClassifieds -//----------------------------------------------------------------------------- -FSPanelClassifieds::FSPanelClassifieds() -: FSPanelProfileTab(), - mPopupMenu(NULL), - mClassifiedsList(NULL), - mPanelClassifiedInfo(NULL), - mNoClassifieds(false), - mRlvBehaviorCallbackConnection() -{ -} - -FSPanelClassifieds::~FSPanelClassifieds() -{ - if (getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } - - if (mRlvBehaviorCallbackConnection.connected()) - { - mRlvBehaviorCallbackConnection.disconnect(); - } - - gGenericDispatcher.addHandler("classifiedclickthrough", NULL); -} - -void FSPanelClassifieds::updateData() -{ - // Send Picks request only when we need to, not on every onOpen(during tab switch). - if (isDirty()) - { - mNoClassifieds = false; - - mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); - mNoItemsLabel->setVisible(TRUE); - - mClassifiedsList->clear(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(getAvatarId()); - } -} - -void FSPanelClassifieds::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_CLASSIFIEDS == type) - { - LLAvatarClassifieds* c_info = static_cast(data); - if (c_info && getAvatarId() == c_info->target_id) - { - // do not clear classified list in case we will receive two or more data packets. - // list has been cleared in updateData(). (fix for EXT-6436) - - LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin(); - for (; c_info->classifieds_list.end() != it; ++it) - { - LLAvatarClassifieds::classified_data c_data = *it; - - FSClassifiedItem* c_item = new FSClassifiedItem(getAvatarId(), c_data.classified_id); - c_item->childSetAction("info_chevron", boost::bind(&FSPanelClassifieds::onClickInfo, this)); - c_item->setClassifiedName(c_data.name); - - LLSD pick_value = LLSD(); - pick_value.insert(CLASSIFIED_ID, c_data.classified_id); - pick_value.insert(CLASSIFIED_NAME, c_data.name); - - if (!findClassifiedById(c_data.classified_id)) - { - mClassifiedsList->addItem(c_item, pick_value); - } - - c_item->setDoubleClickCallback(boost::bind(&FSPanelClassifieds::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&FSPanelClassifieds::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&FSPanelClassifieds::updateButtons, this)); - } - - resetDirty(); - updateButtons(); - } - - mNoClassifieds = !mClassifiedsList->size(); - - bool no_data = mNoClassifieds; - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if (getAvatarId() == gAgentID) - { - mNoItemsLabel->setValue(LLTrans::getString("NoClassifiedsText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarClassifiedsText")); - } - } - - enableControls(); - } -} - -FSClassifiedItem* FSPanelClassifieds::getSelectedClassifiedItem() -{ - LLPanel* selected_item = mClassifiedsList->getSelectedItem(); - if (!selected_item) - { - return NULL; - } - return dynamic_cast(selected_item); -} - -BOOL FSPanelClassifieds::postBuild() -{ - mClassifiedsList = getChild("classifieds_list"); - mClassifiedsList->setCommitOnSelectionChange(true); - mClassifiedsList->setCommitCallback(boost::bind(&FSPanelClassifieds::onListCommit, this, mClassifiedsList)); - mClassifiedsList->setNoItemsCommentText(getString("no_classifieds")); - - mNoItemsLabel = getChild("picks_panel_text"); - - childSetAction(XML_BTN_NEW, boost::bind(&FSPanelClassifieds::createNewClassified, this)); - childSetAction(XML_BTN_DELETE, boost::bind(&FSPanelClassifieds::onClickDelete, this)); - childSetAction(XML_BTN_TELEPORT, boost::bind(&FSPanelClassifieds::onClickTeleport, this)); - childSetAction(XML_BTN_SHOW_ON_MAP, boost::bind(&FSPanelClassifieds::onClickMap, this)); - childSetAction(XML_BTN_INFO, boost::bind(&FSPanelClassifieds::onClickInfo, this)); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; - registar.add("Classified.Info", boost::bind(&FSPanelClassifieds::onClickInfo, this)); - registar.add("Classified.Edit", boost::bind(&FSPanelClassifieds::onClickMenuEdit, this)); - registar.add("Classified.Teleport", boost::bind(&FSPanelClassifieds::onClickTeleport, this)); - registar.add("Classified.Map", boost::bind(&FSPanelClassifieds::onClickMap, this)); - registar.add("Classified.Delete", boost::bind(&FSPanelClassifieds::onClickDelete, this)); - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registar; - enable_registar.add("Classified.Enable", boost::bind(&FSPanelClassifieds::onEnableMenuItem, this, _2)); - - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_classifieds.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&FSPanelClassifieds::updateRlvRestrictions, this, _1, _2)); - childSetEnabled(XML_BTN_NEW, !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); - - return TRUE; -} - -bool FSPanelClassifieds::isClassifiedPublished(FSClassifiedItem* c_item) -{ - if (c_item) - { - FSPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if (panel) - { - return !panel->isNewWithErrors(); - } - - // we've got this classified from server - it's published - return true; - } - return false; -} - -void FSPanelClassifieds::onOpen(const LLSD& key) -{ - const LLUUID id(key.asUUID()); - BOOL self = (gAgentID == id); - - // only agent can edit her picks - getChildView("edit_panel")->setEnabled(self); - getChildView("edit_panel")->setVisible( self); - - // Disable buttons when viewing profile for first time - if (getAvatarId() != id) - { - getChildView(XML_BTN_INFO)->setEnabled(FALSE); - getChildView(XML_BTN_TELEPORT)->setEnabled(FALSE); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(FALSE); - } - - if (getAvatarId() != id) - { - mClassifiedsList->goToTop(); - // Set dummy value to make panel dirty and make it reload picks - setValue(LLSD()); - } - - FSPanelProfileTab::onOpen(key); - - gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); - updateData(); - updateButtons(); -} - -void FSPanelClassifieds::onClosePanel() -{ - if (mPanelClassifiedInfo) - { - onPanelClassifiedClose(mPanelClassifiedInfo); - } -} - -void FSPanelClassifieds::onListCommit(const LLFlatListView* f_list) -{ - updateButtons(); -} - -//static -void FSPanelClassifieds::onClickDelete() -{ - LLSD value = mClassifiedsList->getSelectedValue(); - if (value.isDefined()) - { - LLSD args; - args["NAME"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&FSPanelClassifieds::callbackDeleteClassified, this, _1, _2)); - return; - } -} - -bool FSPanelClassifieds::callbackDeleteClassified(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLSD value = mClassifiedsList->getSelectedValue(); - - if (0 == option) - { - LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]); - mClassifiedsList->removeItemByValue(value); - } - mNoItemsLabel->setVisible(!mClassifiedsList->size()); - updateButtons(); - return false; -} - -bool FSPanelClassifieds::callbackTeleport( const LLSD& notification, const LLSD& response ) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - onClickTeleport(); - } - return false; -} - -//static -void FSPanelClassifieds::onClickTeleport() -{ - FSClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if (c_item) - { - pos = c_item->getPosGlobal(); - FSPanelClassifiedInfo::sendClickMessage("teleport", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - } - - if (!pos.isExactlyZero()) - { - gAgent.teleportViaLocation(pos); - LLFloaterWorldMap::getInstance()->trackLocation(pos); - } -} - -//static -void FSPanelClassifieds::onClickMap() -{ - FSClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if (c_item) - { - FSPanelClassifiedInfo::sendClickMessage("map", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - pos = c_item->getPosGlobal(); - } - - LLFloaterWorldMap::getInstance()->trackLocation(pos); - LLFloaterReg::showInstance("world_map", "center"); -} - - -void FSPanelClassifieds::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask) -{ - updateButtons(); - - if (mPopupMenu) - { - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - ((LLContextMenu*)mPopupMenu)->show(x, y); - LLMenuGL::showPopup(item, mPopupMenu, x, y); - } -} - -void FSPanelClassifieds::onDoubleClickClassifiedItem(LLUICtrl* item) -{ - LLSD value = mClassifiedsList->getSelectedValue(); - if (value.isUndefined()) return; - - LLSD args; - args["CLASSIFIED"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("TeleportToClassified", args, LLSD(), boost::bind(&FSPanelClassifieds::callbackTeleport, this, _1, _2)); -} - -void FSPanelClassifieds::updateButtons() -{ - bool has_selected = mClassifiedsList->numSelected() > 0; - - if (getAvatarId() == gAgentID) - { - getChildView(XML_BTN_DELETE)->setEnabled(has_selected); - } - - getChildView(XML_BTN_INFO)->setEnabled(has_selected); - getChildView(XML_BTN_TELEPORT)->setEnabled(has_selected); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(has_selected); - - FSClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if (c_item) - { - getChildView(XML_BTN_INFO)->setEnabled(isClassifiedPublished(c_item)); - } -} - -void FSPanelClassifieds::createNewClassified() -{ - FSPanelClassifiedEdit* panel = NULL; - createClassifiedEditPanel(&panel); - - openPanel(panel, LLSD()); -} - -void FSPanelClassifieds::onClickInfo() -{ - if (mClassifiedsList->numSelected() > 0) - { - openClassifiedInfo(); - } -} - -void FSPanelClassifieds::openClassifiedInfo() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) - { - return; - } - - FSClassifiedItem* c_item = getSelectedClassifiedItem(); - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["classified_snapshot_id"] = c_item->getSnapshotId(); - params["classified_name"] = c_item->getClassifiedName(); - params["classified_desc"] = c_item->getDescription(); - params["from_search"] = false; - - openClassifiedInfo(params); -} - -void FSPanelClassifieds::openClassifiedInfo(const LLSD ¶ms) -{ - createClassifiedInfoPanel(); - openPanel(mPanelClassifiedInfo, params); -} - -void FSPanelClassifieds::openClassifiedEdit(const LLSD& params) -{ - LLUUID classified_id = params["classified_id"].asUUID();; - LL_INFOS("FSPanelClassifieds") << "opening classified " << classified_id << " for edit" << LL_ENDL; - editClassified(classified_id); -} - -void FSPanelClassifieds::onPanelPickClose(LLPanel* panel) -{ - closePanel(panel); -} - -void FSPanelClassifieds::onPanelClassifiedSave(FSPanelClassifiedEdit* panel) -{ - if (!panel->canClose()) - { - return; - } - - if (panel->isNew()) - { - mEditClassifiedPanels[panel->getClassifiedId()] = panel; - - FSClassifiedItem* c_item = new FSClassifiedItem(getAvatarId(), panel->getClassifiedId()); - c_item->fillIn(panel); - - LLSD c_value; - c_value.insert(CLASSIFIED_ID, c_item->getClassifiedId()); - c_value.insert(CLASSIFIED_NAME, c_item->getClassifiedName()); - mClassifiedsList->addItem(c_item, c_value, ADD_TOP); - - c_item->setDoubleClickCallback(boost::bind(&FSPanelClassifieds::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&FSPanelClassifieds::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&FSPanelClassifieds::updateButtons, this)); - c_item->childSetAction("info_chevron", boost::bind(&FSPanelClassifieds::onClickInfo, this)); - - mNoItemsLabel->setVisible(FALSE); - } - else if (panel->isNewWithErrors()) - { - FSClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (c_item) - { - c_item->fillIn(panel); - } - } - else - { - onPanelClassifiedClose(panel); - return; - } - - onPanelPickClose(panel); - updateButtons(); -} - -void FSPanelClassifieds::onPanelClassifiedClose(FSPanelClassifiedInfo* panel) -{ - if (panel->getInfoLoaded() && !panel->isDirty()) - { - std::vector values; - mClassifiedsList->getValues(values); - for (size_t n = 0; n < values.size(); ++n) - { - LLUUID c_id = values[n][CLASSIFIED_ID].asUUID(); - if (panel->getClassifiedId() == c_id) - { - FSClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getItemByValue(values[n])); - llassert(c_item); - if (c_item) - { - c_item->setClassifiedName(panel->getClassifiedName()); - c_item->setDescription(panel->getDescription()); - c_item->setSnapshotId(panel->getSnapshotId()); - } - } - } - } - - onPanelPickClose(panel); - updateButtons(); -} - -void FSPanelClassifieds::createClassifiedInfoPanel() -{ - mPanelClassifiedInfo = FSPanelClassifiedInfo::create(); - mPanelClassifiedInfo->setExitCallback(boost::bind(&FSPanelClassifieds::onPanelClassifiedClose, this, mPanelClassifiedInfo)); - mPanelClassifiedInfo->setEditClassifiedCallback(boost::bind(&FSPanelClassifieds::onPanelClassifiedEdit, this)); - mPanelClassifiedInfo->setVisible(FALSE); -} - -void FSPanelClassifieds::createClassifiedEditPanel(FSPanelClassifiedEdit** panel) -{ - if (panel) - { - FSPanelClassifiedEdit* new_panel = FSPanelClassifiedEdit::create(); - new_panel->setExitCallback(boost::bind(&FSPanelClassifieds::onPanelClassifiedClose, this, new_panel)); - new_panel->setSaveCallback(boost::bind(&FSPanelClassifieds::onPanelClassifiedSave, this, new_panel)); - new_panel->setCancelCallback(boost::bind(&FSPanelClassifieds::onPanelClassifiedClose, this, new_panel)); - new_panel->setVisible(FALSE); - *panel = new_panel; - } -} - -void FSPanelClassifieds::onPanelClassifiedEdit() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) - { - return; - } - - FSClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (!c_item) - { - return; - } - editClassified(c_item->getClassifiedId()); -} - -FSClassifiedItem *FSPanelClassifieds::findClassifiedById(const LLUUID& classified_id) -{ - // HACK - find item by classified id. Should be a better way. - std::vector items; - mClassifiedsList->getItems(items); - FSClassifiedItem* c_item = NULL; - for (std::vector::iterator it = items.begin(); it != items.end(); ++it) - { - FSClassifiedItem *test_item = dynamic_cast(*it); - if (test_item && test_item->getClassifiedId() == classified_id) - { - c_item = test_item; - break; - } - } - return c_item; -} - -void FSPanelClassifieds::editClassified(const LLUUID& classified_id) -{ - FSClassifiedItem* c_item = findClassifiedById(classified_id); - if (!c_item) - { - LL_WARNS("FSPanelClassifieds") << "item not found for classified_id " << classified_id << LL_ENDL; - return; - } - - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["snapshot_id"] = c_item->getSnapshotId(); - params["name"] = c_item->getClassifiedName(); - params["desc"] = c_item->getDescription(); - params["category"] = (S32)c_item->getCategory(); - params["content_type"] = (S32)c_item->getContentType(); - params["auto_renew"] = c_item->getAutoRenew(); - params["price_for_listing"] = c_item->getPriceForListing(); - params["location_text"] = c_item->getLocationText(); - - FSPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if (!panel) - { - createClassifiedEditPanel(&panel); - mEditClassifiedPanels[c_item->getClassifiedId()] = panel; - } - openPanel(panel, params); - panel->setPosGlobal(c_item->getPosGlobal()); -} - -void FSPanelClassifieds::onClickMenuEdit() -{ - if (getSelectedClassifiedItem()) - { - onPanelClassifiedEdit(); - } -} - -bool FSPanelClassifieds::onEnableMenuItem(const LLSD& user_data) -{ - std::string param = user_data.asString(); - - FSClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if (c_item && "info" == param) - { - // dont show Info panel if classified was not created - return isClassifiedPublished(c_item); - } - - return true; -} - -//hack -void FSPanelClassifieds::openPanel(LLPanel* panel, const LLSD& params) -{ - // Add the panel or bring it to front. - if (panel->getParent() != this) - { - addChild(panel); - } - else - { - sendChildToFront(panel); - } - - panel->setVisible(TRUE); - panel->setFocus(TRUE); // prevent losing focus by the floater - panel->onOpen(params); - - LLRect new_rect = getRect(); - panel->reshape(new_rect.getWidth(), new_rect.getHeight()); - new_rect.setLeftTopAndSize(0, new_rect.getHeight(), new_rect.getWidth(), new_rect.getHeight()); - panel->setRect(new_rect); -} - -//hack -void FSPanelClassifieds::closePanel(LLPanel* panel) -{ - panel->setVisible(FALSE); - - if (panel->getParent() == this) - { - removeChild(panel); - - // Prevent losing focus by the floater - const child_list_t* child_list = getChildList(); - if (child_list->size() > 0) - { - child_list->front()->setFocus(TRUE); - } - else - { - LL_WARNS("FSPanelClassifieds") << "No underlying panel to focus." << LL_ENDL; - } - } -} - -void FSPanelClassifieds::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) -{ - if (behavior == RLV_BHVR_SHOWLOC) - { - childSetEnabled(XML_BTN_NEW, type != RLV_TYPE_ADD); - } -} - - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -FSClassifiedItem::FSClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id) - : LLPanel() - , mAvatarId(avatar_id) - , mClassifiedId(classified_id) -{ - buildFromFile("panel_classifieds_list_item.xml"); - - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); -} - -FSClassifiedItem::~FSClassifiedItem() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -void FSClassifiedItem::processProperties(void* data, EAvatarProcessorType type) -{ - if (APT_CLASSIFIED_INFO != type) - { - return; - } - - LLAvatarClassifiedInfo* c_info = static_cast(data); - if (!c_info || c_info->classified_id != getClassifiedId()) - { - return; - } - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setPosGlobal(c_info->pos_global); - - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -void set_child_visible2(LLView* parent, const std::string& child_name, bool visible) -{ - parent->getChildView(child_name)->setVisible(visible); -} - -BOOL FSClassifiedItem::postBuild() -{ - setMouseEnterCallback(boost::bind(&set_child_visible2, this, "hovered_icon", true)); - setMouseLeaveCallback(boost::bind(&set_child_visible2, this, "hovered_icon", false)); - return TRUE; -} - -void FSClassifiedItem::setValue(const LLSD& value) -{ - if (!value.isMap()) - { - return; - } - if (!value.has("selected")) - { - return; - } - getChildView("selected_icon")->setVisible( value["selected"]); -} - -void FSClassifiedItem::fillIn(FSPanelClassifiedEdit* panel) -{ - if (!panel) - { - return; - } - - setClassifiedName(panel->getClassifiedName()); - setDescription(panel->getDescription()); - setSnapshotId(panel->getSnapshotId()); - setCategory(panel->getCategory()); - setContentType(panel->getContentType()); - setAutoRenew(panel->getAutoRenew()); - setPriceForListing(panel->getPriceForListing()); - setPosGlobal(panel->getPosGlobal()); - setLocationText(panel->getClassifiedLocation()); -} - -void FSClassifiedItem::setClassifiedName(const std::string& name) -{ - getChild("name")->setValue(name); -} - -void FSClassifiedItem::setDescription(const std::string& desc) -{ - getChild("description")->setValue(desc); -} - -void FSClassifiedItem::setSnapshotId(const LLUUID& snapshot_id) -{ - getChild("picture")->setValue(snapshot_id); -} - -LLUUID FSClassifiedItem::getSnapshotId() -{ - return getChild("picture")->getValue(); -} - -//EOF diff --git a/indra/newview/fspanelprofileclassifieds.h b/indra/newview/fspanelprofileclassifieds.h deleted file mode 100644 index 8328dcb681..0000000000 --- a/indra/newview/fspanelprofileclassifieds.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @file fspanelprofileclassifieds.h - * @brief FSPanelClassifieds and related class definitions - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef FS_PANELCLASSIFIEDS_H -#define FS_PANELCLASSIFIEDS_H - -#include "llpanel.h" -#include "v3dmath.h" -#include "lluuid.h" -#include "llavatarpropertiesprocessor.h" -#include "fspanelprofile.h" -#include "llregistry.h" - -class LLMessageSystem; -class LLVector3d; -class FSPanelProfileTab; -class LLAgent; -class LLMenuGL; -class FSClassifiedItem; -class LLFlatListView; -class FSPanelClassifiedInfo; -class FSPanelClassifiedEdit; - -// *TODO -// Panel Picks has been consolidated with Classifieds (EXT-2095), give FSPanelClassifieds -// and corresponding files (cpp, h, xml) a new name. (new name is TBD at the moment) - -class FSPanelClassifieds - : public FSPanelProfileTab -{ -public: - FSPanelClassifieds(); - ~FSPanelClassifieds(); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void onClosePanel(); - - void processProperties(void* data, EAvatarProcessorType type); - - void updateData(); - - // returns the selected pick item - FSClassifiedItem* getSelectedClassifiedItem(); - FSClassifiedItem* findClassifiedById(const LLUUID& classified_id); - - void createNewClassified(); - -protected: - /*virtual*/void updateButtons(); - -private: - void onClickDelete(); - void onClickTeleport(); - void onClickMap(); - - bool isClassifiedPublished(FSClassifiedItem* c_item); - - void onListCommit(const LLFlatListView* f_list); - - boost::signals2::connection mRlvBehaviorCallbackConnection; - void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type); - - //------------------------------------------------ - // Callbacks which require panel toggling - //------------------------------------------------ - void onClickInfo(); - void onPanelPickClose(LLPanel* panel); - void onPanelClassifiedSave(FSPanelClassifiedEdit* panel); - void onPanelClassifiedClose(FSPanelClassifiedInfo* panel); - void onPanelClassifiedEdit(); - void editClassified(const LLUUID& classified_id); - void onClickMenuEdit(); - - bool onEnableMenuItem(const LLSD& user_data); - - void openClassifiedInfo(); - void openClassifiedInfo(const LLSD& params); - void openClassifiedEdit(const LLSD& params); - - bool callbackDeleteClassified(const LLSD& notification, const LLSD& response); - bool callbackTeleport(const LLSD& notification, const LLSD& response); - - - virtual void onDoubleClickClassifiedItem(LLUICtrl* item); - virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask); - - void createClassifiedInfoPanel(); - void createClassifiedEditPanel(FSPanelClassifiedEdit** panel); - - void openPanel(LLPanel* panel, const LLSD& params); - void closePanel(LLPanel* panel); - - LLMenuGL* mPopupMenu; - LLFlatListView* mClassifiedsList; - FSPanelClassifiedInfo* mPanelClassifiedInfo; - LLUICtrl* mNoItemsLabel; - - // - typedef std::map panel_classified_edit_map_t; - - // This map is needed for newly created classifieds. The purpose of panel is to - // sit in this map and listen to FSPanelClassifiedEdit::processProperties callback. - panel_classified_edit_map_t mEditClassifiedPanels; - - //true if classifieds list is empty after processing classifieds - bool mNoClassifieds; -}; - -class FSClassifiedItem : public LLPanel, public LLAvatarPropertiesObserver -{ -public: - - FSClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id); - - virtual ~FSClassifiedItem(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void setValue(const LLSD& value); - - void fillIn(FSPanelClassifiedEdit* panel); - - LLUUID getAvatarId() {return mAvatarId;} - - void setAvatarId(const LLUUID& avatar_id) {mAvatarId = avatar_id;} - - LLUUID getClassifiedId() {return mClassifiedId;} - - void setClassifiedId(const LLUUID& classified_id) {mClassifiedId = classified_id;} - - void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - - const LLVector3d getPosGlobal() { return mPosGlobal; } - - void setLocationText(const std::string location) { mLocationText = location; } - - std::string getLocationText() { return mLocationText; } - - void setClassifiedName (const std::string& name); - - std::string getClassifiedName() { return getChild("name")->getValue().asString(); } - - void setDescription(const std::string& desc); - - std::string getDescription() { return getChild("description")->getValue().asString(); } - - void setSnapshotId(const LLUUID& snapshot_id); - - LLUUID getSnapshotId(); - - void setCategory(U32 cat) { mCategory = cat; } - - U32 getCategory() { return mCategory; } - - void setContentType(U32 ct) { mContentType = ct; } - - U32 getContentType() { return mContentType; } - - void setAutoRenew(U32 renew) { mAutoRenew = renew; } - - bool getAutoRenew() { return mAutoRenew; } - - void setPriceForListing(S32 price) { mPriceForListing = price; } - - S32 getPriceForListing() { return mPriceForListing; } - -private: - LLUUID mAvatarId; - LLUUID mClassifiedId; - LLVector3d mPosGlobal; - std::string mLocationText; - U32 mCategory; - U32 mContentType; - bool mAutoRenew; - S32 mPriceForListing; -}; - -#endif // FS_PANELCLASSIFIEDS_H diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h index f981e08ff7..21df036cb7 100644 --- a/indra/newview/llagentpicksinfo.h +++ b/indra/newview/llagentpicksinfo.h @@ -74,10 +74,10 @@ public: void decrementNumberOfPicks() { --mNumberOfPicks; } -private: - void onServerRespond(LLAvatarPicks* picks); +private: + /** * Sets number of Picks. */ diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 749b3f9864..50ac64ef4d 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -48,6 +48,7 @@ #include "llfloatergroups.h" #include "llfloaterreg.h" #include "llfloaterpay.h" +#include "llfloaterprofile.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterwebcontent.h" #include "llfloaterworldmap.h" @@ -62,11 +63,14 @@ #include "llnotificationsutil.h" // for LLNotificationsUtil #include "llpaneloutfitedit.h" #include "llpanelprofile.h" +#include "llparcel.h" #include "llrecentpeople.h" #include "lltrans.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llviewermessage.h" // for handle_lure +#include "llviewernetwork.h" //LLGridManager +#include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lltrans.h" #include "llcallingcard.h" @@ -83,7 +87,6 @@ // Firestorm includes #include "fsfloaterim.h" #include "fsfloaterimcontainer.h" -#include "fsfloaterprofile.h" #include "fslslbridge.h" #include "fsradar.h" #include "fsassetblacklist.h" @@ -103,6 +106,48 @@ const U32 KICK_FLAGS_FREEZE = 1 << 0; const U32 KICK_FLAGS_UNFREEZE = 1 << 1; +std::string getProfileURL(const std::string& agent_name, bool feed_only) +{ + // OpenSim support + //std::string url = "[WEB_PROFILE_URL][AGENT_NAME][FEED_ONLY]"; + //LLSD subs; + //subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); + //subs["AGENT_NAME"] = agent_name; + //subs["FEED_ONLY"] = feed_only ? "/?feed_only=true" : ""; + std::string url; + LLSD subs; + +#ifdef OPENSIM + if (LLGridManager::instance().isInOpenSim()) + { + url = LLGridManager::getInstance()->getWebProfileURL(); + if (url.empty()) + { + return LLStringUtil::null; + } + + std::string match = "?name=[AGENT_NAME]"; + if (url.find(match) == std::string::npos) + { + url += match; + } + } + else +#endif + { + url = "[WEB_PROFILE_URL][AGENT_NAME][FEED_ONLY]"; + subs["FEED_ONLY"] = feed_only ? "/?feed_only=true" : ""; + subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); + } + // + + subs["AGENT_NAME"] = agent_name; + url = LLWeb::expandURLSubstitutions(url, subs); + LLStringUtil::toLower(url); + return url; +} + + // static void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name) { @@ -420,94 +465,144 @@ const LLUUID LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUI return session_id; } -static const char* get_profile_floater_name(const LLUUID& avatar_id) -{ - // Use different floater XML for our profile to be able to save its rect. - return avatar_id == gAgentID ? "my_profile" : "profile"; -} - -static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - std::string url = getProfileURL(av_name.getAccountName()); - - // PROFILES: open in webkit window - LLFloaterWebContent::Params p; - p.url(url).id(agent_id.asString()); - LLFloaterReg::showInstance(get_profile_floater_name(agent_id), p); -} - // static -void LLAvatarActions::showProfile(const LLUUID& id) +void LLAvatarActions::showProfile(const LLUUID& avatar_id) { - if (id.notNull()) + if (avatar_id.notNull()) { -// -// LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2)); - if (gSavedSettings.getBOOL("FSUseWebProfiles")) - { - showProfileWeb(id); - } - else - { - showProfileLegacy(id); - } -// + LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)); } } +// static +void LLAvatarActions::showPicks(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showPick(); + } + } +} + +// static +void LLAvatarActions::showPick(const LLUUID& avatar_id, const LLUUID& pick_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showPick(pick_id); + } + } +} + +// static +void LLAvatarActions::createPick() +{ + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgent.getID()))); + LLViewerRegion* region = gAgent.getRegion(); + if (profilefloater && region) + { + LLPickData data; + data.pos_global = gAgent.getPositionGlobal(); + data.sim_name = region->getName(); + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + data.name = parcel->getName(); + data.desc = parcel->getDesc(); + data.snapshot_id = parcel->getSnapshotID(); + data.parcel_id = parcel->getID(); + } + else + { + data.name = region->getName(); + } + + profilefloater->createPick(data); + } +} + +// static +bool LLAvatarActions::isPickTabSelected(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = LLFloaterReg::findTypedInstance("profile", LLSD().with("id", avatar_id)); + if (profilefloater) + { + return profilefloater->isPickTabSelected(); + } + } + return false; +} + +// static +void LLAvatarActions::showClassifieds(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showClassified(); + } + } +} + +// static +void LLAvatarActions::showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showClassified(classified_id, edit); + } + } +} + +// static +void LLAvatarActions::createClassified() +{ + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgent.getID()))); + if (profilefloater) + { + profilefloater->createClassified(); + } +} + //static -bool LLAvatarActions::profileVisible(const LLUUID& id) +bool LLAvatarActions::profileVisible(const LLUUID& avatar_id) { LLSD sd; - sd["id"] = id; - LLFloater* browser = getProfileFloater(id); - return browser && browser->isShown(); + sd["id"] = avatar_id; + LLFloater* floater = getProfileFloater(avatar_id); + return floater && floater->isShown(); } //static -LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& id) +LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& avatar_id) { -// - if (!gSavedSettings.getBOOL("FSUseWebProfiles")) - { - FSFloaterProfile* browser = LLFloaterReg::findTypedInstance("fs_floater_profile", LLSD().with("id", id)); - return browser; - } -// - LLFloaterWebContent *browser = dynamic_cast - (LLFloaterReg::findInstance(get_profile_floater_name(id), LLSD().with("id", id))); - return browser; + LLFloaterProfile* floater = LLFloaterReg::findTypedInstance("profile", LLSD().with("id", avatar_id)); + return floater; } -// -// static -void LLAvatarActions::showProfileWeb(const LLUUID& id) -{ - if (id.notNull()) - { - LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2)); - } -} - -// static -void LLAvatarActions::showProfileLegacy(const LLUUID& id) -{ - if (id.notNull()) - { - LLFloaterReg::showInstance("fs_floater_profile", LLSD().with("id", id)); - } -} -// - //static -void LLAvatarActions::hideProfile(const LLUUID& id) +void LLAvatarActions::hideProfile(const LLUUID& avatar_id) { LLSD sd; - sd["id"] = id; - LLFloater* browser = getProfileFloater(id); - if (browser) + sd["id"] = avatar_id; + LLFloater* floater = getProfileFloater(avatar_id); + if (floater) { - browser->closeFloater(); + floater->closeFloater(); } } @@ -1235,7 +1330,7 @@ bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NUL } // static -void LLAvatarActions::toggleBlock(const LLUUID& id) +bool LLAvatarActions::toggleBlock(const LLUUID& id) { LLAvatarName av_name; LLAvatarNameCache::get(id, &av_name); @@ -1245,10 +1340,12 @@ void LLAvatarActions::toggleBlock(const LLUUID& id) if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName)) { LLMuteList::getInstance()->remove(mute); + return false; } else { LLMuteList::getInstance()->add(mute); + return true; } } diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 32126fcbed..7af72027ce 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -38,6 +38,8 @@ class LLInventoryPanel; class LLFloater; class LLView; +std::string getProfileURL(const std::string& agent_name, bool feed_only = false); + /** * Friend-related actions (add, remove, offer teleport, etc) */ @@ -97,17 +99,20 @@ public: static const LLUUID startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null); // - /** - * Show avatar profile. - */ - static void showProfile(const LLUUID& id); - static void hideProfile(const LLUUID& id); - static bool profileVisible(const LLUUID& id); - static LLFloater* getProfileFloater(const LLUUID& id); -// - static void showProfileWeb(const LLUUID& id); - static void showProfileLegacy(const LLUUID& id); -// + /** + * Show avatar profile. + */ + static void showProfile(const LLUUID& avatar_id); + static void showPicks(const LLUUID& avatar_id); + static void showPick(const LLUUID& avatar_id, const LLUUID& pick_id); + static void createPick(); + static void showClassifieds(const LLUUID& avatar_id); + static void showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit = false); + static void createClassified(); + static void hideProfile(const LLUUID& avatar_id); + static bool profileVisible(const LLUUID& avatar_id); + static bool isPickTabSelected(const LLUUID& avatar_id); + static LLFloater* getProfileFloater(const LLUUID& avatar_id); /** * Show avatar on world map. @@ -136,9 +141,10 @@ public: static void shareWithAvatars(LLView * panel); /** - * Block/unblock the avatar. + * Block/unblock the avatar by id. + * Returns true if blocked, returns false if unblocked */ - static void toggleBlock(const LLUUID& id); + static bool toggleBlock(const LLUUID& id); /** * Mute/unmute avatar. diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 887256c9f6..ea39f73a61 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -36,6 +36,7 @@ #include "llstartup.h" // Linden library includes +#include "llavataractions.h" // for getProfileUrl #include "lldate.h" #include "lltrans.h" #include "llui.h" // LLUI::getLanguage() @@ -94,54 +95,98 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat } } - -void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method) +void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method) { + // this is the startup state when send_complete_agent_movement() message is sent. + // Before this messages won't work so don't bother trying + if (LLStartUp::getStartupState() <= STATE_AGENT_SEND) + { + return; + } + + if (avatar_id.isNull()) + { + return; + } + // Suppress duplicate requests while waiting for a response from the network if (isPendingRequest(avatar_id, type)) { // waiting for a response, don't re-request return; } - // indicate we're going to make a request - addPendingRequest(avatar_id, type); - std::vector strings; - strings.push_back( avatar_id.asString() ); - send_generic_message(method, strings); + std::string cap; + + switch (type) + { + 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()) + { + // indicate we're going to make a request + sendGenericRequest(avatar_id, type, method); + } + else + { + initAgentProfileCapRequest(avatar_id, cap); + } + break; + default: + sendGenericRequest(avatar_id, type, method); + break; + } +} + +void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method) +{ + // indicate we're going to make a request + addPendingRequest(avatar_id, type); + + std::vector strings; + strings.push_back(avatar_id.asString()); + send_generic_message(method, strings); +} + +void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id) +{ + addPendingRequest(avatar_id, APT_PROPERTIES); + + 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_AvatarID, avatar_id); + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url) +{ + addPendingRequest(avatar_id, APT_PROPERTIES); + addPendingRequest(avatar_id, APT_PICKS); + addPendingRequest(avatar_id, APT_GROUPS); + addPendingRequest(avatar_id, APT_NOTES); + LLCoros::instance().launch("requestAgentUserInfoCoro", + boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id)); } void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) { - // this is the startup state when send_complete_agent_movement() message is sent. - // Before this, the AvatarPropertiesRequest message - // won't work so don't bother trying - if (LLStartUp::getStartupState() <= STATE_AGENT_SEND) - { - return; - } - - if (isPendingRequest(avatar_id, APT_PROPERTIES)) - { - // waiting for a response, don't re-request - return; - } - // indicate we're going to make a request - addPendingRequest(avatar_id, APT_PROPERTIES); - - 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_AvatarID, avatar_id); - gAgent.sendReliableMessage(); + sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest"); } void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) { - sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); + sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest"); } void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id) @@ -174,7 +219,7 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* return; } - LL_INFOS() << "Sending avatarinfo update" << LL_ENDL; + 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) @@ -266,6 +311,113 @@ bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avata return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED)); } +// static +void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + std::string finalUrl = cap_url + "/" + agent_id.asString(); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status + || !result.has("id") + || agent_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); + return; + } + + // Avatar Data + + LLAvatarData avatar_data; + std::string birth_date; + + avatar_data.agent_id = agent_id; + avatar_data.avatar_id = agent_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()); + + 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) + { + const LLSD& pick_data = *it; + avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); + } + + // Request processed, no longer pending + self->removePendingRequest(agent_id, APT_PICKS); + self->notifyObservers(agent_id, &avatar_picks, APT_PICKS); + + // 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; + 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); + } + + self->removePendingRequest(agent_id, APT_GROUPS); + self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS); + + // 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); +} + void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) { LLAvatarData avatar_data; @@ -312,8 +464,8 @@ void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* m 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 */ -// - FSInterestsData interests_data; + + LLInterestsData interests_data; msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id ); msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id ); @@ -326,8 +478,7 @@ void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* m 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->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO); } void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**) @@ -405,7 +556,7 @@ void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**) { LLAvatarPicks avatar_picks; - msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.target_id); + 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); @@ -571,6 +722,29 @@ 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; @@ -694,28 +868,3 @@ void LLAvatarPropertiesProcessor::removePendingRequest(const LLUUID& avatar_id, timestamp_map_t::key_type key = std::make_pair(avatar_id, type); mRequestTimestamps.erase(key); } - -// -void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const FSInterestsData* 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(); -} -// diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index 7a96bc896f..f778634d25 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -56,15 +56,12 @@ enum EAvatarProcessorType APT_PICKS, APT_PICK_INFO, APT_TEXTURES, -// APT_INTERESTS_INFO, -// APT_CLASSIFIEDS, APT_CLASSIFIED_INFO }; -// -struct FSInterestsData +struct LLInterestsData { LLUUID agent_id; LLUUID avatar_id; //target id @@ -74,7 +71,6 @@ struct FSInterestsData std::string skills_text; std::string languages_text; }; -// struct LLAvatarData { @@ -239,9 +235,7 @@ public: void sendClassifiedDelete(const LLUUID& classified_id); -// - void sendInterestsInfoUpdate(const FSInterestsData* interests_data); -// + void sendInterestsInfoUpdate(const LLInterestsData* interests_data); // Returns translated, human readable string for account type, such // as "Resident" or "Linden Employee". Used for profiles, inspectors. @@ -254,6 +248,8 @@ public: static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data); + static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id); + static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); static void processAvatarInterestsReply(LLMessageSystem* msg, void**); @@ -272,7 +268,10 @@ public: protected: - void sendGenericRequest(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 notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type); diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index d8eec9b6a5..5f2f26cf8f 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -713,10 +713,6 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) if(mBuddyInfo.find(agent_related) != mBuddyInfo.end()) { (mBuddyInfo[agent_related])->setRightsTo(new_rights); - - // I'm not totally sure why it adds the agents id to the changed list - // nor why it doesn't add the friends's ID. - // Add the friend's id to the changed list for contacts list -KC mChangedBuddyIDs.insert(agent_related); } } diff --git a/indra/newview/llfloaterchatvoicevolume.cpp b/indra/newview/llfloaterchatvoicevolume.cpp index 45aea00a49..67c412dfa6 100644 --- a/indra/newview/llfloaterchatvoicevolume.cpp +++ b/indra/newview/llfloaterchatvoicevolume.cpp @@ -35,7 +35,7 @@ LLFloaterChatVoiceVolume::LLFloaterChatVoiceVolume(const LLSD& key) void LLFloaterChatVoiceVolume::onOpen(const LLSD& key) { LLInspect::onOpen(key); - LLUI::getInstance()->positionViewNearMouse(this); + LLInspect::repositionInspector(key); } LLFloaterChatVoiceVolume::~LLFloaterChatVoiceVolume() diff --git a/indra/newview/llfloaterclassified.cpp b/indra/newview/llfloaterclassified.cpp new file mode 100644 index 0000000000..3520b0f67a --- /dev/null +++ b/indra/newview/llfloaterclassified.cpp @@ -0,0 +1,71 @@ +/** + * @file llfloaterclassified.cpp + * @brief LLFloaterClassified for displaying classifieds. + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterclassified.h" + +LLFloaterClassified::LLFloaterClassified(const LLSD& key) + : LLFloater(key) +{ +} + +LLFloaterClassified::~LLFloaterClassified() +{ +} + +void LLFloaterClassified::onOpen(const LLSD& key) +{ + LLPanel* panel = findChild("main_panel", true); + if (panel) + { + panel->onOpen(key); + } + if (key.has("classified_name")) + { + setTitle(key["classified_name"].asString()); + } + LLFloater::onOpen(key); +} + +BOOL LLFloaterClassified::postBuild() +{ + return TRUE; +} + + +bool LLFloaterClassified::matchesKey(const LLSD& key) +{ + bool is_mkey_valid = mKey.has("classified_id"); + bool is_key_valid = key.has("classified_id"); + if (is_mkey_valid && is_key_valid) + { + return key["classified_id"].asUUID() == mKey["classified_id"].asUUID(); + } + return is_mkey_valid == is_key_valid; +} + +// eof diff --git a/indra/newview/llpanelme.h b/indra/newview/llfloaterclassified.h similarity index 58% rename from indra/newview/llpanelme.h rename to indra/newview/llfloaterclassified.h index 60e9d4317d..2c95d82b2c 100644 --- a/indra/newview/llpanelme.h +++ b/indra/newview/llfloaterclassified.h @@ -1,50 +1,45 @@ -/** - * @file llpanelme.h - * @brief Side tray "Me" (My Profile) panel +/** + * @file llfloaterclassified.h + * @brief LLFloaterClassified for displaying classifieds. * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * + * Copyright (C) 2022, Linden Research, Inc. + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_LLPANELMEPROFILE_H -#define LL_LLPANELMEPROFILE_H +#ifndef LL_LLFLOATERCLASSIFIED_H +#define LL_LLFLOATERCLASSIFIED_H -#include "llpanel.h" -#include "llpanelprofile.h" +#include "llfloater.h" -/** -* Panel for displaying Agent's Picks and Classifieds panel. -* LLPanelMe allows user to edit his picks and classifieds. -*/ -class LLPanelMe : public LLPanelProfile +class LLFloaterClassified : public LLFloater { - LOG_CLASS(LLPanelMe); - + LOG_CLASS(LLFloaterClassified); public: + LLFloaterClassified(const LLSD& key); + virtual ~LLFloaterClassified(); - LLPanelMe(); + void onOpen(const LLSD& key) override; + BOOL postBuild() override; - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); + bool matchesKey(const LLSD& key) override; }; -#endif // LL_LLPANELMEPROFILE_H +#endif // LL_LLFLOATERCLASSIFIED_H diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp index c85130afff..3b0c67415a 100644 --- a/indra/newview/llfloaterdisplayname.cpp +++ b/indra/newview/llfloaterdisplayname.cpp @@ -47,7 +47,6 @@ public: virtual ~LLFloaterDisplayName() { } /*virtual*/ BOOL postBuild(); void onSave(); - void onReset(); void onCancel(); /*virtual*/ void onOpen(const LLSD& key); @@ -102,7 +101,6 @@ void LLFloaterDisplayName::onOpen(const LLSD& key) BOOL LLFloaterDisplayName::postBuild() { - getChild("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this)); getChild("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this)); getChild("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this)); @@ -158,21 +156,6 @@ void LLFloaterDisplayName::onCancel() setVisible(false); } -void LLFloaterDisplayName::onReset() -{ - if (LLAvatarNameCache::getInstance()->hasNameLookupURL()) - { - LLViewerDisplayName::set("",boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); - } - else - { - LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); - } - - setVisible(false); -} - - void LLFloaterDisplayName::onSave() { std::string display_name_utf8 = getChild("display_name_editor")->getValue().asString(); @@ -194,7 +177,7 @@ void LLFloaterDisplayName::onSave() return; } - if (LLAvatarNameCache::getInstance()->hasNameLookupURL()) + if (LLAvatarNameCache::getInstance()->hasNameLookupURL()) { LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); } diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 2f2cc7d1bb..114b937a44 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -122,7 +122,7 @@ LLFloaterGesture::LLFloaterGesture(const LLSD& key) mObserver = new LLFloaterGestureObserver(this); LLGestureMgr::instance().addObserver(mObserver); - mCommitCallbackRegistrar.add("Gesture.Action.ToogleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this)); + mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this)); mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this)); mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2)); mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this)); diff --git a/indra/newview/llfloateroutfitsnapshot.cpp b/indra/newview/llfloateroutfitsnapshot.cpp index 3e465fb83e..7513afed17 100644 --- a/indra/newview/llfloateroutfitsnapshot.cpp +++ b/indra/newview/llfloateroutfitsnapshot.cpp @@ -43,7 +43,6 @@ #include "llviewercontrol.h" #include "lltoolfocus.h" #include "lltoolmgr.h" -#include "llwebprofile.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9b6a202c56..6613ab78db 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -555,60 +555,59 @@ void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType t const LLAvatarData* pAvatarData = static_cast( pData ); if (pAvatarData && (gAgent.getID() == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { - storeAvatarProperties( pAvatarData ); - processProfileProperties( pAvatarData ); + mAllowPublish = (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH); + mAvatarDataInitialized = true; + getChild("online_searchresults")->setValue(mAllowPublish); } } } -void LLFloaterPreference::storeAvatarProperties( const LLAvatarData* pAvatarData ) -{ - if (gAgent.isInitialized() && (gAgent.getID() != LLUUID::null) && (LLStartUp::getStartupState() == STATE_STARTED)) - { - mAvatarProperties.avatar_id = pAvatarData->avatar_id; - mAvatarProperties.image_id = pAvatarData->image_id; - mAvatarProperties.fl_image_id = pAvatarData->fl_image_id; - mAvatarProperties.about_text = pAvatarData->about_text; - mAvatarProperties.fl_about_text = pAvatarData->fl_about_text; - mAvatarProperties.profile_url = pAvatarData->profile_url; - mAvatarProperties.flags = pAvatarData->flags; - mAvatarProperties.allow_publish = pAvatarData->flags & AVATAR_ALLOW_PUBLISH; - - mAvatarDataInitialized = true; - } -} - -void LLFloaterPreference::processProfileProperties(const LLAvatarData* pAvatarData ) -{ - getChild("online_searchresults")->setValue( (bool)(pAvatarData->flags & AVATAR_ALLOW_PUBLISH) ); -} - void LLFloaterPreference::saveAvatarProperties( void ) { - const BOOL allowPublish = getChild("online_searchresults")->getValue(); + const bool allowPublish = getChild("online_searchresults")->getValue(); - if (allowPublish) - { - mAvatarProperties.flags |= AVATAR_ALLOW_PUBLISH; - } + if ((LLStartUp::getStartupState() == STATE_STARTED) + && mAvatarDataInitialized + && (allowPublish != mAllowPublish)) + { + std::string cap_url = gAgent.getRegionCapability("AgentProfile"); + if (!cap_url.empty()) + { + mAllowPublish = allowPublish; - // - // NOTE: We really don't want to send the avatar properties unless we absolutely - // need to so we can avoid the accidental profile reset bug, so, if we're - // logged in, the avatar data has been initialized and we have a state change - // for the "allow publish" flag, then set the flag to its new value and send - // the properties update. - // - // NOTE: The only reason we can not remove this update altogether is because of the - // "allow publish" flag, the last remaining profile setting in the viewer - // that doesn't exist in the web profile. - // - if ((LLStartUp::getStartupState() == STATE_STARTED) && mAvatarDataInitialized && (allowPublish != mAvatarProperties.allow_publish)) - { - mAvatarProperties.allow_publish = allowPublish; + LLCoros::instance().launch("requestAgentUserInfoCoro", + boost::bind(saveAvatarPropertiesCoro, cap_url, allowPublish)); + } + } +} - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate( &mAvatarProperties ); - } +void LLFloaterPreference::saveAvatarPropertiesCoro(const std::string cap_url, bool allow_publish) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + std::string finalUrl = cap_url + "/" + gAgentID.asString(); + LLSD data; + data["allow_publish"] = allow_publish; + + LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("Preferences") << "Failed to put agent information " << data << " for id " << gAgentID << LL_ENDL; + return; + } + + LL_DEBUGS("Preferences") << "Agent id: " << gAgentID << " Data: " << data << " Result: " << httpResults << LL_ENDL; } BOOL LLFloaterPreference::postBuild() @@ -1518,7 +1517,7 @@ void LLFloaterPreference::onBtnOK(const LLSD& userdata) else { // Show beep, pop up dialog, etc. - LL_INFOS() << "Can't close preferences!" << LL_ENDL; + LL_INFOS("Preferences") << "Can't close preferences!" << LL_ENDL; } // [FS Login Panel] @@ -2720,13 +2719,13 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map if (!LLXMLNode::parseFile(filename, root, NULL)) { - LL_WARNS() << "Unable to parse file " << filename << LL_ENDL; + LL_WARNS("Preferences") << "Unable to parse file " << filename << LL_ENDL; return false; } if (!root->hasName("labels")) { - LL_WARNS() << filename << " is not a valid definition file" << LL_ENDL; + LL_WARNS("Preferences") << filename << " is not a valid definition file" << LL_ENDL; return false; } @@ -2746,7 +2745,7 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map } else { - LL_WARNS() << filename << " failed to load" << LL_ENDL; + LL_WARNS("Preferences") << filename << " failed to load" << LL_ENDL; return false; } @@ -4004,7 +4003,7 @@ bool LLPanelPreferenceControls::addControlTableColumns(const std::string &filena LLScrollListCtrl::Contents contents; if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) { - LL_WARNS() << "Failed to load " << filename << LL_ENDL; + LL_WARNS("Preferences") << "Failed to load " << filename << LL_ENDL; return false; } LLXUIParser parser; @@ -4031,7 +4030,7 @@ bool LLPanelPreferenceControls::addControlTableRows(const std::string &filename) LLScrollListCtrl::Contents contents; if (!LLUICtrlFactory::getLayeredXMLNode(filename, xmlNode)) { - LL_WARNS() << "Failed to load " << filename << LL_ENDL; + LL_WARNS("Preferences") << "Failed to load " << filename << LL_ENDL; return false; } LLXUIParser parser; @@ -4137,7 +4136,7 @@ void LLPanelPreferenceControls::populateControlTable() { // Either unknown mode or MODE_SAVED_SETTINGS // It doesn't have UI or actual settings yet - LL_WARNS() << "Unimplemented mode" << LL_ENDL; + LL_WARNS("Preferences") << "Unimplemented mode" << LL_ENDL; // Searchable columns were removed, mark searchables for an update LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); @@ -4177,7 +4176,7 @@ void LLPanelPreferenceControls::populateControlTable() } else { - LL_WARNS() << "Unimplemented mode" << LL_ENDL; + LL_WARNS("Preferences") << "Unimplemented mode" << LL_ENDL; } // explicit update to make sure table is ready for llsearchableui diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index b3a543ef13..27b10135b0 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -111,9 +111,8 @@ public: static void updateShowFavoritesCheckbox(bool val); void processProperties( void* pData, EAvatarProcessorType type ); - void processProfileProperties(const LLAvatarData* pAvatarData ); - void storeAvatarProperties( const LLAvatarData* pAvatarData ); void saveAvatarProperties( void ); + static void saveAvatarPropertiesCoro(const std::string url, bool allow_publish); void selectPrivacyPanel(); void selectChatPanel(); void getControlNames(std::vector& names); @@ -313,7 +312,7 @@ private: bool mOriginalHideOnlineStatus; std::string mDirectoryVisibility; - LLAvatarData mAvatarProperties; + bool mAllowPublish; // Allow showing agent in search std::string mSavedGraphicsPreset; LOG_CLASS(LLFloaterPreference); diff --git a/indra/newview/llfloaterprofile.cpp b/indra/newview/llfloaterprofile.cpp new file mode 100644 index 0000000000..6ccdace6c5 --- /dev/null +++ b/indra/newview/llfloaterprofile.cpp @@ -0,0 +1,170 @@ +/** + * @file llfloaterprofile.cpp + * @brief Avatar profile floater. + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterprofile.h" + +#include "llagent.h" //gAgent +#include "llnotificationsutil.h" +#include "llpanelavatar.h" +#include "llpanelprofile.h" + +static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; + +LLFloaterProfile::LLFloaterProfile(const LLSD& key) + : LLFloater(key), + mAvatarId(key["id"].asUUID()), + mNameCallbackConnection() +{ + mDefaultRectForGroup = false; +} + +LLFloaterProfile::~LLFloaterProfile() +{ + if (mNameCallbackConnection.connected()) + { + mNameCallbackConnection.disconnect(); + } +} + +void LLFloaterProfile::onOpen(const LLSD& key) +{ + mPanelProfile->onOpen(key); + + // Update the avatar name. + mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2)); +} + +BOOL LLFloaterProfile::postBuild() +{ + mPanelProfile = findChild(PANEL_PROFILE_VIEW); + + return TRUE; +} + +void LLFloaterProfile::onClickCloseBtn(bool app_quitting) +{ + if (!app_quitting) + { + if (mPanelProfile->hasUnpublishedClassifieds()) + { + LLNotificationsUtil::add("ProfileUnpublishedClassified", LLSD(), LLSD(), + boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, false)); + } + else if (mPanelProfile->hasUnsavedChanges()) + { + LLNotificationsUtil::add("ProfileUnsavedChanges", LLSD(), LLSD(), + boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, true)); + } + else + { + closeFloater(); + } + } + else + { + closeFloater(); + } +} + +void LLFloaterProfile::onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (can_save) + { + // savable content + + if (option == 0) // Save + { + mPanelProfile->commitUnsavedChanges(); + closeFloater(); + } + if (option == 1) // Discard + { + closeFloater(); + } + // else cancel + } + else + { + // classifieds + + if (option == 0) // Ok + { + closeFloater(); + } + // else cancel + } + +} + +void LLFloaterProfile::createPick(const LLPickData &data) +{ + mPanelProfile->createPick(data); +} + +void LLFloaterProfile::showPick(const LLUUID& pick_id) +{ + mPanelProfile->showPick(pick_id); +} + +bool LLFloaterProfile::isPickTabSelected() +{ + return mPanelProfile->isPickTabSelected(); +} + +void LLFloaterProfile::refreshName() +{ + if (!mNameCallbackConnection.connected()) + { + mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2)); + } + + LLPanelProfileSecondLife *panel = findChild("panel_profile_secondlife"); + if (panel) + { + panel->refreshName(); + } +} + +void LLFloaterProfile::showClassified(const LLUUID& classified_id, bool edit) +{ + mPanelProfile->showClassified(classified_id, edit); +} + +void LLFloaterProfile::createClassified() +{ + mPanelProfile->createClassified(); +} + +void LLFloaterProfile::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mNameCallbackConnection.disconnect(); + setTitle(av_name.getCompleteName()); +} + +// eof diff --git a/indra/newview/llfloaterprofile.h b/indra/newview/llfloaterprofile.h new file mode 100644 index 0000000000..b3ed02fc2c --- /dev/null +++ b/indra/newview/llfloaterprofile.h @@ -0,0 +1,66 @@ +/** + * @file llfloaterprofile.h + * @brief Avatar profile floater. + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERPROFILE_H +#define LL_LLFLOATERPROFILE_H + +#include "llavatarnamecache.h" +#include "llavatarpropertiesprocessor.h" +#include "llfloater.h" + +class LLPanelProfile; + +class LLFloaterProfile : public LLFloater +{ + LOG_CLASS(LLFloaterProfile); +public: + LLFloaterProfile(const LLSD& key); + virtual ~LLFloaterProfile(); + + BOOL postBuild() override; + + void onOpen(const LLSD& key) override; + void onClickCloseBtn(bool app_quitting = false) override; + void onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save); + + void createPick(const LLPickData &data); + void showPick(const LLUUID& pick_id = LLUUID::null); + bool isPickTabSelected(); + void refreshName(); + + void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); + void createClassified(); + +private: + LLAvatarNameCache::callback_connection_t mNameCallbackConnection; + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + LLPanelProfile* mPanelProfile; + + LLUUID mAvatarId; +}; + +#endif // LL_LLFLOATERPROFILE_H diff --git a/indra/newview/llfloaterprofiletexture.cpp b/indra/newview/llfloaterprofiletexture.cpp new file mode 100644 index 0000000000..2ebbbdf08b --- /dev/null +++ b/indra/newview/llfloaterprofiletexture.cpp @@ -0,0 +1,241 @@ +/** + * @file llfloaterprofiletexture.cpp + * @brief LLFloaterProfileTexture class implementation + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterprofiletexture.h" + +#include "llbutton.h" +#include "llfloaterreg.h" +#include "llpreview.h" // fors constants +#include "lltrans.h" +#include "llviewercontrol.h" +#include "lltextureview.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" +#include "llviewermenu.h" + + + +LLFloaterProfileTexture::LLFloaterProfileTexture(LLView* owner) + : LLFloater(LLSD()) + , mUpdateDimensions(TRUE) + , mLastHeight(0) + , mLastWidth(0) + , mImage(NULL) + , mImageOldBoostLevel(LLGLTexture::BOOST_NONE) + , mOwnerHandle(owner->getHandle()) +{ + buildFromFile("floater_profile_texture.xml"); +} + +LLFloaterProfileTexture::~LLFloaterProfileTexture() +{ + if (mImage.notNull()) + { + mImage->setBoostLevel(mImageOldBoostLevel); + mImage->forceActive(); // Make sure it can get discarded + mImage = NULL; + } +} + +// virtual +BOOL LLFloaterProfileTexture::postBuild() +{ + mProfileIcon = getChild("profile_pic"); + + mCloseButton = getChild("close_btn"); + mCloseButton->setCommitCallback([this](LLUICtrl*, void*) { closeFloater(); }, nullptr); + + // Add refresh function + getChild("btn_refresh")->setCommitCallback([this](LLUICtrl*, void*) { refresh(); }, nullptr); + + return TRUE; +} + +// virtual +void LLFloaterProfileTexture::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLFloater::reshape(width, height, called_from_parent); +} + +// It takes a while until we get height and width information. +// When we receive it, reshape the window accordingly. +void LLFloaterProfileTexture::updateDimensions() +{ + if (mImage.isNull()) + { + return; + } + if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0) + { + return; + } + + S32 img_width = mImage->getFullWidth(); + S32 img_height = mImage->getFullHeight(); + + if (mAssetStatus != LLPreview::PREVIEW_ASSET_LOADED + || mLastWidth != img_width + || mLastHeight != img_height) + { + mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED; + // Asset has been fully loaded + mUpdateDimensions = TRUE; + } + + mLastHeight = img_height; + mLastWidth = img_width; + + // Reshape the floater only when required + if (mUpdateDimensions) + { + mUpdateDimensions = FALSE; + + LLRect old_floater_rect = getRect(); + LLRect old_image_rect = mProfileIcon->getRect(); + S32 width = old_floater_rect.getWidth() - old_image_rect.getWidth() + mLastWidth; + S32 height = old_floater_rect.getHeight() - old_image_rect.getHeight() + mLastHeight; + + const F32 MAX_DIMENTIONS = 512; // most profiles are supposed to be 256x256 + + S32 biggest_dim = llmax(width, height); + if (biggest_dim > MAX_DIMENTIONS) + { + F32 scale_down = MAX_DIMENTIONS / (F32)biggest_dim; + width *= scale_down; + height *= scale_down; + } + + //reshape floater + reshape(width, height); + + gFloaterView->adjustToFitScreen(this, FALSE); + } +} + +void LLFloaterProfileTexture::draw() +{ + // drawFrustum + LLView *owner = mOwnerHandle.get(); + static LLCachedControl max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, owner); + + LLFloater::draw(); +} + +void LLFloaterProfileTexture::onOpen(const LLSD& key) +{ + mCloseButton->setFocus(true); +} + +void LLFloaterProfileTexture::resetAsset() +{ + mProfileIcon->setValue("Generic_Person_Large"); + mImageID = LLUUID::null; + if (mImage.notNull()) + { + mImage->setBoostLevel(mImageOldBoostLevel); + mImage->forceActive(); // Make sure it can get discarded + mImage = NULL; + } +} +void LLFloaterProfileTexture::loadAsset(const LLUUID &image_id) +{ + if (mImageID != image_id) + { + if (mImage.notNull()) + { + mImage->setBoostLevel(mImageOldBoostLevel); + mImage->forceActive(); // Make sure it can get discarded + mImage = NULL; + } + } + else + { + return; + } + + mProfileIcon->setValue(image_id); + mImageID = image_id; + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mImageOldBoostLevel = mImage->getBoostLevel(); + + if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0) + { + mImage->setLoadedCallback(LLFloaterProfileTexture::onTextureLoaded, + 0, TRUE, FALSE, new LLHandle(getHandle()), &mCallbackTextureList); + + mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + mAssetStatus = LLPreview::PREVIEW_ASSET_LOADING; + } + else + { + mAssetStatus = LLPreview::PREVIEW_ASSET_LOADED; + } + + mUpdateDimensions = TRUE; + updateDimensions(); +} + +// static +void LLFloaterProfileTexture::onTextureLoaded( + BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + LLHandle* handle = (LLHandle*)userdata; + + if (!handle->isDead()) + { + LLFloaterProfileTexture* floater = static_cast(handle->get()); + if (floater && success) + { + floater->mUpdateDimensions = TRUE; + floater->updateDimensions(); + } + } + + if (final || !success) + { + delete handle; + } +} + +// Add refresh function +void LLFloaterProfileTexture::refresh() +{ + if (mImageID.notNull() && mImage.notNull()) + { + destroy_texture(mImageID); + mImage->forceToRefetchTexture(); + } +} +// diff --git a/indra/newview/llfloaterprofiletexture.h b/indra/newview/llfloaterprofiletexture.h new file mode 100644 index 0000000000..0faa22c99e --- /dev/null +++ b/indra/newview/llfloaterprofiletexture.h @@ -0,0 +1,84 @@ +/** + * @file llfloaterprofiletexture.h + * @brief LLFloaterProfileTexture class definition + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERPROFILETEXTURE_H +#define LL_LLFLOATERPROFILETEXTURE_H + +#include "llfloater.h" +#include "llviewertexture.h" + +class LLButton; +class LLImageRaw; +class LLIconCtrl; + +class LLFloaterProfileTexture : public LLFloater +{ +public: + LLFloaterProfileTexture(LLView* owner); + ~LLFloaterProfileTexture(); + + void draw() override; + void onOpen(const LLSD& key) override; + + void resetAsset(); + void loadAsset(const LLUUID &image_id); + + // Add refresh function + void refresh(); + + + static void onTextureLoaded( + BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; +protected: + BOOL postBuild() override; + +private: + void updateDimensions(); + + LLUUID mImageID; + LLPointer mImage; + S32 mImageOldBoostLevel; + S32 mAssetStatus; + F32 mContextConeOpacity; + S32 mLastHeight; + S32 mLastWidth; + BOOL mUpdateDimensions; + + LLHandle mOwnerHandle; + LLIconCtrl* mProfileIcon; + LLButton* mCloseButton; + + LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList; +}; +#endif // LL_LLFLOATERPROFILETEXTURE_H diff --git a/indra/newview/llfloatervoicevolume.cpp b/indra/newview/llfloatervoicevolume.cpp index 59e1f49f81..23f19dd5aa 100644 --- a/indra/newview/llfloatervoicevolume.cpp +++ b/indra/newview/llfloatervoicevolume.cpp @@ -127,7 +127,7 @@ void LLFloaterVoiceVolume::onOpen(const LLSD& data) // Extract appropriate avatar id mAvatarID = data["avatar_id"]; - LLUI::getInstance()->positionViewNearMouse(this); + LLInspect::repositionInspector(data); getChild("avatar_name")->setValue(""); updateVolumeControls(); diff --git a/indra/newview/llfloaterwebprofile.cpp b/indra/newview/llfloaterwebprofile.cpp deleted file mode 100644 index 891bb90c0e..0000000000 --- a/indra/newview/llfloaterwebprofile.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file llfloaterwebprofile.cpp - * @brief Avatar profile floater. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterwebprofile.h" - -#include "llviewercontrol.h" - -LLFloaterWebProfile::LLFloaterWebProfile(const Params& key) : - LLFloaterWebContent(key) -{ -} - -void LLFloaterWebProfile::onOpen(const LLSD& key) -{ - Params p(key); - p.show_chrome(true); - p.window_class("profile"); - p.allow_address_entry(false); - p.trusted_content(true); - LLFloaterWebContent::onOpen(p); - applyPreferredRect(); -} - -// virtual -void LLFloaterWebProfile::handleReshape(const LLRect& new_rect, bool by_user) -{ - LL_DEBUGS() << "handleReshape: " << new_rect << LL_ENDL; - - if (by_user && !isMinimized()) - { - LL_DEBUGS() << "Storing new rect" << LL_ENDL; - gSavedSettings.setRect("WebProfileFloaterRect", new_rect); - } - - LLFloaterWebContent::handleReshape(new_rect, by_user); -} - -LLFloater* LLFloaterWebProfile::create(const LLSD& key) -{ - LLFloaterWebContent::Params p(key); - preCreate(p); - return new LLFloaterWebProfile(p); -} - -void LLFloaterWebProfile::applyPreferredRect() -{ - const LLRect preferred_rect = gSavedSettings.getRect("WebProfileFloaterRect"); - LL_DEBUGS() << "Applying preferred rect: " << preferred_rect << LL_ENDL; - - // Don't override position that may have been set by floater stacking code. - LLRect new_rect = getRect(); - new_rect.setLeftTopAndSize( - new_rect.mLeft, new_rect.mTop, - preferred_rect.getWidth(), preferred_rect.getHeight()); - setShape(new_rect); -} diff --git a/indra/newview/llfloaterwebprofile.h b/indra/newview/llfloaterwebprofile.h deleted file mode 100644 index 4c355e401b..0000000000 --- a/indra/newview/llfloaterwebprofile.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * @file llfloaterwebprofile.h - * @brief Avatar profile floater. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATERWEBPROFILE_H -#define LL_LLFLOATERWEBPROFILE_H - -#include "llfloaterwebcontent.h" -#include "llviewermediaobserver.h" - -#include - -class LLMediaCtrl; - -/** - * Displays avatar profile web page. - */ -class LLFloaterWebProfile -: public LLFloaterWebContent -{ - LOG_CLASS(LLFloaterWebProfile); -public: - typedef LLFloaterWebContent::Params Params; - - LLFloaterWebProfile(const Params& key); - - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); - - static LLFloater* create(const LLSD& key); - -private: - void applyPreferredRect(); -}; - -#endif // LL_LLFLOATERWEBPROFILE_H - diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index f2da4cdce2..c353a9efe0 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -50,7 +50,6 @@ #include "llurlaction.h" static LLDefaultChildRegistry::Register r("group_list"); -S32 LLGroupListItem::sIconWidth = 0; class LLGroupComparator : public LLFlatListView::ItemComparator { @@ -70,8 +69,35 @@ public: } }; -//static const LLGroupComparator GROUP_COMPARATOR; -static LLGroupComparator GROUP_COMPARATOR; // const makes GCC >= 4.6 very angry about not user defined default ctor. +class LLSharedGroupComparator : public LLFlatListView::ItemComparator +{ +public: + LLSharedGroupComparator() {}; + + /*virtual*/ bool compare(const LLPanel* item1, const LLPanel* item2) const + { + const LLGroupListItem* group_item1 = static_cast(item1); + std::string name1 = group_item1->getGroupName(); + bool item1_shared = gAgent.isInGroup(group_item1->getGroupID(), true); + + const LLGroupListItem* group_item2 = static_cast(item2); + std::string name2 = group_item2->getGroupName(); + bool item2_shared = gAgent.isInGroup(group_item2->getGroupID(), true); + + if (item2_shared != item1_shared) + { + return item1_shared; + } + + LLStringUtil::toUpper(name1); + LLStringUtil::toUpper(name2); + + return name1 < name2; + } +}; + +static LLGroupComparator GROUP_COMPARATOR; +static LLSharedGroupComparator SHARED_GROUP_COMPARATOR; LLGroupList::Params::Params() : for_agent("for_agent", true) @@ -80,7 +106,7 @@ LLGroupList::Params::Params() LLGroupList::LLGroupList(const Params& p) : LLFlatListViewEx(p) - , mForAgent(p.for_agent) + , mForAgent(p.for_agent) , mDirty(true) // to force initial update , mShowIcons(false) , mShowNone(true) @@ -88,7 +114,15 @@ LLGroupList::LLGroupList(const Params& p) setCommitOnSelectionChange(true); // Set default sort order. - setComparator(&GROUP_COMPARATOR); + if (mForAgent) + { + setComparator(&GROUP_COMPARATOR); + } + else + { + // shared groups first + setComparator(&SHARED_GROUP_COMPARATOR); + } if (mForAgent) { @@ -98,18 +132,18 @@ LLGroupList::LLGroupList(const Params& p) LLGroupList::~LLGroupList() { - if (mForAgent) gAgent.removeListener(this); - if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); + if (mForAgent) gAgent.removeListener(this); + if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); } void LLGroupList::enableForAgent(bool show_icons) { mForAgent = true; - mShowIcons = mForAgent && gSavedSettings.getBOOL("GroupListShowIcons") && show_icons; + mShowIcons = mForAgent && gSavedSettings.getBOOL("GroupListShowIcons") && show_icons; - // Listen for agent group changes. - gAgent.addListener(this, "new group"); + // Listen for agent group changes. + gAgent.addListener(this, "new group"); // Set up context menu. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -138,15 +172,15 @@ BOOL LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask); - if (mForAgent) - { - LLToggleableMenu* context_menu = mContextMenuHandle.get(); - if (context_menu && size() > 0) - { - context_menu->buildDrawLabels(); - context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, context_menu, x, y); - } + if (mForAgent) + { + LLToggleableMenu* context_menu = mContextMenuHandle.get(); + if (context_menu && size() > 0) + { + context_menu->buildDrawLabels(); + context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, context_menu, x, y); + } } return handled; @@ -159,7 +193,7 @@ BOOL LLGroupList::handleDoubleClick(S32 x, S32 y, MASK mask) // Handle double click only for the selected item in the list, skip clicks on empty space. if (handled) { - if (mDoubleClickSignal) + if (mDoubleClickSignal && getItemsRect().pointInRect(x, y)) { (*mDoubleClickSignal)(this, x, y, mask); } @@ -191,51 +225,49 @@ static bool findInsensitive(std::string haystack, const std::string& needle_uppe void LLGroupList::refresh() { - if (mForAgent) - { - const LLUUID& highlight_id = gAgent.getGroupID(); - S32 count = gAgent.mGroups.size(); - LLUUID id; - bool have_filter = !mNameFilter.empty(); + if (mForAgent) + { + const LLUUID& highlight_id = gAgent.getGroupID(); + S32 count = gAgent.mGroups.size(); + LLUUID id; + bool have_filter = !mNameFilter.empty(); - clear(); + clear(); - for(S32 i = 0; i < count; ++i) - { - id = gAgent.mGroups.at(i).mID; - const LLGroupData& group_data = gAgent.mGroups.at(i); - if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) - continue; - // Mark groups hidden in profile - //addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM); - addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile); - } + for(S32 i = 0; i < count; ++i) + { + id = gAgent.mGroups.at(i).mID; + const LLGroupData& group_data = gAgent.mGroups.at(i); + if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) + continue; + addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile); + } - // Sort the list. - sort(); + // Sort the list. + sort(); - // Add "none" to list at top if filter not set (what's the point of filtering "none"?). - // but only if some real groups exists. EXT-4838 - if (!have_filter && count > 0 && mShowNone) - { - std::string loc_none = LLTrans::getString("GroupsNone"); - addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); - } + // Add "none" to list at top if filter not set (what's the point of filtering "none"?). + // but only if some real groups exists. EXT-4838 + if (!have_filter && count > 0 && mShowNone) + { + std::string loc_none = LLTrans::getString("GroupsNone"); + addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); + } - selectItemByUUID(highlight_id); - } - else - { - clear(); + selectItemByUUID(highlight_id); + } + else + { + clear(); - for (group_map_t::iterator it = mGroups.begin(); it != mGroups.end(); ++it) - { - addNewItem(it->second, it->first, LLUUID::null, ADD_BOTTOM); - } + for (group_map_t::iterator it = mGroups.begin(); it != mGroups.end(); ++it) + { + addNewItem(it->second, it->first, LLUUID::null, ADD_BOTTOM); + } - // Sort the list. - sort(); - } + // Sort the list. + sort(); + } setDirty(false); onCommit(); @@ -258,19 +290,17 @@ void LLGroupList::toggleIcons() void LLGroupList::setGroups(const std::map< std::string,LLUUID> group_list) { - mGroups = group_list; - setDirty(true); + mGroups = group_list; + setDirty(true); } ////////////////////////////////////////////////////////////////////////// // PRIVATE Section ////////////////////////////////////////////////////////////////////////// -// Mark groups hidden in profile -//void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos) void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile) { - LLGroupListItem* item = new LLGroupListItem(mForAgent && mShowIcons); + LLGroupListItem* item = new LLGroupListItem(mForAgent, mShowIcons); item->setGroupID(id); item->setName(name, mNameFilter); @@ -279,7 +309,10 @@ 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->setGroupIconVisible(mShowIcons); - + if (!mShowIcons) + { + item->setVisibleInProfile(visible_in_profile); + } // Mark groups hidden in profile item->setVisibleInProfile(visible_in_profile); // Mark groups hidden in profile @@ -299,30 +332,28 @@ bool LLGroupList::handleEvent(LLPointer event, const LLSD& return true; } - // Mark groups hidden in profile - if (event->desc() == "value_changed") - { - LLSD data = event->getValue(); - if (data.has("group_id") && data.has("visible")) - { - LLUUID group_id = data["group_id"].asUUID(); - bool visible = data["visible"].asBoolean(); + if (event->desc() == "value_changed") + { + LLSD data = event->getValue(); + if (data.has("group_id") && data.has("visible")) + { + LLUUID group_id = data["group_id"].asUUID(); + bool visible = data["visible"].asBoolean(); - std::vector items; - getItems(items); - for (std::vector::iterator it = items.begin(); it != items.end(); ++it) - { - LLGroupListItem* item = dynamic_cast(*it); - if (item && item->getGroupID() == group_id) - { - item->setVisibleInProfile(visible); - break; - } - } - } - return true; - } - // + std::vector items; + getItems(items); + for (std::vector::iterator it = items.begin(); it != items.end(); ++it) + { + LLGroupListItem* item = dynamic_cast(*it); + if (item && item->getGroupID() == group_id) + { + item->setVisibleInProfile(visible); + break; + } + } + } + return true; + } return false; } @@ -387,24 +418,25 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) /* LLGroupListItem implementation */ /************************************************************************/ -LLGroupListItem::LLGroupListItem(bool for_agent) +LLGroupListItem::LLGroupListItem(bool for_agent, bool show_icons) : LLPanel(), mGroupIcon(NULL), mGroupNameBox(NULL), mInfoBtn(NULL), -mGroupID(LLUUID::null) +mProfileBtn(NULL), +mVisibilityHideBtn(NULL), +mVisibilityShowBtn(NULL), +mGroupID(LLUUID::null), +mForAgent(for_agent) { - if (for_agent) - buildFromFile( "panel_group_list_item.xml"); - else - buildFromFile( "panel_group_list_item_short.xml"); - - // Remember group icon width including its padding from the name text box, - // so that we can hide and show the icon again later. - if (!sIconWidth) - { - sIconWidth = mGroupNameBox->getRect().mLeft - mGroupIcon->getRect().mLeft; - } + if (show_icons) + { + buildFromFile( "panel_group_list_item.xml"); + } + else + { + buildFromFile( "panel_group_list_item_short.xml"); + } } LLGroupListItem::~LLGroupListItem() @@ -421,7 +453,25 @@ BOOL LLGroupListItem::postBuild() mInfoBtn = getChild("info_btn"); mInfoBtn->setClickedCallback(boost::bind(&LLGroupListItem::onInfoBtnClick, this)); - childSetAction("profile_btn", boost::bind(&LLGroupListItem::onProfileBtnClick, this)); + mProfileBtn = getChild("profile_btn"); + mProfileBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onProfileBtnClick(); }); + + mVisibilityHideBtn = findChild("visibility_hide_btn"); + if (mVisibilityHideBtn) + { + mVisibilityHideBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onVisibilityBtnClick(false); }); + } + mVisibilityShowBtn = findChild("visibility_show_btn"); + if (mVisibilityShowBtn) + { + mVisibilityShowBtn->setClickedCallback([this](LLUICtrl *, const LLSD &) { onVisibilityBtnClick(true); }); + } + + // Remember group icon width including its padding from the name text box, + // so that we can hide and show the icon again later. + // Also note that panel_group_list_item and panel_group_list_item_short + // have icons of different sizes so we need to figure it per file. + mIconWidth = mGroupNameBox->getRect().mLeft - mGroupIcon->getRect().mLeft; return TRUE; } @@ -440,7 +490,16 @@ void LLGroupListItem::onMouseEnter(S32 x, S32 y, MASK mask) if (mGroupID.notNull()) // don't show the info button for the "none" group { mInfoBtn->setVisible(true); - getChildView("profile_btn")->setVisible( true); + mProfileBtn->setVisible(true); + if (mForAgent && mVisibilityHideBtn) + { + LLGroupData agent_gdatap; + if (gAgent.getGroupData(mGroupID, agent_gdatap)) + { + mVisibilityHideBtn->setVisible(agent_gdatap.mListInProfile); + mVisibilityShowBtn->setVisible(!agent_gdatap.mListInProfile); + } + } } LLPanel::onMouseEnter(x, y, mask); @@ -450,7 +509,12 @@ void LLGroupListItem::onMouseLeave(S32 x, S32 y, MASK mask) { getChildView("hovered_icon")->setVisible( false); mInfoBtn->setVisible(false); - getChildView("profile_btn")->setVisible( false); + mProfileBtn->setVisible(false); + if (mVisibilityHideBtn) + { + mVisibilityHideBtn->setVisible(false); + mVisibilityShowBtn->setVisible(false); + } LLPanel::onMouseLeave(x, y, mask); } @@ -468,7 +532,17 @@ void LLGroupListItem::setGroupID(const LLUUID& group_id) mID = group_id; mGroupID = group_id; - setActive(group_id == gAgent.getGroupID()); + + if (mForAgent) + { + // Active group should be bold. + setBold(group_id == gAgent.getGroupID()); + } + else + { + // Groups shared with the agent should be bold + setBold(gAgent.isInGroup(group_id, true)); + } LLGroupMgr::getInstance()->addObserver(this); } @@ -489,31 +563,28 @@ void LLGroupListItem::setGroupIconVisible(bool visible) // Move the group name horizontally by icon size + its distance from the group name. LLRect name_rect = mGroupNameBox->getRect(); - name_rect.mLeft += visible ? sIconWidth : -sIconWidth; + name_rect.mLeft += visible ? mIconWidth : -mIconWidth; mGroupNameBox->setRect(name_rect); } -// Mark groups hidden in profile void LLGroupListItem::setVisibleInProfile(bool visible) { - mGroupNameBox->setColor(LLUIColorTable::instance().getColor((visible ? "GroupVisibleInProfile" : "GroupHiddenInProfile"), LLColor4::red).get()); + mGroupNameBox->setColor(LLUIColorTable::instance().getColor((visible ? "GroupVisibleInProfile" : "GroupHiddenInProfile"), LLColor4::red).get()); } -// Mark groups hidden in profile ////////////////////////////////////////////////////////////////////////// // Private Section ////////////////////////////////////////////////////////////////////////// -void LLGroupListItem::setActive(bool active) +void LLGroupListItem::setBold(bool bold) { // *BUG: setName() overrides the style params. - // Active group should be bold. LLFontDescriptor new_desc(mGroupNameBox->getFont()->getFontDesc()); // *NOTE dzaporozhan // On Windows LLFontGL::NORMAL will not remove LLFontGL::BOLD if font // is predefined as bold (SansSerifSmallBold, for example) - new_desc.setStyle(active ? LLFontGL::BOLD : LLFontGL::NORMAL); + new_desc.setStyle(bold ? LLFontGL::BOLD : LLFontGL::NORMAL); LLFontGL* new_font = LLFontGL::getFont(new_desc); mGroupNameStyle.font = new_font; @@ -533,14 +604,25 @@ void LLGroupListItem::onProfileBtnClick() LLGroupActions::show(mGroupID); } +void LLGroupListItem::onVisibilityBtnClick(bool new_visibility) +{ + LLGroupData agent_gdatap; + if (gAgent.getGroupData(mGroupID, agent_gdatap)) + { + gAgent.setUserGroupFlags(mGroupID, agent_gdatap.mAcceptNotices, new_visibility); + setVisibleInProfile(new_visibility); + mVisibilityHideBtn->setVisible(new_visibility); + mVisibilityShowBtn->setVisible(!new_visibility); + } +} + void LLGroupListItem::changed(LLGroupChange gc) { LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mID); - // FIRE-22148: Only update group icon if the received group data actually contains group icon info - //if (group_data) if ((gc == GC_ALL || gc == GC_PROPERTIES) && group_data) - // - setGroupIconID(group_data->mInsigniaID); + { + setGroupIconID(group_data->mInsigniaID); + } } //EOF diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 5ab3970044..5cbabb712f 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -50,8 +50,8 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener public: struct Params : public LLInitParam::Block { - Optional for_agent; - Params(); + Optional for_agent; + Params(); }; LLGroupList(const Params& p); @@ -66,17 +66,15 @@ public: void setNameFilter(const std::string& filter); void toggleIcons(); bool getIconsVisible() const { return mShowIcons; } - void setIconsVisible(bool show_icons) { mShowIcons = show_icons; } - void setShowNone(bool show_none) { mShowNone = show_none; } - void setGroups(const std::map< std::string,LLUUID> group_list); + void setIconsVisible(bool show_icons) { mShowIcons = show_icons; } + void setShowNone(bool show_none) { mShowNone = show_none; } + void setGroups(const std::map< std::string,LLUUID> group_list); LLToggleableMenu* getContextMenu() const { return mContextMenuHandle.get(); } private: void setDirty(bool val = true) { mDirty = val; } void refresh(); - // Mark groups hidden in profile - //void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM); void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true); bool handleEvent(LLPointer event, const LLSD& userdata); // called on agent group list changes @@ -89,10 +87,10 @@ private: bool mDirty; std::string mNameFilter; - bool mForAgent; + bool mForAgent; bool mShowNone; - typedef std::map< std::string,LLUUID> group_map_t; - group_map_t mGroups; + typedef std::map< std::string,LLUUID> group_map_t; + group_map_t mGroups; }; class LLButton; @@ -103,7 +101,7 @@ class LLGroupListItem : public LLPanel , public LLGroupMgrObserver { public: - LLGroupListItem(bool for_agent); + LLGroupListItem(bool for_agent, bool show_icons); ~LLGroupListItem(); /*virtual*/ BOOL postBuild(); /*virtual*/ void setValue(const LLSD& value); @@ -120,22 +118,25 @@ public: virtual void changed(LLGroupChange gc); - // Mark groups hidden in profile - void setVisibleInProfile(bool visible); - + void setVisibleInProfile(bool visible); private: - void setActive(bool active); + void setBold(bool bold); void onInfoBtnClick(); void onProfileBtnClick(); + void onVisibilityBtnClick(bool new_visibility); LLTextBox* mGroupNameBox; LLUUID mGroupID; LLGroupIconCtrl* mGroupIcon; - LLButton* mInfoBtn; + LLButton* mInfoBtn; + LLButton* mProfileBtn; + LLButton* mVisibilityHideBtn; + LLButton* mVisibilityShowBtn; std::string mGroupName; + bool mForAgent; LLStyle::Params mGroupNameStyle; - static S32 sIconWidth; // icon width + padding + S32 mIconWidth; }; #endif // LL_LLGROUPLIST_H diff --git a/indra/newview/llinspect.cpp b/indra/newview/llinspect.cpp index 479e8f9abf..f382b5985f 100644 --- a/indra/newview/llinspect.cpp +++ b/indra/newview/llinspect.cpp @@ -147,3 +147,19 @@ bool LLInspect::childHasVisiblePopupMenu() } return false; } + +void LLInspect::repositionInspector(const LLSD& data) +{ + // Position the inspector relative to the mouse cursor + // Similar to how tooltips are positioned + // See LLToolTipMgr::createToolTip + if (data.has("pos")) + { + LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); + } + else + { + LLUI::getInstance()->positionViewNearMouse(this); + } + applyRectControl(); +} diff --git a/indra/newview/llinspect.h b/indra/newview/llinspect.h index 1f6aafc7bd..6909aa3f16 100644 --- a/indra/newview/llinspect.h +++ b/indra/newview/llinspect.h @@ -49,6 +49,8 @@ public: /// Inspectors close themselves when they lose focus /*virtual*/ void onFocusLost(); + + void repositionInspector(const LLSD& data); protected: diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp index 6e14862044..8923879433 100644 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -45,7 +45,6 @@ #include "llfloater.h" #include "llfloaterreg.h" #include "lltextbox.h" -#include "lltooltip.h" // positionViewNearMouse() #include "lltrans.h" // Undo CHUI-90 and make avatar inspector useful again @@ -329,17 +328,7 @@ void LLInspectAvatar::onOpen(const LLSD& data) } // - // Position the inspector relative to the mouse cursor - // Similar to how tooltips are positioned - // See LLToolTipMgr::createToolTip - if (data.has("pos")) - { - LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); - } - else - { - LLUI::getInstance()->positionViewNearMouse(this); - } + LLInspect::repositionInspector(data); // Generate link to avatar profile. // Undo CHUI-90 and make avatar inspector useful again diff --git a/indra/newview/llinspectgroup.cpp b/indra/newview/llinspectgroup.cpp index fa8a53c546..0a30ab9217 100644 --- a/indra/newview/llinspectgroup.cpp +++ b/indra/newview/llinspectgroup.cpp @@ -38,7 +38,6 @@ #include "llfloater.h" #include "llfloaterreg.h" #include "llresmgr.h" // getMonetaryString() -#include "lltooltip.h" // positionViewNearMouse() #include "lltrans.h" #include "lluictrl.h" #include "llgroupiconctrl.h" @@ -124,17 +123,7 @@ void LLInspectGroup::onOpen(const LLSD& data) setGroupID(data["group_id"]); - // Position the inspector relative to the mouse cursor - // Similar to how tooltips are positioned - // See LLToolTipMgr::createToolTip - if (data.has("pos")) - { - LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); - } - else - { - LLUI::getInstance()->positionViewNearMouse(this); - } + LLInspect::repositionInspector(data); // can't call from constructor as widgets are not built yet requestUpdate(); diff --git a/indra/newview/llinspectobject.cpp b/indra/newview/llinspectobject.cpp index c270075624..4e295cb02d 100644 --- a/indra/newview/llinspectobject.cpp +++ b/indra/newview/llinspectobject.cpp @@ -56,7 +56,6 @@ #include "lltextbox.h" // for description truncation #include "lltoggleablemenu.h" #include "lltrans.h" -#include "llui.h" // positionViewNearMouse() #include "lluictrl.h" class LLViewerObject; @@ -204,17 +203,8 @@ void LLInspectObject::onOpen(const LLSD& data) { mObjectFace = data["object_face"]; } - // Position the inspector relative to the mouse cursor - // Similar to how tooltips are positioned - // See LLToolTipMgr::createToolTip - if (data.has("pos")) - { - LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); - } - else - { - LLUI::getInstance()->positionViewNearMouse(this); - } + + LLInspect::repositionInspector(data); // Promote hovered object to a complete selection, which will also force // a request for selected object data off the network diff --git a/indra/newview/llinspectremoteobject.cpp b/indra/newview/llinspectremoteobject.cpp index c77b510a17..da3ed9ebbf 100644 --- a/indra/newview/llinspectremoteobject.cpp +++ b/indra/newview/llinspectremoteobject.cpp @@ -124,17 +124,7 @@ void LLInspectRemoteObject::onOpen(const LLSD& data) // update the inspector with the current object state update(); - // Position the inspector relative to the mouse cursor - // Similar to how tooltips are positioned - // See LLToolTipMgr::createToolTip - if (data.has("pos")) - { - LLUI::getInstance()->positionViewNearMouse(this, data["pos"]["x"].asInteger(), data["pos"]["y"].asInteger()); - } - else - { - LLUI::getInstance()->positionViewNearMouse(this); - } + LLInspect::repositionInspector(data); } void LLInspectRemoteObject::onClickMap() diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp index d0034eff13..68801b0895 100644 --- a/indra/newview/llinspecttoast.cpp +++ b/indra/newview/llinspecttoast.cpp @@ -110,7 +110,7 @@ void LLInspectToast::onOpen(const LLSD& notification_id) panel_rect = panel->getRect(); reshape(panel_rect.getWidth(), panel_rect.getHeight()); - LLUI::getInstance()->positionViewNearMouse(this); + LLInspect::repositionInspector(notification_id); } // virtual diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index 362d47142d..668a469fce 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -118,6 +118,7 @@ public: bool addUnit(); bool addUnit(const std::vector& filenames); bool addUnit(const std::string& filename); + LLUUID addUnit(const std::string &filename); void delUnit(LLUUID tracking_id); bool checkTextureDimensions(std::string filename); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index adee611db8..b216e3e52e 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1374,6 +1374,7 @@ void LLOutfitGallery::onSelectPhoto(LLUUID selected_outfit_id) texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLOutfitGallery::onTexturePickerCommit, this, _1, _2)); texture_floaterp->setOnUpdateImageStatsCallback(boost::bind(&LLOutfitGallery::onTexturePickerUpdateImageStats, this, _1)); texture_floaterp->setLocalTextureEnabled(FALSE); + texture_floaterp->setBakeTextureEnabled(FALSE); texture_floaterp->setCanApply(false, true); } diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 37ed4bc74c..9a030f1d7d 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelavatar.cpp * @brief LLPanelAvatar and related class implementations * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,173 +28,127 @@ #include "llpanelavatar.h" #include "llagent.h" -#include "llavataractions.h" -#include "llcallingcard.h" -#include "llcombobox.h" -#include "lldateutil.h" // ageFromDate() -#include "llimview.h" -#include "llmenubutton.h" -#include "llnotificationsutil.h" -#include "llslurl.h" -#include "lltexteditor.h" -#include "lltexturectrl.h" -#include "lltoggleablemenu.h" +#include "llloadingindicator.h" #include "lltooldraganddrop.h" -#include "llscrollcontainer.h" -#include "llavatariconctrl.h" -#include "llfloaterreg.h" -#include "llnotificationsutil.h" -#include "llviewermenu.h" // is_agent_mappable -#include "llvoiceclient.h" -#include "lltextbox.h" -#include "lltrans.h" -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLDropTarget -// -// This handy class is a simple way to drop something on another -// view. It handles drop events, always setting itself to the size of -// its parent. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +////////////////////////////////////////////////////////////////////////// +// LLProfileDropTarget -class LLDropTarget : public LLView -{ -public: - struct Params : public LLInitParam::Block - { - Optional agent_id; - Params() - : agent_id("agent_id") - { - changeDefault(mouse_opaque, false); - changeDefault(follows.flags, FOLLOWS_ALL); - } - }; - - LLDropTarget(const Params&); - ~LLDropTarget(); - - void doDrop(EDragAndDropType cargo_type, void* cargo_data); - - // - // LLView functionality - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - void setAgentID(const LLUUID &agent_id) { mAgentID = agent_id; } -protected: - LLUUID mAgentID; -}; - -LLDropTarget::LLDropTarget(const LLDropTarget::Params& p) -: LLView(p), - mAgentID(p.agent_id) +LLProfileDropTarget::LLProfileDropTarget(const LLProfileDropTarget::Params& p) +: LLView(p), + mAgentID(p.agent_id) {} -LLDropTarget::~LLDropTarget() -{} - -void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) +void LLProfileDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { - LL_INFOS() << "LLDropTarget::doDrop()" << LL_ENDL; + LL_INFOS() << "LLProfileDropTarget::doDrop()" << LL_ENDL; } -BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) +BOOL LLProfileDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - if(getParent()) - { - LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop, - cargo_type, cargo_data, accept); + if (getParent()) + { + LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop, + cargo_type, cargo_data, accept); - return TRUE; - } + return TRUE; + } - return FALSE; + return FALSE; } -static LLDefaultChildRegistry::Register r("drop_target"); +static LLDefaultChildRegistry::Register r("profile_drop_target"); ////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// +// LLPanelProfileTab LLPanelProfileTab::LLPanelProfileTab() : LLPanel() , mAvatarId(LLUUID::null) +, mLoadingState(PROFILE_INIT) +, mSelfProfile(false) { } LLPanelProfileTab::~LLPanelProfileTab() { - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } } -void LLPanelProfileTab::setAvatarId(const LLUUID& id) +void LLPanelProfileTab::setAvatarId(const LLUUID& avatar_id) { - if(id.notNull()) - { - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId,this); - } - mAvatarId = id; - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(),this); - } + if (avatar_id.notNull()) + { + mAvatarId = avatar_id; + mSelfProfile = (getAvatarId() == gAgentID); + } } void LLPanelProfileTab::onOpen(const LLSD& key) { - // Don't reset panel if we are opening it for same avatar. - if(getAvatarId() != key.asUUID()) - { - resetControls(); - resetData(); + // Update data even if we are viewing same avatar profile as some data might been changed. + setAvatarId(key.asUUID()); - scrollToTop(); - } - - // Update data even if we are viewing same avatar profile as some data might been changed. - setAvatarId(key.asUUID()); - updateData(); - updateButtons(); + setApplyProgress(true); } -void LLPanelProfileTab::scrollToTop() +void LLPanelProfileTab::setLoaded() { - LLScrollContainer* scrollContainer = findChild("profile_scroll"); - if (scrollContainer) - scrollContainer->goToTop(); + setApplyProgress(false); + + mLoadingState = PROFILE_LOADED; } -void LLPanelProfileTab::onMapButtonClick() +void LLPanelProfileTab::setApplyProgress(bool started) { - LLAvatarActions::showOnMap(getAvatarId()); + LLLoadingIndicator* indicator = findChild("progress_indicator"); + + if (indicator) + { + indicator->setVisible(started); + + if (started) + { + indicator->start(); + } + else + { + indicator->stop(); + } + } + + LLPanel* panel = findChild("indicator_stack"); + if (panel) + { + panel->setVisible(started); + } } -void LLPanelProfileTab::updateButtons() +LLPanelProfilePropertiesProcessorTab::LLPanelProfilePropertiesProcessorTab() + : LLPanelProfileTab() { - bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()); - - if(LLAvatarActions::isFriend(getAvatarId())) - { - getChildView("teleport")->setEnabled(is_buddy_online); - } - else - { - getChildView("teleport")->setEnabled(true); - } - - bool enable_map_btn = (is_buddy_online && - is_agent_mappable(getAvatarId())) - || gAgent.isGodlike(); - getChildView("show_on_map_btn")->setEnabled(enable_map_btn); +} + +LLPanelProfilePropertiesProcessorTab::~LLPanelProfilePropertiesProcessorTab() +{ + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } +} + +void LLPanelProfilePropertiesProcessorTab::setAvatarId(const LLUUID & avatar_id) +{ + if (avatar_id.notNull()) + { + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } + LLPanelProfileTab::setAvatarId(avatar_id); + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); + } } diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index e33a850cfa..f182660c8e 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -1,25 +1,25 @@ -/** +/** * @file llpanelavatar.h - * @brief LLPanelAvatar and related class definitions + * @brief Legacy profile panel base class * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * + * Copyright (C) 2019, Linden Research, Inc. + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,80 +29,141 @@ #include "llpanel.h" #include "llavatarpropertiesprocessor.h" -#include "llcallingcard.h" -#include "llvoiceclient.h" #include "llavatarnamecache.h" class LLComboBox; class LLLineEditor; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLProfileDropTarget +// +// This handy class is a simple way to drop something on another +// view. It handles drop events, always setting itself to the size of +// its parent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLProfileDropTarget : public LLView +{ +public: + struct Params : public LLInitParam::Block + { + Optional agent_id; + Params() + : agent_id("agent_id") + { + changeDefault(mouse_opaque, false); + changeDefault(follows.flags, FOLLOWS_ALL); + } + }; + + LLProfileDropTarget(const Params&); + ~LLProfileDropTarget() {} + + void doDrop(EDragAndDropType cargo_type, void* cargo_data); + + // + // LLView functionality + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + void setAgentID(const LLUUID &agent_id) { mAgentID = agent_id; } + +protected: + LLUUID mAgentID; +}; + + /** * Base class for any Profile View. */ class LLPanelProfileTab - : public LLPanel - , public LLAvatarPropertiesObserver + : public LLPanel { public: - /** - * Sets avatar ID, sets panel as observer of avatar related info replies from server. - */ - virtual void setAvatarId(const LLUUID& id); + /** + * Sets avatar ID, sets panel as observer of avatar related info replies from server. + */ + virtual void setAvatarId(const LLUUID& avatar_id); - /** - * Returns avatar ID. - */ - virtual const LLUUID& getAvatarId() { return mAvatarId; } + /** + * Returns avatar ID. + */ + virtual const LLUUID& getAvatarId() { return mAvatarId; } - /** - * Sends update data request to server. - */ - virtual void updateData() = 0; + /** + * Sends update data request to server. + */ + virtual void updateData() {}; - /** - * Clears panel data if viewing avatar info for first time and sends update data request. - */ - virtual void onOpen(const LLSD& key); + /** + * Clears panel data if viewing avatar info for first time and sends update data request. + */ + virtual void onOpen(const LLSD& key); - /** - * Profile tabs should close any opened panels here. - * - * Called from LLPanelProfile::onOpen() before opening new profile. - * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel - * before new profile is displayed, otherwise new profile will - * be hidden behind picture info panel. - */ - virtual void onClosePanel() {} + /** + * Clears all data received from server. + */ + virtual void resetData(){}; - /** - * Resets controls visibility, state, etc. - */ - virtual void resetControls(){}; - - /** - * Clears all data received from server. - */ - virtual void resetData(){}; - - /*virtual*/ ~LLPanelProfileTab(); + /*virtual*/ ~LLPanelProfileTab(); protected: - LLPanelProfileTab(); + LLPanelProfileTab(); - /** - * Scrolls panel to top when viewing avatar info for first time. - */ - void scrollToTop(); + enum ELoadingState + { + PROFILE_INIT, + PROFILE_LOADING, + PROFILE_LOADED, + }; - virtual void onMapButtonClick(); - virtual void updateButtons(); + // mLoading: false: Initial state, can request + // true: Data requested, skip duplicate requests (happens due to LLUI's habit of repeated callbacks) + // mLoaded: false: Initial state, show loading indicator + // true: Data recieved, which comes in a single message, hide indicator + ELoadingState getLoadingState() { return mLoadingState; } + virtual void setLoaded(); + void setApplyProgress(bool started); + + const bool getSelfProfile() const { return mSelfProfile; } + +public: + void setIsLoading() { mLoadingState = PROFILE_LOADING; } + void resetLoading() { mLoadingState = PROFILE_INIT; } + + bool getStarted() { return mLoadingState != PROFILE_INIT; } + bool getIsLoaded() { return mLoadingState == PROFILE_LOADED; } + + virtual bool hasUnsavedChanges() { return false; } + virtual void commitUnsavedChanges() {} private: - LLUUID mAvatarId; + LLUUID mAvatarId; + ELoadingState mLoadingState; + bool mSelfProfile; +}; + +class LLPanelProfilePropertiesProcessorTab + : public LLPanelProfileTab + , public LLAvatarPropertiesObserver +{ +public: + LLPanelProfilePropertiesProcessorTab(); + ~LLPanelProfilePropertiesProcessorTab(); + + /*virtual*/ void setAvatarId(const LLUUID& avatar_id); + + /** + * Processes data received from server via LLAvatarPropertiesObserver. + */ + virtual void processProperties(void* data, EAvatarProcessorType type) = 0; }; #endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index f3cc0e2778..183000ceac 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -1,10 +1,10 @@ /** * @file llpanelclassified.cpp - * @brief LLPanelClassified class implementation + * @brief LLPanelClassifiedInfo class implementation * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2021, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,38 +34,21 @@ #include "lldispatcher.h" #include "llfloaterreg.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" #include "llparcel.h" #include "llagent.h" #include "llclassifiedflags.h" -#include "llcommandhandler.h" // for classified HTML detail page click tracking #include "lliconctrl.h" -#include "lllineeditor.h" -#include "llcombobox.h" #include "lltexturectrl.h" -#include "lltexteditor.h" -#include "llviewerparcelmgr.h" #include "llfloaterworldmap.h" #include "llviewergenericmessage.h" // send_generic_message #include "llviewerregion.h" -#include "llviewertexture.h" -#include "lltrans.h" #include "llscrollcontainer.h" -#include "llstatusbar.h" -#include "llviewertexture.h" #include "llcorehttputil.h" -#ifdef OPENSIM -#include "llviewernetwork.h" -#endif // OPENSIM -#include "fspanelclassified.h" - -const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ - //static LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels; +static LLPanelInjector t_panel_panel_classified_info("panel_classified_info"); // "classifiedclickthrough" // strings[0] = classified_id @@ -121,25 +104,10 @@ LLPanelClassifiedInfo::LLPanelClassifiedInfo() LLPanelClassifiedInfo::~LLPanelClassifiedInfo() { sAllPanels.remove(this); -// [SL:KB] - Patch : UI-ProfileGroupFloater | Checked: 2010-11-28 (Catznip-2.4.0g) | Added: Catznip-2.4.0g - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - } -// [/SL:KB] -} - -// static -LLPanelClassifiedInfo* LLPanelClassifiedInfo::create() -{ - LLPanelClassifiedInfo* panel = new LLPanelClassifiedInfo(); - panel->buildFromFile("panel_classified_info.xml"); - return panel; } BOOL LLPanelClassifiedInfo::postBuild() { - childSetAction("back_btn", boost::bind(&LLPanelClassifiedInfo::onExit, this)); childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this)); childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this)); @@ -155,16 +123,6 @@ BOOL LLPanelClassifiedInfo::postBuild() return TRUE; } -void LLPanelClassifiedInfo::setExitCallback(const commit_callback_t& cb) -{ - getChild("back_btn")->setClickedCallback(cb); -} - -void LLPanelClassifiedInfo::setEditClassifiedCallback(const commit_callback_t& cb) -{ - getChild("edit_btn")->setClickedCallback(cb); -} - void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) { LLPanel::reshape(width, height, called_from_parent); @@ -256,14 +214,6 @@ void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD r map + search_map, profile + search_profile, true); - - // FIRE-8787: Also update legacy profiles - FSPanelClassifiedInfo::setClickThrough(classifiedId, - teleport + search_teleport, - map + search_map, - profile + search_profile, - true); - // } void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) @@ -305,6 +255,8 @@ void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType t getChild("creation_date")->setValue(date_str); setInfoLoaded(true); + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); } } } @@ -609,605 +561,4 @@ void LLPanelClassifiedInfo::onTeleportClick() } } -void LLPanelClassifiedInfo::onExit() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -static const S32 CB_ITEM_MATURE = 0; -static const S32 CB_ITEM_PG = 1; - -LLPanelClassifiedEdit::LLPanelClassifiedEdit() - : LLPanelClassifiedInfo() - , mIsNew(false) - , mIsNewWithErrors(false) - , mCanClose(false) - , mPublishFloater(NULL) -{ -} - -LLPanelClassifiedEdit::~LLPanelClassifiedEdit() -{ -} - -//static -LLPanelClassifiedEdit* LLPanelClassifiedEdit::create() -{ - LLPanelClassifiedEdit* panel = new LLPanelClassifiedEdit(); - panel->buildFromFile("panel_edit_classified.xml"); - return panel; -} - -BOOL LLPanelClassifiedEdit::postBuild() -{ - LLPanelClassifiedInfo::postBuild(); - - LLUICtrl* edit_icon = getChild("edit_icon"); - mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon)); - mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon)); - edit_icon->setVisible(false); - - LLLineEditor* line_edit = getChild("classified_name"); - line_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - - LLTextEditor* text_edit = getChild("classified_desc"); - text_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - - LLComboBox* combobox = getChild( "category"); - LLClassifiedInfo::cat_map::iterator iter; - for (iter = LLClassifiedInfo::sCategories.begin(); - iter != LLClassifiedInfo::sCategories.end(); - iter++) - { - combobox->add(LLTrans::getString(iter->second)); - } - - combobox->setCommitCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - - childSetCommitCallback("content_type", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("price_for_listing", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("auto_renew", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - - childSetAction("save_changes_btn", boost::bind(&LLPanelClassifiedEdit::onSaveClick, this)); - childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelClassifiedEdit::onSetLocationClick, this)); - - mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onTextureSelected, this)); - - return TRUE; -} - -void LLPanelClassifiedEdit::fillIn(const LLSD& key) -{ - setAvatarId(gAgent.getID()); - - if(key.isUndefined()) - { - setPosGlobal(gAgent.getPositionGlobal()); - - LLUUID snapshot_id = LLUUID::null; - std::string desc; - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if(parcel) - { - desc = parcel->getDesc(); - snapshot_id = parcel->getSnapshotID(); - } - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - getChild("classified_name")->setValue(makeClassifiedName()); - getChild("classified_desc")->setValue(desc); - setSnapshotId(snapshot_id); - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - // server will set valid parcel id - setParcelId(LLUUID::null); - } - else - { - setClassifiedId(key["classified_id"]); - setClassifiedName(key["name"]); - setDescription(key["desc"]); - setSnapshotId(key["snapshot_id"]); - setCategory((U32)key["category"].asInteger()); - setContentType((U32)key["content_type"].asInteger()); - setClassifiedLocation(key["location_text"]); - getChild("auto_renew")->setValue(key["auto_renew"]); - getChild("price_for_listing")->setValue(key["price_for_listing"].asInteger()); - } -} - -void LLPanelClassifiedEdit::onOpen(const LLSD& key) -{ - mIsNew = key.isUndefined(); - - scrollToTop(); - - // classified is not created yet - bool is_new = isNew() || isNewWithErrors(); - - if(is_new) - { - resetData(); - resetControls(); - - fillIn(key); - - if(isNew()) - { - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - } - } - else - { - LLPanelClassifiedInfo::onOpen(key); - } - - std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label"); - getChild("save_changes_btn")->setLabelArg("[LABEL]", save_btn_label); - - enableVerbs(is_new); - enableEditing(is_new); - showEditing(!is_new); - resetDirty(); - setInfoLoaded(false); -} - -void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO == type) - { - LLAvatarClassifiedInfo* c_info = static_cast(data); - if(c_info && getClassifiedId() == c_info->classified_id) - { - // see LLPanelClassifiedEdit::sendUpdate() for notes - mIsNewWithErrors = false; - // for just created classified - panel will probably be closed when we get here. - if(!getVisible()) - { - return; - } - - enableEditing(true); - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setParcelId(c_info->parcel_id); - setPosGlobal(c_info->pos_global); - - setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - // *HACK see LLPanelClassifiedEdit::sendUpdate() - setCategory(c_info->category - 1); - - bool mature = is_cf_mature(c_info->flags); - bool auto_renew = is_cf_auto_renew(c_info->flags); - - setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG); - getChild("auto_renew")->setValue(auto_renew); - getChild("price_for_listing")->setValue(c_info->price_for_listing); - getChildView("price_for_listing")->setEnabled(isNew()); - - resetDirty(); - setInfoLoaded(true); - enableVerbs(false); - - // for just created classified - in case user opened edit panel before processProperties() callback - getChild("save_changes_btn")->setLabelArg("[LABEL]", getString("save_label")); - } - } -} - -BOOL LLPanelClassifiedEdit::isDirty() const -{ - if(mIsNew) - { - return TRUE; - } - - BOOL dirty = false; - - dirty |= LLPanelClassifiedInfo::isDirty(); - dirty |= getChild("classified_snapshot")->isDirty(); - dirty |= getChild("classified_name")->isDirty(); - dirty |= getChild("classified_desc")->isDirty(); - dirty |= getChild("category")->isDirty(); - dirty |= getChild("content_type")->isDirty(); - dirty |= getChild("auto_renew")->isDirty(); - dirty |= getChild("price_for_listing")->isDirty(); - - return dirty; -} - -void LLPanelClassifiedEdit::resetDirty() -{ - LLPanelClassifiedInfo::resetDirty(); - getChild("classified_snapshot")->resetDirty(); - getChild("classified_name")->resetDirty(); - - LLTextEditor* desc = getChild("classified_desc"); - // call blockUndo() to really reset dirty(and make isDirty work as intended) - desc->blockUndo(); - desc->resetDirty(); - - getChild("category")->resetDirty(); - getChild("content_type")->resetDirty(); - getChild("auto_renew")->resetDirty(); - getChild("price_for_listing")->resetDirty(); -} - -void LLPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb) -{ - mSaveButtonClickedSignal.connect(cb); -} - -void LLPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -void LLPanelClassifiedEdit::resetControls() -{ - LLPanelClassifiedInfo::resetControls(); - - getChild("category")->setCurrentByIndex(0); - getChild("content_type")->setCurrentByIndex(0); - getChild("auto_renew")->setValue(false); - // FIRE-9814 - Don't hardcode a classified listing fee - //getChild("price_for_listing")->setValue(MINIMUM_PRICE_FOR_LISTING); - getChild("price_for_listing")->setValue(getClassifiedFee()); - // - getChildView("price_for_listing")->setEnabled(TRUE); -} - -// FIRE-9814 - Don't hardcode a classified listing fee -S32 LLPanelClassifiedEdit::getClassifiedFee() -{ - S32 fee = MINIMUM_PRICE_FOR_LISTING; -#ifdef OPENSIM - if (LLGridManager::getInstance()->isInOpenSim()) - { - fee = LLGridManager::getInstance()->getClassifiedFee(); - } -#endif // OPENSIM - return fee; -} -// - -bool LLPanelClassifiedEdit::canClose() -{ - return mCanClose; -} - -void LLPanelClassifiedEdit::draw() -{ - LLPanel::draw(); - - // Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback - // does not trigger callbacks when user navigates through images. - stretchSnapshot(); -} - -void LLPanelClassifiedEdit::stretchSnapshot() -{ - LLPanelClassifiedInfo::stretchSnapshot(); - - getChild("edit_icon")->setShape(mSnapshotCtrl->getRect()); -} - -U32 LLPanelClassifiedEdit::getContentType() -{ - LLComboBox* ct_cb = getChild("content_type"); - return ct_cb->getCurrentIndex(); -} - -void LLPanelClassifiedEdit::setContentType(U32 content_type) -{ - LLComboBox* ct_cb = getChild("content_type"); - ct_cb->setCurrentByIndex(content_type); - ct_cb->resetDirty(); -} - -bool LLPanelClassifiedEdit::getAutoRenew() -{ - return getChild("auto_renew")->getValue().asBoolean(); -} - -void LLPanelClassifiedEdit::sendUpdate() -{ - LLAvatarClassifiedInfo c_data; - - if(getClassifiedId().isNull()) - { - setClassifiedId(LLUUID::generateNewID()); - } - - c_data.agent_id = gAgent.getID(); - c_data.classified_id = getClassifiedId(); - // *HACK - // Categories on server start with 1 while combo-box index starts with 0 - c_data.category = getCategory() + 1; - c_data.name = getClassifiedName(); - c_data.description = getDescription(); - c_data.parcel_id = getParcelId(); - c_data.snapshot_id = getSnapshotId(); - c_data.pos_global = getPosGlobal(); - c_data.flags = getFlags(); - c_data.price_for_listing = getPriceForListing(); - - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); - - if(isNew()) - { - // Lets assume there will be some error. - // Successful sendClassifiedInfoUpdate will trigger processProperties and - // let us know there was no error. - mIsNewWithErrors = true; - } -} - -U32 LLPanelClassifiedEdit::getCategory() -{ - LLComboBox* cat_cb = getChild("category"); - return cat_cb->getCurrentIndex(); -} - -void LLPanelClassifiedEdit::setCategory(U32 category) -{ - LLComboBox* cat_cb = getChild("category"); - cat_cb->setCurrentByIndex(category); - cat_cb->resetDirty(); -} - -U8 LLPanelClassifiedEdit::getFlags() -{ - bool auto_renew = getChild("auto_renew")->getValue().asBoolean(); - - LLComboBox* content_cb = getChild("content_type"); - bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE; - - return pack_classified_flags_request(auto_renew, false, mature, false); -} - -void LLPanelClassifiedEdit::enableVerbs(bool enable) -{ - getChildView("save_changes_btn")->setEnabled(enable); -} - -void LLPanelClassifiedEdit::enableEditing(bool enable) -{ - getChildView("classified_snapshot")->setEnabled(enable); - getChildView("classified_name")->setEnabled(enable); - getChildView("classified_desc")->setEnabled(enable); - getChildView("set_to_curr_location_btn")->setEnabled(enable); - getChildView("category")->setEnabled(enable); - getChildView("content_type")->setEnabled(enable); - getChildView("price_for_listing")->setEnabled(enable); - getChildView("auto_renew")->setEnabled(enable); -} - -void LLPanelClassifiedEdit::showEditing(bool show) -{ - getChildView("price_for_listing_label")->setVisible( show); - getChildView("price_for_listing")->setVisible( show); -} - -std::string LLPanelClassifiedEdit::makeClassifiedName() -{ - std::string name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(parcel) - { - name = parcel->getName(); - } - - if(!name.empty()) - { - return name; - } - - LLViewerRegion* region = gAgent.getRegion(); - if(region) - { - name = region->getName(); - } - - return name; -} - -S32 LLPanelClassifiedEdit::getPriceForListing() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void LLPanelClassifiedEdit::setPriceForListing(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -void LLPanelClassifiedEdit::onSetLocationClick() -{ - setPosGlobal(gAgent.getPositionGlobal()); - setParcelId(LLUUID::null); - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - - // mark classified as dirty - setValue(LLSD()); - - onChange(); -} - -void LLPanelClassifiedEdit::onChange() -{ - enableVerbs(isDirty()); -} - -void LLPanelClassifiedEdit::onSaveClick() -{ - mCanClose = false; - - if(!isValidName()) - { - notifyInvalidName(); - return; - } - if(isNew() || isNewWithErrors()) - { - if(gStatusBar->getBalance() < getPriceForListing()) - { - LLNotificationsUtil::add("ClassifiedInsufficientFunds"); - return; - } - - mPublishFloater = LLFloaterReg::findTypedInstance( - "publish_classified", LLSD()); - - if(!mPublishFloater) - { - mPublishFloater = LLFloaterReg::getTypedInstance( - "publish_classified", LLSD()); - - mPublishFloater->setPublishClickedCallback(boost::bind - (&LLPanelClassifiedEdit::onPublishFloaterPublishClicked, this)); - } - - // set spinner value before it has focus or value wont be set - mPublishFloater->setPrice(getPriceForListing()); - mPublishFloater->openFloater(mPublishFloater->getKey()); - mPublishFloater->center(); - } - else - { - doSave(); - } -} - -void LLPanelClassifiedEdit::doSave() -{ - mCanClose = true; - sendUpdate(); - resetDirty(); - - mSaveButtonClickedSignal(this, LLSD()); -} - -void LLPanelClassifiedEdit::onPublishFloaterPublishClicked() -{ - setPriceForListing(mPublishFloater->getPrice()); - - doSave(); -} - -std::string LLPanelClassifiedEdit::getLocationNotice() -{ - static std::string location_notice = getString("location_notice"); - return location_notice; -} - -bool LLPanelClassifiedEdit::isValidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - return false; - } - if (!isalnum(name[0])) - { - return false; - } - - return true; -} - -void LLPanelClassifiedEdit::notifyInvalidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - LLNotificationsUtil::add("BlankClassifiedName"); - } - else if (!isalnum(name[0])) - { - LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric"); - } -} - -void LLPanelClassifiedEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl) -{ - ctrl->setVisible(TRUE); -} - -void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) -{ - ctrl->setVisible(FALSE); -} - -void LLPanelClassifiedEdit::onTextureSelected() -{ - setSnapshotId(mSnapshotCtrl->getValue().asUUID()); - onChange(); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key) - : LLFloater(key) -{ -} - -LLPublishClassifiedFloater::~LLPublishClassifiedFloater() -{ -} - -BOOL LLPublishClassifiedFloater::postBuild() -{ - LLFloater::postBuild(); - - childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); - childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); - - return TRUE; -} - -void LLPublishClassifiedFloater::setPrice(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -S32 LLPublishClassifiedFloater::getPrice() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("publish_btn")->setClickedCallback(cb); -} - -void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - //EOF diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index 2d88abd01f..471becd0f7 100644 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -1,10 +1,10 @@ /** * @file llpanelclassified.h - * @brief LLPanelClassified class definition + * @brief LLPanelClassifiedInfo class definition * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2021, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,39 +35,16 @@ #include "llfloater.h" #include "llpanel.h" #include "llrect.h" -#include "lluuid.h" -#include "v3dmath.h" -#include "llcoros.h" -#include "lleventcoro.h" class LLScrollContainer; class LLTextureCtrl; -class LLUICtrl; - -class LLPublishClassifiedFloater : public LLFloater -{ -public: - LLPublishClassifiedFloater(const LLSD& key); - virtual ~LLPublishClassifiedFloater(); - - /*virtual*/ BOOL postBuild(); - - void setPrice(S32 price); - S32 getPrice(); - - void setPublishClickedCallback(const commit_signal_t::slot_type& cb); - void setCancelClickedCallback(const commit_signal_t::slot_type& cb); - -private: -}; class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver { LOG_CLASS(LLPanelClassifiedInfo); public: - static LLPanelClassifiedInfo* create(); - + LLPanelClassifiedInfo(); virtual ~LLPanelClassifiedInfo(); /*virtual*/ void onOpen(const LLSD& key); @@ -135,18 +112,12 @@ public: const LLVector3d& global_pos, const std::string& sim_name); - void setExitCallback(const commit_callback_t& cb); - - void setEditClassifiedCallback(const commit_callback_t& cb); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); /*virtual*/ void draw(); protected: - LLPanelClassifiedInfo(); - virtual void resetData(); virtual void resetControls(); @@ -165,7 +136,6 @@ protected: void onMapClick(); void onTeleportClick(); - void onExit(); bool mSnapshotStreched; LLRect mSnapshotRect; @@ -195,109 +165,11 @@ private: S32 mMapClicksNew; S32 mProfileClicksNew; -public: // Need this public for fspanelclassified - static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + -private: // typedef std::list panel_list_t; static panel_list_t sAllPanels; }; -class LLPanelClassifiedEdit : public LLPanelClassifiedInfo -{ - LOG_CLASS(LLPanelClassifiedEdit); -public: - - static LLPanelClassifiedEdit* create(); - - virtual ~LLPanelClassifiedEdit(); - - /*virtual*/ BOOL postBuild(); - - void fillIn(const LLSD& key); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL isDirty() const; - - /*virtual*/ void resetDirty(); - - void setSaveCallback(const commit_signal_t::slot_type& cb); - - void setCancelCallback(const commit_signal_t::slot_type& cb); - - /*virtual*/ void resetControls(); - - bool isNew() { return mIsNew; } - - bool isNewWithErrors() { return mIsNewWithErrors; } - - bool canClose(); - - void draw(); - - void stretchSnapshot(); - - U32 getCategory(); - - void setCategory(U32 category); - - U32 getContentType(); - - void setContentType(U32 content_type); - - bool getAutoRenew(); - - S32 getPriceForListing(); - -protected: - - LLPanelClassifiedEdit(); - - void sendUpdate(); - - void enableVerbs(bool enable); - - void enableEditing(bool enable); - - void showEditing(bool show); - - std::string makeClassifiedName(); - - void setPriceForListing(S32 price); - - U8 getFlags(); - - std::string getLocationNotice(); - - bool isValidName(); - - void notifyInvalidName(); - - void onSetLocationClick(); - void onChange(); - void onSaveClick(); - - void doSave(); - - void onPublishFloaterPublishClicked(); - - void onTexturePickerMouseEnter(LLUICtrl* ctrl); - void onTexturePickerMouseLeave(LLUICtrl* ctrl); - - void onTextureSelected(); - -private: - S32 getClassifiedFee(); // FIRE-9814 - Don't hardcode a classified listing fee - bool mIsNew; - bool mIsNewWithErrors; - bool mCanClose; - - LLPublishClassifiedFloater* mPublishFloater; - - commit_signal_t mSaveButtonClickedSignal; -}; - #endif // LL_LLPANELCLASSIFIED_H diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h index 9d5afd1a6a..11111f2a2e 100644 --- a/indra/newview/llpanelexperiences.h +++ b/indra/newview/llpanelexperiences.h @@ -29,7 +29,6 @@ #include "llaccordionctrltab.h" #include "llflatlistview.h" -#include "llpanelavatar.h" class LLExperienceItem; class LLPanelProfile; diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 1808f5f7a2..5278056f9c 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -1,6 +1,6 @@ /** - * @file llpanelavatar.cpp - * @brief LLPanelAvatar and related class implementations + * @file llpanelimcontrolpanel.cpp + * @brief LLPanelIMControlPanel and related class implementations * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index c8d144ef8a..9fdf7117bd 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -29,6 +29,7 @@ #include "llpanellandmarks.h" #include "llbutton.h" +#include "llfloaterprofile.h" #include "llfloaterreg.h" #include "llnotificationsutil.h" #include "llsdutil.h" @@ -1080,17 +1081,6 @@ bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFold return can_be_modified; } -void LLLandmarksPanel::onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params) -{ - pick_panel->setVisible(FALSE); - owner->removeChild(pick_panel); - //we need remove observer to avoid processParcelInfo in the future. - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this); - - delete pick_panel; - pick_panel = NULL; -} - bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data , EAcceptance* accept) { *accept = ACCEPT_NO; @@ -1158,49 +1148,21 @@ void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, LLInventoryItem* inv_item, const LLParcelData& parcel_data) { - LLPanelPickEdit* panel_pick = LLPanelPickEdit::create(); LLVector3d landmark_global_pos; landmark->getGlobalPos(landmark_global_pos); - // let's toggle pick panel into panel places - LLPanel* panel_places = NULL; - LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance("places"); - if (floaterp) - { - panel_places = floaterp->findChild("main_panel"); - } - - if (!panel_places) - { - llassert(NULL != panel_places); - return; - } - panel_places->addChild(panel_pick); - LLRect paren_rect(panel_places->getRect()); - panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE); - panel_pick->setRect(paren_rect); - panel_pick->onOpen(LLSD()); - LLPickData data; data.pos_global = landmark_global_pos; data.name = inv_item->getName(); data.desc = inv_item->getDescription(); data.snapshot_id = parcel_data.snapshot_id; data.parcel_id = parcel_data.parcel_id; - panel_pick->setPickData(&data); - LLSD params; - params["parcel_id"] = parcel_data.parcel_id; - /* set exit callback to get back onto panel places - in callback we will make cleaning up( delete pick_panel instance, - remove landmark panel from observer list - */ - panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, - panel_pick, panel_places,params)); - panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, - panel_pick, panel_places,params)); - panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, - panel_pick, panel_places,params)); + LLFloaterProfile* profile_floater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgentID))); + if (profile_floater) + { + profile_floater->createPick(data); + } } void LLLandmarksPanel::doCreatePick(LLLandmark* landmark, const LLUUID &item_id) diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 2f99e6c47b..6650c604d7 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -34,7 +34,6 @@ #include "llinventorymodel.h" #include "lllandmarklist.h" #include "llpanelplacestab.h" -#include "llpanelpick.h" #include "llremoteparcelrequest.h" class LLAccordionCtrlTab; @@ -139,7 +138,6 @@ private: * For now it checks cut/rename/delete/paste actions. */ bool canItemBeModified(const std::string& command_name, LLFolderViewItem* item) const; - void onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params); /** * Landmark actions callbacks. Fire when a landmark is loaded from the list. diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp deleted file mode 100644 index 55e4ffff5e..0000000000 --- a/indra/newview/llpanelme.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file llpanelme.cpp - * @brief Side tray "Me" (My Profile) panel - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelme.h" - -// Viewer includes -#include "llpanelprofile.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llfirstuse.h" -#include "llfloaterreg.h" -#include "llhints.h" -#include "llviewercontrol.h" - -// Linden libraries -#include "llavatarnamecache.h" // IDEVO -#include "lliconctrl.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" // IDEVO -#include "lltabcontainer.h" -#include "lltexturectrl.h" - -static LLPanelInjector t_panel_me_profile("panel_me"); - -LLPanelMe::LLPanelMe(void) - : LLPanelProfile() -{ - setAvatarId(gAgent.getID()); -} - -BOOL LLPanelMe::postBuild() -{ - LLPanelProfile::postBuild(); - - return TRUE; -} - -void LLPanelMe::onOpen(const LLSD& key) -{ - LLPanelProfile::onOpen(key); -} diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp deleted file mode 100644 index 40326cfb39..0000000000 --- a/indra/newview/llpanelpick.cpp +++ /dev/null @@ -1,620 +0,0 @@ -/** - * @file llpanelpick.cpp - * @brief LLPanelPick class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Display of a "Top Pick" used both for the global top picks in the -// Find directory, and also for each individual user's picks in their -// profile. - -#include "llviewerprecompiledheaders.h" - -#include "llpanelpick.h" - -#include "message.h" - -#include "llparcel.h" - -#include "llbutton.h" -#include "llfloaterreg.h" -#include "lliconctrl.h" -#include "lllineeditor.h" -#include "llpanel.h" -#include "llscrollcontainer.h" -#include "lltexteditor.h" - -#include "llagent.h" -#include "llagentpicksinfo.h" -#include "llavatarpropertiesprocessor.h" -#include "llfloaterworldmap.h" -#include "lltexturectrl.h" -#include "lluiconstants.h" -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include "llworldmap.h" - - -#define XML_PANEL_EDIT_PICK "panel_edit_pick.xml" -#define XML_PANEL_PICK_INFO "panel_pick_info.xml" - -#define XML_NAME "pick_name" -#define XML_DESC "pick_desc" -#define XML_SNAPSHOT "pick_snapshot" -#define XML_LOCATION "pick_location" - -#define XML_BTN_ON_TXTR "edit_icon" -#define XML_BTN_SAVE "save_changes_btn" - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//static -LLPanelPickInfo* LLPanelPickInfo::create() -{ - LLPanelPickInfo* panel = new LLPanelPickInfo(); - panel->buildFromFile(XML_PANEL_PICK_INFO); - return panel; -} - -LLPanelPickInfo::LLPanelPickInfo() - : LLPanel() - , LLAvatarPropertiesObserver() - , LLRemoteParcelInfoObserver() - , mAvatarId(LLUUID::null) - , mSnapshotCtrl(NULL) - , mPickId(LLUUID::null) - , mParcelId(LLUUID::null) - , mRequestedId(LLUUID::null) - , mScrollingPanelMinHeight(0) - , mScrollingPanelWidth(0) - , mScrollingPanel(NULL) - , mScrollContainer(NULL) -{ -} - -LLPanelPickInfo::~LLPanelPickInfo() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - - if (mParcelId.notNull()) - { - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); - } -} - -void LLPanelPickInfo::onOpen(const LLSD& key) -{ - LLUUID avatar_id = key["avatar_id"]; - if(avatar_id.isNull()) - { - return; - } - - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver( - getAvatarId(), this); - } - - setAvatarId(avatar_id); - - resetData(); - resetControls(); - - setPickId(key["pick_id"]); - setPickName(key["pick_name"]); - setPickDesc(key["pick_desc"]); - setSnapshotId(key["snapshot_id"]); - - LLAvatarPropertiesProcessor::getInstance()->addObserver( - getAvatarId(), this); - LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest( - getAvatarId(), getPickId()); -} - -BOOL LLPanelPickInfo::postBuild() -{ - mSnapshotCtrl = getChild(XML_SNAPSHOT); - - childSetAction("teleport_btn", boost::bind(&LLPanelPickInfo::onClickTeleport, this)); - childSetAction("show_on_map_btn", boost::bind(&LLPanelPickInfo::onClickMap, this)); - childSetAction("back_btn", boost::bind(&LLPanelPickInfo::onClickBack, this)); - - mScrollingPanel = getChild("scroll_content_panel"); - mScrollContainer = getChild("profile_scroll"); - - mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); - mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); - - LLTextEditor* text_desc = getChild(XML_DESC); - text_desc->setContentTrusted(false); - - return TRUE; -} - -void LLPanelPickInfo::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPanel::reshape(width, height, called_from_parent); - - if (!mScrollContainer || !mScrollingPanel) - return; - - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - S32 scroll_height = mScrollContainer->getRect().getHeight(); - if (mScrollingPanelMinHeight >= scroll_height) - { - mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight); - } - else - { - mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); - } -} - -void LLPanelPickInfo::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_PICK_INFO != type) - { - return; - } - LLPickData* pick_info = static_cast(data); - if(!pick_info - || pick_info->creator_id != getAvatarId() - || pick_info->pick_id != getPickId()) - { - return; - } - - mParcelId = pick_info->parcel_id; - setSnapshotId(pick_info->snapshot_id); - setPickName(pick_info->name); - setPickDesc(pick_info->desc); - setPosGlobal(pick_info->pos_global); - - // Send remote parcel info request to get parcel name and sim (region) name. - sendParcelInfoRequest(); - - // *NOTE dzaporozhan - // We want to keep listening to APT_PICK_INFO because user may - // edit the Pick and we have to update Pick info panel. - // revomeObserver is called from onClickBack -} - -void LLPanelPickInfo::sendParcelInfoRequest() -{ - if (mParcelId != mRequestedId) - { - LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this); - LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId); - - mRequestedId = mParcelId; - } -} - -void LLPanelPickInfo::setExitCallback(const commit_callback_t& cb) -{ - getChild("back_btn")->setClickedCallback(cb); -} - -void LLPanelPickInfo::processParcelInfo(const LLParcelData& parcel_data) -{ - setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name, - parcel_data.sim_name, getPosGlobal())); - - // We have received parcel info for the requested ID so clear it now. - mRequestedId.setNull(); - - if (mParcelId.notNull()) - { - LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); - } -} - -void LLPanelPickInfo::setEditPickCallback(const commit_callback_t& cb) -{ - getChild("edit_btn")->setClickedCallback(cb); -} - -// PROTECTED AREA - -void LLPanelPickInfo::resetControls() -{ - if(getAvatarId() == gAgent.getID()) - { - getChildView("edit_btn")->setEnabled(TRUE); - getChildView("edit_btn")->setVisible( TRUE); - } - else - { - getChildView("edit_btn")->setEnabled(FALSE); - getChildView("edit_btn")->setVisible( FALSE); - } -} - -void LLPanelPickInfo::resetData() -{ - setPickName(LLStringUtil::null); - setPickDesc(LLStringUtil::null); - setPickLocation(LLStringUtil::null); - setPickId(LLUUID::null); - setSnapshotId(LLUUID::null); - mPosGlobal.clearVec(); - mParcelId.setNull(); - mRequestedId.setNull(); -} - -// static -std::string LLPanelPickInfo::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global) -{ - std::string location_text; - location_text.append(owner_name); - if (!original_name.empty()) - { - if (!location_text.empty()) location_text.append(", "); - location_text.append(original_name); - - } - if (!sim_name.empty()) - { - if (!location_text.empty()) location_text.append(", "); - location_text.append(sim_name); - } - - if (!location_text.empty()) location_text.append(" "); - - if (!pos_global.isNull()) - { - S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = ll_round((F32)pos_global.mdV[VZ]); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - } - return location_text; -} - -void LLPanelPickInfo::setSnapshotId(const LLUUID& id) -{ - mSnapshotCtrl->setImageAssetID(id); - mSnapshotCtrl->setValid(TRUE); -} - -void LLPanelPickInfo::setPickName(const std::string& name) -{ - getChild(XML_NAME)->setValue(name); -} - -void LLPanelPickInfo::setPickDesc(const std::string& desc) -{ - getChild(XML_DESC)->setValue(desc); -} - -void LLPanelPickInfo::setPickLocation(const std::string& location) -{ - getChild(XML_LOCATION)->setValue(location); -} - -void LLPanelPickInfo::onClickMap() -{ - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - LLFloaterReg::showInstance("world_map", "center"); -} - -void LLPanelPickInfo::onClickTeleport() -{ - if (!getPosGlobal().isExactlyZero()) - { - gAgent.teleportViaLocation(getPosGlobal()); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - } -} - -void LLPanelPickInfo::onClickBack() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -//static -LLPanelPickEdit* LLPanelPickEdit::create() -{ - LLPanelPickEdit* panel = new LLPanelPickEdit(); - panel->buildFromFile(XML_PANEL_EDIT_PICK); - return panel; -} - -LLPanelPickEdit::LLPanelPickEdit() - : LLPanelPickInfo() - , mLocationChanged(false) - , mNeedData(true) - , mNewPick(false) -{ -} - -LLPanelPickEdit::~LLPanelPickEdit() -{ -} - -void LLPanelPickEdit::onOpen(const LLSD& key) -{ - LLUUID pick_id = key["pick_id"]; - mNeedData = true; - - // creating new Pick - if(pick_id.isNull()) - { - mNewPick = true; - - setAvatarId(gAgent.getID()); - - resetData(); - resetControls(); - - setPosGlobal(gAgent.getPositionGlobal()); - - LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null; - std::string pick_name, pick_desc, region_name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(parcel) - { - parcel_id = parcel->getID(); - pick_name = parcel->getName(); - pick_desc = parcel->getDesc(); - snapshot_id = parcel->getSnapshotID(); - } - - LLViewerRegion* region = gAgent.getRegion(); - if(region) - { - region_name = region->getName(); - } - - setParcelID(parcel_id); - getChild("pick_name")->setValue(pick_name.empty() ? region_name : pick_name); - getChild("pick_desc")->setValue(pick_desc); - setSnapshotId(snapshot_id); - setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal())); - - enableSaveButton(true); - } - // editing existing pick - else - { - mNewPick = false; - LLPanelPickInfo::onOpen(key); - - enableSaveButton(false); - } - - resetDirty(); -} - -void LLPanelPickEdit::setPickData(const LLPickData* pick_data) -{ - if(!pick_data) - { - return; - } - - mNeedData = false; - - setParcelID(pick_data->parcel_id); - getChild("pick_name")->setValue(pick_data->name); - getChild("pick_desc")->setValue(pick_data->desc); - setSnapshotId(pick_data->snapshot_id); - setPosGlobal(pick_data->pos_global); - setPickLocation(createLocationText(LLStringUtil::null, pick_data->name, - pick_data->sim_name, pick_data->pos_global)); -} - -BOOL LLPanelPickEdit::postBuild() -{ - LLPanelPickInfo::postBuild(); - - mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelPickEdit::onSnapshotChanged, this)); - - LLLineEditor* line_edit = getChild("pick_name"); - line_edit->setKeystrokeCallback(boost::bind(&LLPanelPickEdit::onPickChanged, this, _1), NULL); - - LLTextEditor* text_edit = getChild("pick_desc"); - text_edit->setKeystrokeCallback(boost::bind(&LLPanelPickEdit::onPickChanged, this, _1)); - - childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPickEdit::onClickSave, this)); - childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPickEdit::onClickSetLocation, this)); - - initTexturePickerMouseEvents(); - - return TRUE; -} - -void LLPanelPickEdit::setSaveCallback(const commit_callback_t& cb) -{ - getChild("save_changes_btn")->setClickedCallback(cb); -} - -void LLPanelPickEdit::setCancelCallback(const commit_callback_t& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -void LLPanelPickEdit::resetDirty() -{ - LLPanelPickInfo::resetDirty(); - - getChild("pick_name")->resetDirty(); - getChild("pick_desc")->resetDirty(); - mSnapshotCtrl->resetDirty(); - mLocationChanged = false; -} - -BOOL LLPanelPickEdit::isDirty() const -{ - if( mNewPick - || LLPanelPickInfo::isDirty() - || mLocationChanged - || mSnapshotCtrl->isDirty() - || getChild("pick_name")->isDirty() - || getChild("pick_desc")->isDirty()) - { - return TRUE; - } - return FALSE; -} - -// PROTECTED AREA - -void LLPanelPickEdit::sendUpdate() -{ - LLPickData pick_data; - - // If we don't have a pick id yet, we'll need to generate one, - // otherwise we'll keep overwriting pick_id 00000 in the database. - if (getPickId().isNull()) - { - getPickId().generate(); - } - - pick_data.agent_id = gAgent.getID(); - pick_data.session_id = gAgent.getSessionID(); - pick_data.pick_id = getPickId(); - pick_data.creator_id = gAgent.getID();; - - //legacy var need to be deleted - pick_data.top_pick = FALSE; - pick_data.parcel_id = mParcelId; - pick_data.name = getChild(XML_NAME)->getValue().asString(); - pick_data.desc = getChild(XML_DESC)->getValue().asString(); - pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); - pick_data.pos_global = getPosGlobal(); - pick_data.sort_order = 0; - pick_data.enabled = TRUE; - - LLAvatarPropertiesProcessor::instance().sendPickInfoUpdate(&pick_data); - - if(mNewPick) - { - // Assume a successful create pick operation, make new number of picks - // available immediately. Actual number of picks will be requested in - // LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond. - LLAgentPicksInfo::getInstance()->incrementNumberOfPicks(); - } -} - -void LLPanelPickEdit::onSnapshotChanged() -{ - enableSaveButton(true); -} - -void LLPanelPickEdit::onPickChanged(LLUICtrl* ctrl) -{ - enableSaveButton(isDirty()); -} - -void LLPanelPickEdit::resetData() -{ - LLPanelPickInfo::resetData(); - mLocationChanged = false; -} - -void LLPanelPickEdit::enableSaveButton(bool enable) -{ - getChildView(XML_BTN_SAVE)->setEnabled(enable); -} - -void LLPanelPickEdit::onClickSetLocation() -{ - // Save location for later use. - setPosGlobal(gAgent.getPositionGlobal()); - - std::string parcel_name, region_name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (parcel) - { - mParcelId = parcel->getID(); - parcel_name = parcel->getName(); - } - - LLViewerRegion* region = gAgent.getRegion(); - if(region) - { - region_name = region->getName(); - } - - setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal())); - - mLocationChanged = true; - enableSaveButton(TRUE); -} - -void LLPanelPickEdit::onClickSave() -{ - sendUpdate(); - - mLocationChanged = false; - - LLSD params; - params["action"] = "save_new_pick"; - notifyParent(params); -} - -std::string LLPanelPickEdit::getLocationNotice() -{ - static std::string notice = getString("location_notice"); - return notice; -} - -void LLPanelPickEdit::processProperties(void* data, EAvatarProcessorType type) -{ - if(mNeedData) - { - LLPanelPickInfo::processProperties(data, type); - } -} - -// PRIVATE AREA - -void LLPanelPickEdit::initTexturePickerMouseEvents() -{ - text_icon = getChild(XML_BTN_ON_TXTR); - mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelPickEdit::onTexturePickerMouseEnter, this, _1)); - mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelPickEdit::onTexturePickerMouseLeave, this, _1)); - - text_icon->setVisible(FALSE); -} - -void LLPanelPickEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl) -{ - text_icon->setVisible(TRUE); -} - -void LLPanelPickEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) -{ - text_icon->setVisible(FALSE); -} diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h deleted file mode 100644 index 7a8bd66fcf..0000000000 --- a/indra/newview/llpanelpick.h +++ /dev/null @@ -1,264 +0,0 @@ -/** - * @file llpanelpick.h - * @brief LLPanelPick class definition - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Display of a "Top Pick" used both for the global top picks in the -// Find directory, and also for each individual user's picks in their -// profile. - -#ifndef LL_LLPANELPICK_H -#define LL_LLPANELPICK_H - -#include "llpanel.h" -#include "llremoteparcelrequest.h" -#include "llavatarpropertiesprocessor.h" - -class LLIconCtrl; -class LLTextureCtrl; -class LLScrollContainer; -class LLMessageSystem; -class LLAvatarPropertiesObserver; - -/** - * Panel for displaying Pick Information - snapshot, name, description, etc. - */ -class LLPanelPickInfo : public LLPanel, public LLAvatarPropertiesObserver, LLRemoteParcelInfoObserver -{ - LOG_CLASS(LLPanelPickInfo); -public: - - // Creates new panel - static LLPanelPickInfo* create(); - - virtual ~LLPanelPickInfo(); - - /** - * Initializes panel properties - * - * By default Pick will be created for current Agent location. - * Use setPickData to change Pick properties. - */ - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /** - * Sends remote parcel info request to resolve parcel name from its ID. - */ - void sendParcelInfoRequest(); - - /** - * Sets "Back" button click callback - */ - virtual void setExitCallback(const commit_callback_t& cb); - - /** - * Sets "Edit" button click callback - */ - virtual void setEditPickCallback(const commit_callback_t& cb); - - //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing - /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); - /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } - /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; - -protected: - - LLPanelPickInfo(); - - /** - * Resets Pick information - */ - virtual void resetData(); - - /** - * Resets UI controls (visibility, values) - */ - virtual void resetControls(); - - /** - * "Location text" is actually the owner name, the original - * name that owner gave the parcel, and the location. - */ - static std::string createLocationText( - const std::string& owner_name, - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global); - - virtual void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } - virtual LLUUID& getAvatarId() { return mAvatarId; } - - /** - * Sets snapshot id. - * - * Will mark snapshot control as valid if id is not null. - * Will mark snapshot control as invalid if id is null. If null id is a valid value, - * you have to manually mark snapshot is valid. - */ - virtual void setSnapshotId(const LLUUID& id); - - virtual void setPickId(const LLUUID& id) { mPickId = id; } - virtual LLUUID& getPickId() { return mPickId; } - - virtual void setPickName(const std::string& name); - - virtual void setPickDesc(const std::string& desc); - - virtual void setPickLocation(const std::string& location); - - virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - virtual LLVector3d& getPosGlobal() { return mPosGlobal; } - - /** - * Callback for "Map" button, opens Map - */ - void onClickMap(); - - /** - * Callback for "Teleport" button, teleports user to Pick location. - */ - void onClickTeleport(); - - void onClickBack(); - -protected: - - S32 mScrollingPanelMinHeight; - S32 mScrollingPanelWidth; - LLScrollContainer* mScrollContainer; - LLPanel* mScrollingPanel; - LLTextureCtrl* mSnapshotCtrl; - - LLUUID mAvatarId; - LLVector3d mPosGlobal; - LLUUID mParcelId; - LLUUID mPickId; - LLUUID mRequestedId; -}; - -/** - * Panel for creating/editing Pick. - */ -class LLPanelPickEdit : public LLPanelPickInfo -{ - LOG_CLASS(LLPanelPickEdit); -public: - - /** - * Creates new panel - */ - static LLPanelPickEdit* create(); - - /*virtual*/ ~LLPanelPickEdit(); - - /*virtual*/ void onOpen(const LLSD& key); - - virtual void setPickData(const LLPickData* pick_data); - - /*virtual*/ BOOL postBuild(); - - /** - * Sets "Save" button click callback - */ - virtual void setSaveCallback(const commit_callback_t& cb); - - /** - * Sets "Cancel" button click callback - */ - virtual void setCancelCallback(const commit_callback_t& cb); - - /** - * Resets panel and all cantrols to unedited state - */ - /*virtual*/ void resetDirty(); - - /** - * Returns true if any of Pick properties was changed by user. - */ - /*virtual*/ BOOL isDirty() const; - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - -protected: - - LLPanelPickEdit(); - - /** - * Sends Pick properties to server. - */ - void sendUpdate(); - - /** - * Called when snapshot image changes. - */ - void onSnapshotChanged(); - - /** - * Callback for Pick snapshot, name and description changed event. - */ - void onPickChanged(LLUICtrl* ctrl); - - /*virtual*/ void resetData(); - - /** - * Enables/disables "Save" button - */ - void enableSaveButton(bool enable); - - /** - * Callback for "Set Location" button click - */ - void onClickSetLocation(); - - /** - * Callback for "Save" button click - */ - void onClickSave(); - - std::string getLocationNotice(); - -protected: - - bool mLocationChanged; - bool mNeedData; - bool mNewPick; - -private: - - void initTexturePickerMouseEvents(); - void onTexturePickerMouseEnter(LLUICtrl* ctrl); - void onTexturePickerMouseLeave(LLUICtrl* ctrl); - -private: - - LLIconCtrl* text_icon; -}; - -#endif // LL_LLPANELPICK_H diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp deleted file mode 100644 index f20c5a7b80..0000000000 --- a/indra/newview/llpanelpicks.cpp +++ /dev/null @@ -1,1517 +0,0 @@ -/** - * @file llpanelpicks.cpp - * @brief LLPanelPicks and related class implementations - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelpicks.h" - -#include "llagent.h" -#include "llagentpicksinfo.h" -#include "llcommandhandler.h" -#include "lldispatcher.h" -#include "llflatlistview.h" -#include "llfloaterreg.h" -#include "llfloatersidepanelcontainer.h" -#include "llfloaterworldmap.h" -#include "llnotificationsutil.h" -#include "llstartup.h" -#include "lltexturectrl.h" -#include "lltoggleablemenu.h" -#include "lltrans.h" -#include "llviewergenericmessage.h" // send_generic_message -#include "llmenugl.h" -#include "llviewermenu.h" -#include "llregistry.h" - -#include "llaccordionctrl.h" -#include "llaccordionctrltab.h" -#include "llavatarpropertiesprocessor.h" -#include "llfloatersidepanelcontainer.h" -#include "llpanelavatar.h" -#include "llpanelprofile.h" -#include "llpanelpick.h" -#include "llpanelclassified.h" - -#include "rlvhandler.h" - -static const std::string XML_BTN_NEW = "new_btn"; -static const std::string XML_BTN_DELETE = "trash_btn"; -static const std::string XML_BTN_INFO = "info_btn"; -static const std::string XML_BTN_TELEPORT = "teleport_btn"; -static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; - -static const std::string PICK_ID("pick_id"); -static const std::string PICK_CREATOR_ID("pick_creator_id"); -static const std::string PICK_NAME("pick_name"); - -static const std::string CLASSIFIED_ID("classified_id"); -static const std::string CLASSIFIED_NAME("classified_name"); - - -static LLPanelInjector t_panel_picks("panel_picks"); - - -class LLPickHandler : public LLCommandHandler, - public LLAvatarPropertiesObserver -{ -public: - - std::set mPickIds; - - // requires trusted browser to trigger - LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } - - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) - { - if (LLStartUp::getStartupState() < STATE_STARTED) - { - return true; - } - - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks")) - { - LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - // handle app/classified/create urls first - if (params.size() == 1 && params[0].asString() == "create") - { - createPick(); - return true; - } - - // then handle the general app/pick/{UUID}/{CMD} urls - if (params.size() < 2) - { - return false; - } - - // get the ID for the pick_id - LLUUID pick_id; - if (!pick_id.set(params[0], FALSE)) - { - return false; - } - - // edit the pick in the side tray. - // need to ask the server for more info first though... - const std::string verb = params[1].asString(); - if (verb == "edit") - { - mPickIds.insert(pick_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(gAgent.getID(),pick_id); - return true; - } - else - { - LL_WARNS() << "unknown verb " << verb << LL_ENDL; - return false; - } - } - - void createPick() - { - // FIRE-7694 / BUG-932 / MAINT-1999 - if (LLAgentPicksInfo::getInstance()->isPickLimitReached()) - { - LLNotificationsUtil::add("PickLimitReached"); - return; - } - // - - // open the new pick panel on the Picks floater - LLFloater* picks_floater = LLFloaterReg::showInstance("picks"); - - LLPanelPicks* picks = picks_floater->findChild("panel_picks"); - if (picks) - { - picks->createNewPick(); - } - } - - void editPick(LLPickData* pick_info) - { - LLSD params; - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "edit_pick"; - params["pick_id"] = pick_info->pick_id; - params["avatar_id"] = pick_info->creator_id; - params["snapshot_id"] = pick_info->snapshot_id; - params["pick_name"] = pick_info->name; - params["pick_desc"] = pick_info->desc; - LLFloaterSidePanelContainer::showPanel("picks", params); - } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type) - { - if (APT_PICK_INFO != type) - { - return; - } - - // is this the pick that we asked for? - LLPickData* pick_info = static_cast(data); - if (!pick_info || mPickIds.find(pick_info->pick_id) == mPickIds.end()) - { - return; - } - - // open the edit side tray for this pick - if (pick_info->creator_id == gAgent.getID()) - { - editPick(pick_info); - } - else - { - LL_WARNS() << "Can't edit a pick you did not create" << LL_ENDL; - } - - // remove our observer now that we're done - mPickIds.erase(pick_info->pick_id); - LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); - } -}; - -LLPickHandler gPickHandler; - -class LLClassifiedHandler : - public LLCommandHandler, - public LLAvatarPropertiesObserver -{ -public: - // throttle calls from untrusted browsers - LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {} - - std::set mClassifiedIds; - - std::string mRequestVerb; - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) - { - if (LLStartUp::getStartupState() < STATE_STARTED) - { - return true; - } - - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds")) - { - LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - // handle app/classified/create urls first - if (params.size() == 1 && params[0].asString() == "create") - { - createClassified(); - return true; - } - - // then handle the general app/classified/{UUID}/{CMD} urls - if (params.size() < 2) - { - return false; - } - - // get the ID for the classified - LLUUID classified_id; - if (!classified_id.set(params[0], FALSE)) - { - return false; - } - - // show the classified in the side tray. - // need to ask the server for more info first though... - const std::string verb = params[1].asString(); - if (verb == "about") - { - mRequestVerb = verb; - mClassifiedIds.insert(classified_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); - return true; - } - else if (verb == "edit") - { - mRequestVerb = verb; - mClassifiedIds.insert(classified_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); - return true; - } - - return false; - } - - void createClassified() - { - // open the new classified panel on the Picks floater - LLFloater* picks_floater = LLFloaterReg::showInstance("picks"); - - LLPanelPicks* picks = picks_floater->findChild("panel_picks"); - if (picks) - { - picks->createNewClassified(); - } - } - - void openClassified(LLAvatarClassifiedInfo* c_info) - { - if (mRequestVerb == "about") - { - // open the classified info panel on the Me > Picks sidetray - LLSD params; - params["id"] = c_info->creator_id; - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "classified_details"; - params["classified_id"] = c_info->classified_id; - params["classified_creator_id"] = c_info->creator_id; - params["classified_snapshot_id"] = c_info->snapshot_id; - params["classified_name"] = c_info->name; - params["classified_desc"] = c_info->description; - params["from_search"] = true; - LLFloaterSidePanelContainer::showPanel("picks", params); - } - else if (mRequestVerb == "edit") - { - if (c_info->creator_id == gAgent.getID()) - { - LL_WARNS() << "edit in progress" << LL_ENDL; - // open the new classified panel on the Me > Picks sidetray - LLSD params; - params["id"] = gAgent.getID(); - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "edit_classified"; - params["classified_id"] = c_info->classified_id; - LLFloaterSidePanelContainer::showPanel("my_profile", params); - } - else - { - LL_WARNS() << "Can't edit a classified you did not create" << LL_ENDL; - } - } - } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type) - { - if (APT_CLASSIFIED_INFO != type) - { - return; - } - - // is this the classified that we asked for? - LLAvatarClassifiedInfo* c_info = static_cast(data); - if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end()) - { - return; - } - - // open the detail side tray for this classified - openClassified(c_info); - - // remove our observer now that we're done - mClassifiedIds.erase(c_info->classified_id); - LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); - } - -}; -LLClassifiedHandler gClassifiedHandler; - -////////////////////////////////////////////////////////////////////////// - - -//----------------------------------------------------------------------------- -// LLPanelPicks -//----------------------------------------------------------------------------- -LLPanelPicks::LLPanelPicks() -: LLPanelProfileTab(), - mPopupMenu(NULL), - mProfilePanel(NULL), - mPickPanel(NULL), - mPicksList(NULL), - mClassifiedsList(NULL), - mPanelPickInfo(NULL), - mPanelPickEdit(NULL), - mPlusMenu(NULL), - mPicksAccTab(NULL), - mClassifiedsAccTab(NULL), - mPanelClassifiedInfo(NULL), - mNoClassifieds(false), - mNoPicks(false), - mRlvBehaviorCallbackConnection() // FIRE-15556: Picks can circumvent RLVa @showloc restriction -{ -} - -LLPanelPicks::~LLPanelPicks() -{ - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } - - // FIRE-15556: Picks can circumvent RLVa @showloc restriction - if (mRlvBehaviorCallbackConnection.connected()) - { - mRlvBehaviorCallbackConnection.disconnect(); - } - // -} - -void* LLPanelPicks::create(void* data /* = NULL */) -{ - return new LLPanelPicks(); -} - -void LLPanelPicks::updateData() -{ - // Send Picks request only when we need to, not on every onOpen(during tab switch). - if(isDirty()) - { - mNoPicks = false; - mNoClassifieds = false; - - mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); - mNoItemsLabel->setVisible(TRUE); - - mPicksList->clear(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(getAvatarId()); - - mClassifiedsList->clear(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(getAvatarId()); - } -} - -void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_PICKS == type) - { - LLAvatarPicks* avatar_picks = static_cast(data); - if(avatar_picks && getAvatarId() == avatar_picks->target_id) - { - LLAvatarName av_name; - LLAvatarNameCache::get(getAvatarId(), &av_name); - getChild("pick_title")->setTextArg("[NAME]", av_name.getUserName()); - - // Save selection, to be able to edit same item after saving changes. See EXT-3023. - LLUUID selected_id = mPicksList->getSelectedValue()[PICK_ID]; - - mPicksList->clear(); - - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); - for(; avatar_picks->picks_list.end() != it; ++it) - { - LLUUID pick_id = it->first; - std::string pick_name = it->second; - - LLPickItem* picture = LLPickItem::create(); - picture->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - picture->setPickName(pick_name); - picture->setPickId(pick_id); - picture->setCreatorId(getAvatarId()); - - LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture); - picture->update(); - - LLSD pick_value = LLSD(); - pick_value.insert(PICK_ID, pick_id); - pick_value.insert(PICK_NAME, pick_name); - pick_value.insert(PICK_CREATOR_ID, getAvatarId()); - - mPicksList->addItem(picture, pick_value); - - // Restore selection by item id. - if ( pick_id == selected_id ) - mPicksList->selectItemByValue(pick_value); - - picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickPickItem, this, _1)); - picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - } - - showAccordion("tab_picks", mPicksList->size()); - - resetDirty(); - updateButtons(); - } - - mNoPicks = !mPicksList->size(); - } - else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type)) - { - LLAvatarClassifieds* c_info = static_cast(data); - if(c_info && getAvatarId() == c_info->target_id) - { - // do not clear classified list in case we will receive two or more data packets. - // list has been cleared in updateData(). (fix for EXT-6436) - - LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin(); - for(; c_info->classifieds_list.end() != it; ++it) - { - LLAvatarClassifieds::classified_data c_data = *it; - - LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), c_data.classified_id); - c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - c_item->setClassifiedName(c_data.name); - - LLSD pick_value = LLSD(); - pick_value.insert(CLASSIFIED_ID, c_data.classified_id); - pick_value.insert(CLASSIFIED_NAME, c_data.name); - - if (!findClassifiedById(c_data.classified_id)) - { - mClassifiedsList->addItem(c_item, pick_value); - } - - c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - } - - showAccordion("tab_classifieds", mClassifiedsList->size()); - - resetDirty(); - updateButtons(); - } - - mNoClassifieds = !mClassifiedsList->size(); - } - - updateNoItemsLabel(); -} - -LLPickItem* LLPanelPicks::getSelectedPickItem() -{ - LLPanel* selected_item = mPicksList->getSelectedItem(); - if (!selected_item) return NULL; - - return dynamic_cast(selected_item); -} - -LLClassifiedItem* LLPanelPicks::getSelectedClassifiedItem() -{ - LLPanel* selected_item = mClassifiedsList->getSelectedItem(); - if (!selected_item) - { - return NULL; - } - return dynamic_cast(selected_item); -} - -BOOL LLPanelPicks::postBuild() -{ - mPicksList = getChild("picks_list"); - mClassifiedsList = getChild("classifieds_list"); - - mPicksList->setCommitOnSelectionChange(true); - mClassifiedsList->setCommitOnSelectionChange(true); - - mPicksList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mPicksList)); - mClassifiedsList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mClassifiedsList)); - - mPicksList->setNoItemsCommentText(getString("no_picks")); - mClassifiedsList->setNoItemsCommentText(getString("no_classifieds")); - - mNoItemsLabel = getChild("picks_panel_text"); - - childSetAction(XML_BTN_NEW, boost::bind(&LLPanelPicks::onClickPlusBtn, this)); - childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this)); - childSetAction(XML_BTN_TELEPORT, boost::bind(&LLPanelPicks::onClickTeleport, this)); - childSetAction(XML_BTN_SHOW_ON_MAP, boost::bind(&LLPanelPicks::onClickMap, this)); - childSetAction(XML_BTN_INFO, boost::bind(&LLPanelPicks::onClickInfo, this)); - - mPicksAccTab = getChild("tab_picks"); - mPicksAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mPicksAccTab)); - mPicksAccTab->setDisplayChildren(true); - - mClassifiedsAccTab = getChild("tab_classifieds"); - mClassifiedsAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mClassifiedsAccTab)); - mClassifiedsAccTab->setDisplayChildren(false); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; - registar.add("Pick.Info", boost::bind(&LLPanelPicks::onClickInfo, this)); - registar.add("Pick.Edit", boost::bind(&LLPanelPicks::onClickMenuEdit, this)); - registar.add("Pick.Teleport", boost::bind(&LLPanelPicks::onClickTeleport, this)); - registar.add("Pick.Map", boost::bind(&LLPanelPicks::onClickMap, this)); - registar.add("Pick.Delete", boost::bind(&LLPanelPicks::onClickDelete, this)); - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registar; - enable_registar.add("Pick.Enable", boost::bind(&LLPanelPicks::onEnableMenuItem, this, _2)); - - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_picks.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar plus_registar; - plus_registar.add("Picks.Plus.Action", boost::bind(&LLPanelPicks::onPlusMenuItemClicked, this, _2)); - mEnableCallbackRegistrar.add("Picks.Plus.Enable", boost::bind(&LLPanelPicks::isActionEnabled, this, _2)); - mPlusMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_picks_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - // FIRE-15556: Picks can circumvent RLVa @showloc restriction - mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&LLPanelPicks::updateRlvRestrictions, this, _1, _2)); - childSetEnabled(XML_BTN_NEW, !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); - // - - return TRUE; -} - -void LLPanelPicks::onPlusMenuItemClicked(const LLSD& param) -{ - std::string value = param.asString(); - - if("new_pick" == value) - { - createNewPick(); - } - else if("new_classified" == value) - { - createNewClassified(); - } -} - -bool LLPanelPicks::isActionEnabled(const LLSD& userdata) const -{ - std::string command_name = userdata.asString(); - - if (command_name == "new_pick" && LLAgentPicksInfo::getInstance()->isPickLimitReached()) - { - return false; - } - - return true; -} - -bool LLPanelPicks::isClassifiedPublished(LLClassifiedItem* c_item) -{ - if(c_item) - { - LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if(panel) - { - return !panel->isNewWithErrors(); - } - - // we've got this classified from server - it's published - return true; - } - return false; -} - -void LLPanelPicks::onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab) -{ - if(!mPicksAccTab->getDisplayChildren()) - { - mPicksList->resetSelection(true); - } - if(!mClassifiedsAccTab->getDisplayChildren()) - { - mClassifiedsList->resetSelection(true); - } - - updateButtons(); -} - -void LLPanelPicks::onOpen(const LLSD& key) -{ - const LLUUID id(key.asUUID()); - BOOL self = (gAgent.getID() == id); - - // only agent can edit her picks - getChildView("edit_panel")->setEnabled(self); - getChildView("edit_panel")->setVisible( self); - - // Disable buttons when viewing profile for first time - if(getAvatarId() != id) - { - getChildView(XML_BTN_INFO)->setEnabled(FALSE); - getChildView(XML_BTN_TELEPORT)->setEnabled(FALSE); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(FALSE); - } - - // and see a special title - set as invisible by default in xml file - if (self) - { - getChildView("pick_title")->setVisible( !self); - getChildView("pick_title_agent")->setVisible( self); - - mPopupMenu->setItemVisible("pick_delete", TRUE); - mPopupMenu->setItemVisible("pick_edit", TRUE); - mPopupMenu->setItemVisible("pick_separator", TRUE); - } - - if(getAvatarId() != id) - { - showAccordion("tab_picks", false); - showAccordion("tab_classifieds", false); - - mPicksList->goToTop(); - // Set dummy value to make panel dirty and make it reload picks - setValue(LLSD()); - } - - LLPanelProfileTab::onOpen(key); -} - -void LLPanelPicks::onClosePanel() -{ - if (mPanelClassifiedInfo) - { - onPanelClassifiedClose(mPanelClassifiedInfo); - } - if (mPanelPickInfo) - { - onPanelPickClose(mPanelPickInfo); - } -} - -void LLPanelPicks::onListCommit(const LLFlatListView* f_list) -{ - // Make sure only one of the lists has selection. - if(f_list == mPicksList) - { - mClassifiedsList->resetSelection(true); - } - else if(f_list == mClassifiedsList) - { - mPicksList->resetSelection(true); - } - else - { - LL_WARNS() << "Unknown list" << LL_ENDL; - } - - updateButtons(); -} - -//static -void LLPanelPicks::onClickDelete() -{ - LLSD value = mPicksList->getSelectedValue(); - if (value.isDefined()) - { - LLSD args; - args["PICK"] = value[PICK_NAME]; - LLNotificationsUtil::add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeletePick, this, _1, _2)); - return; - } - - value = mClassifiedsList->getSelectedValue(); - if(value.isDefined()) - { - LLSD args; - args["NAME"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeleteClassified, this, _1, _2)); - return; - } -} - -bool LLPanelPicks::callbackDeletePick(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLSD pick_value = mPicksList->getSelectedValue(); - - if (0 == option) - { - LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); - mPicksList->removeItemByValue(pick_value); - - mNoPicks = !mPicksList->size(); - if (mNoPicks) - { - showAccordion("tab_picks", false); - } - updateNoItemsLabel(); - } - updateButtons(); - return false; -} - -bool LLPanelPicks::callbackDeleteClassified(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLSD value = mClassifiedsList->getSelectedValue(); - - if (0 == option) - { - LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]); - mClassifiedsList->removeItemByValue(value); - - mNoClassifieds = !mClassifiedsList->size(); - if (mNoClassifieds) - { - showAccordion("tab_classifieds", false); - } - updateNoItemsLabel(); - } - updateButtons(); - return false; -} - -bool LLPanelPicks::callbackTeleport( const LLSD& notification, const LLSD& response ) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - onClickTeleport(); - } - return false; -} - -//static -void LLPanelPicks::onClickTeleport() -{ - LLPickItem* pick_item = getSelectedPickItem(); - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if(pick_item) - pos = pick_item->getPosGlobal(); - else if(c_item) - { - pos = c_item->getPosGlobal(); - LLPanelClassifiedInfo::sendClickMessage("teleport", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - } - - if (!pos.isExactlyZero()) - { - gAgent.teleportViaLocation(pos); - LLFloaterWorldMap::getInstance()->trackLocation(pos); - } -} - -//static -void LLPanelPicks::onClickMap() -{ - LLPickItem* pick_item = getSelectedPickItem(); - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if (pick_item) - pos = pick_item->getPosGlobal(); - else if(c_item) - { - LLPanelClassifiedInfo::sendClickMessage("map", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - pos = c_item->getPosGlobal(); - } - - LLFloaterWorldMap::getInstance()->trackLocation(pos); - LLFloaterReg::showInstance("world_map", "center"); -} - - -void LLPanelPicks::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask) -{ - updateButtons(); - - if (mPopupMenu) - { - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - ((LLContextMenu*)mPopupMenu)->show(x, y); - LLMenuGL::showPopup(item, mPopupMenu, x, y); - } -} - -void LLPanelPicks::onDoubleClickPickItem(LLUICtrl* item) -{ - LLSD pick_value = mPicksList->getSelectedValue(); - if (pick_value.isUndefined()) return; - - LLSD args; - args["PICK"] = pick_value[PICK_NAME]; - LLNotificationsUtil::add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); -} - -void LLPanelPicks::onDoubleClickClassifiedItem(LLUICtrl* item) -{ - LLSD value = mClassifiedsList->getSelectedValue(); - if (value.isUndefined()) return; - - LLSD args; - args["CLASSIFIED"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("TeleportToClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); -} - -void LLPanelPicks::updateButtons() -{ - bool has_selected = mPicksList->numSelected() > 0 || mClassifiedsList->numSelected() > 0; - - if (getAvatarId() == gAgentID) - { - getChildView(XML_BTN_DELETE)->setEnabled(has_selected); - } - - getChildView(XML_BTN_INFO)->setEnabled(has_selected); - getChildView(XML_BTN_TELEPORT)->setEnabled(has_selected); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(has_selected); - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if(c_item) - { - getChildView(XML_BTN_INFO)->setEnabled(isClassifiedPublished(c_item)); - } -} - -void LLPanelPicks::updateNoItemsLabel() -{ - bool no_data = mNoPicks && mNoClassifieds; - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if (getAvatarId() == gAgentID) - { - mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); - } - } -} - -void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) -{ - mProfilePanel = profile_panel; -} - - -void LLPanelPicks::buildPickPanel() -{ -// if (mPickPanel == NULL) -// { -// mPickPanel = new LLPanelPick(); -// mPickPanel->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, NULL)); -// } -} - -void LLPanelPicks::onClickPlusBtn() -{ - LLRect rect(getChildView(XML_BTN_NEW)->getRect()); - - mPlusMenu->updateParent(LLMenuGL::sMenuContainer); - mPlusMenu->setButtonRect(rect, this); - LLMenuGL::showPopup(this, mPlusMenu, rect.mLeft, rect.mTop); -} - -void LLPanelPicks::createNewPick() -{ - createPickEditPanel(); - - getProfilePanel()->openPanel(mPanelPickEdit, LLSD()); -} - -void LLPanelPicks::createNewClassified() -{ - LLPanelClassifiedEdit* panel = NULL; - createClassifiedEditPanel(&panel); - - getProfilePanel()->openPanel(panel, LLSD()); -} - -void LLPanelPicks::onClickInfo() -{ - if(mPicksList->numSelected() > 0) - { - openPickInfo(); - } - else if(mClassifiedsList->numSelected() > 0) - { - openClassifiedInfo(); - } -} - -void LLPanelPicks::openPickInfo() -{ - LLSD selected_value = mPicksList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLPickItem* pick = (LLPickItem*)mPicksList->getSelectedItem(); - - createPickInfoPanel(); - - LLSD params; - params["pick_id"] = pick->getPickId(); - params["avatar_id"] = pick->getCreatorId(); - params["snapshot_id"] = pick->getSnapshotId(); - params["pick_name"] = pick->getPickName(); - params["pick_desc"] = pick->getPickDesc(); - - getProfilePanel()->openPanel(mPanelPickInfo, params); -} - -void LLPanelPicks::openClassifiedInfo() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["classified_snapshot_id"] = c_item->getSnapshotId(); - params["classified_name"] = c_item->getClassifiedName(); - params["classified_desc"] = c_item->getDescription(); - params["from_search"] = false; - - openClassifiedInfo(params); -} - -void LLPanelPicks::openClassifiedInfo(const LLSD ¶ms) -{ - createClassifiedInfoPanel(); - getProfilePanel()->openPanel(mPanelClassifiedInfo, params); -} - -void LLPanelPicks::openClassifiedEdit(const LLSD& params) -{ - LLUUID classified_id = params["classified_id"].asUUID();; - LL_INFOS() << "opening classified " << classified_id << " for edit" << LL_ENDL; - editClassified(classified_id); -} - -void LLPanelPicks::showAccordion(const std::string& name, bool show) -{ - LLAccordionCtrlTab* tab = getChild(name); - tab->setVisible(show); - LLAccordionCtrl* acc = getChild("accordion"); - acc->arrange(); -} - -void LLPanelPicks::onPanelPickClose(LLPanel* panel) -{ - getProfilePanel()->closePanel(panel); -} - -void LLPanelPicks::onPanelPickSave(LLPanel* panel) -{ - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::onPanelClassifiedSave(LLPanelClassifiedEdit* panel) -{ - if(!panel->canClose()) - { - return; - } - - if(panel->isNew()) - { - mEditClassifiedPanels[panel->getClassifiedId()] = panel; - - LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), panel->getClassifiedId()); - c_item->fillIn(panel); - - LLSD c_value; - c_value.insert(CLASSIFIED_ID, c_item->getClassifiedId()); - c_value.insert(CLASSIFIED_NAME, c_item->getClassifiedName()); - mClassifiedsList->addItem(c_item, c_value, ADD_TOP); - - c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - - // order does matter, showAccordion will invoke arrange for accordions. - mClassifiedsAccTab->changeOpenClose(false); - showAccordion("tab_classifieds", true); - } - else if(panel->isNewWithErrors()) - { - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (c_item) - { - c_item->fillIn(panel); - } - } - else - { - onPanelClassifiedClose(panel); - return; - } - - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::onPanelClassifiedClose(LLPanelClassifiedInfo* panel) -{ - if(panel->getInfoLoaded() && !panel->isDirty()) - { - std::vector values; - mClassifiedsList->getValues(values); - for(size_t n = 0; n < values.size(); ++n) - { - LLUUID c_id = values[n][CLASSIFIED_ID].asUUID(); - if(panel->getClassifiedId() == c_id) - { - LLClassifiedItem* c_item = dynamic_cast( - mClassifiedsList->getItemByValue(values[n])); - llassert(c_item); - if (c_item) - { - c_item->setClassifiedName(panel->getClassifiedName()); - c_item->setDescription(panel->getDescription()); - c_item->setSnapshotId(panel->getSnapshotId()); - } - } - } - } - - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::createPickInfoPanel() -{ - if(!mPanelPickInfo) - { - mPanelPickInfo = LLPanelPickInfo::create(); - mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo)); - mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this)); - mPanelPickInfo->setVisible(FALSE); - } -} - -void LLPanelPicks::createClassifiedInfoPanel() -{ - mPanelClassifiedInfo = LLPanelClassifiedInfo::create(); - mPanelClassifiedInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, mPanelClassifiedInfo)); - mPanelClassifiedInfo->setEditClassifiedCallback(boost::bind(&LLPanelPicks::onPanelClassifiedEdit, this)); - mPanelClassifiedInfo->setVisible(FALSE); -} - -void LLPanelPicks::createClassifiedEditPanel(LLPanelClassifiedEdit** panel) -{ - if(panel) - { - LLPanelClassifiedEdit* new_panel = LLPanelClassifiedEdit::create(); - new_panel->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel)); - new_panel->setSaveCallback(boost::bind(&LLPanelPicks::onPanelClassifiedSave, this, new_panel)); - new_panel->setCancelCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel)); - new_panel->setVisible(FALSE); - *panel = new_panel; - } -} - -void LLPanelPicks::createPickEditPanel() -{ - mPanelPickEdit = LLPanelPickEdit::create(); - mPanelPickEdit->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit)); - mPanelPickEdit->setSaveCallback(boost::bind(&LLPanelPicks::onPanelPickSave, this, mPanelPickEdit)); - mPanelPickEdit->setCancelCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit)); - mPanelPickEdit->setVisible(FALSE); -} - -// void LLPanelPicks::openPickEditPanel(LLPickItem* pick) -// { -// if(!pick) -// { -// return; -// } -// } - -// void LLPanelPicks::openPickInfoPanel(LLPickItem* pick) -// { -// if(!mPanelPickInfo) -// { -// mPanelPickInfo = LLPanelPickInfo::create(); -// mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo)); -// mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this)); -// mPanelPickInfo->setVisible(FALSE); -// } -// -// LLSD params; -// params["pick_id"] = pick->getPickId(); -// params["avatar_id"] = pick->getCreatorId(); -// params["snapshot_id"] = pick->getSnapshotId(); -// params["pick_name"] = pick->getPickName(); -// params["pick_desc"] = pick->getPickDesc(); -// -// getProfilePanel()->openPanel(mPanelPickInfo, params); -// } - -void LLPanelPicks::openPickEdit(const LLSD& params) -{ - createPickEditPanel(); - getProfilePanel()->openPanel(mPanelPickEdit, params); -} - -void LLPanelPicks::onPanelPickEdit() -{ - LLSD selected_value = mPicksList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLPickItem* pick = dynamic_cast(mPicksList->getSelectedItem()); - - createPickEditPanel(); - - LLSD params; - params["pick_id"] = pick->getPickId(); - params["avatar_id"] = pick->getCreatorId(); - params["snapshot_id"] = pick->getSnapshotId(); - params["pick_name"] = pick->getPickName(); - params["pick_desc"] = pick->getPickDesc(); - - getProfilePanel()->openPanel(mPanelPickEdit, params); -} - -void LLPanelPicks::onPanelClassifiedEdit() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) - { - return; - } - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (!c_item) - { - return; - } - editClassified(c_item->getClassifiedId()); -} - -LLClassifiedItem *LLPanelPicks::findClassifiedById(const LLUUID& classified_id) -{ - // HACK - find item by classified id. Should be a better way. - std::vector items; - mClassifiedsList->getItems(items); - LLClassifiedItem* c_item = NULL; - for(std::vector::iterator it = items.begin(); it != items.end(); ++it) - { - LLClassifiedItem *test_item = dynamic_cast(*it); - if (test_item && test_item->getClassifiedId() == classified_id) - { - c_item = test_item; - break; - } - } - return c_item; -} - -void LLPanelPicks::editClassified(const LLUUID& classified_id) -{ - LLClassifiedItem* c_item = findClassifiedById(classified_id); - if (!c_item) - { - LL_WARNS() << "item not found for classified_id " << classified_id << LL_ENDL; - return; - } - - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["snapshot_id"] = c_item->getSnapshotId(); - params["name"] = c_item->getClassifiedName(); - params["desc"] = c_item->getDescription(); - params["category"] = (S32)c_item->getCategory(); - params["content_type"] = (S32)c_item->getContentType(); - params["auto_renew"] = c_item->getAutoRenew(); - params["price_for_listing"] = c_item->getPriceForListing(); - params["location_text"] = c_item->getLocationText(); - - LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if(!panel) - { - createClassifiedEditPanel(&panel); - mEditClassifiedPanels[c_item->getClassifiedId()] = panel; - } - getProfilePanel()->openPanel(panel, params); - panel->setPosGlobal(c_item->getPosGlobal()); -} - -void LLPanelPicks::onClickMenuEdit() -{ - if(getSelectedPickItem()) - { - onPanelPickEdit(); - } - else if(getSelectedClassifiedItem()) - { - onPanelClassifiedEdit(); - } -} - -bool LLPanelPicks::onEnableMenuItem(const LLSD& user_data) -{ - std::string param = user_data.asString(); - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if(c_item && "info" == param) - { - // dont show Info panel if classified was not created - return isClassifiedPublished(c_item); - } - - return true; -} - -inline LLPanelProfile* LLPanelPicks::getProfilePanel() -{ - llassert_always(NULL != mProfilePanel); - return mProfilePanel; -} - -// FIRE-15556: Picks can circumvent RLVa @showloc restriction -void LLPanelPicks::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) -{ - if (behavior == RLV_BHVR_SHOWLOC) - { - childSetEnabled(XML_BTN_NEW, type != RLV_TYPE_ADD); - } -} -// - -//----------------------------------------------------------------------------- -// LLPanelPicks -//----------------------------------------------------------------------------- -LLPickItem::LLPickItem() -: LLPanel() -, mPickID(LLUUID::null) -, mCreatorID(LLUUID::null) -, mParcelID(LLUUID::null) -, mSnapshotID(LLUUID::null) -, mNeedData(true) -{ - buildFromFile("panel_pick_list_item.xml"); -} - -LLPickItem::~LLPickItem() -{ - if (mCreatorID.notNull()) - { - LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); - } - -} - -LLPickItem* LLPickItem::create() -{ - return new LLPickItem(); -} - -void LLPickItem::init(LLPickData* pick_data) -{ - setPickDesc(pick_data->desc); - setSnapshotId(pick_data->snapshot_id); - mPosGlobal = pick_data->pos_global; - mSimName = pick_data->sim_name; - mPickDescription = pick_data->desc; - mUserName = pick_data->user_name; - mOriginalName = pick_data->original_name; - - LLTextureCtrl* picture = getChild("picture"); - picture->setImageAssetID(pick_data->snapshot_id); -} - -void LLPickItem::setPickName(const std::string& name) -{ - mPickName = name; - getChild("picture_name")->setValue(name); - -} - -const std::string& LLPickItem::getPickName() -{ - return mPickName; -} - -const LLUUID& LLPickItem::getCreatorId() -{ - return mCreatorID; -} - -const LLUUID& LLPickItem::getSnapshotId() -{ - return mSnapshotID; -} - -void LLPickItem::setPickDesc(const std::string& descr) -{ - getChild("picture_descr")->setValue(descr); -} - -void LLPickItem::setPickId(const LLUUID& id) -{ - mPickID = id; -} - -const LLUUID& LLPickItem::getPickId() -{ - return mPickID; -} - -const LLVector3d& LLPickItem::getPosGlobal() -{ - return mPosGlobal; -} - -const std::string LLPickItem::getDescription() -{ - return getChild("picture_descr")->getValue().asString(); -} - -void LLPickItem::update() -{ - setNeedData(true); - LLAvatarPropertiesProcessor::instance().sendPickInfoRequest(mCreatorID, mPickID); -} - -void LLPickItem::processProperties(void *data, EAvatarProcessorType type) -{ - if (APT_PICK_INFO != type) - { - return; - } - - LLPickData* pick_data = static_cast(data); - if (!pick_data || mPickID != pick_data->pick_id) - { - return; - } - - init(pick_data); - setNeedData(false); - LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); -} - -void set_child_visible(LLView* parent, const std::string& child_name, bool visible) -{ - parent->getChildView(child_name)->setVisible(visible); -} - -BOOL LLPickItem::postBuild() -{ - setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true)); - setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false)); - return TRUE; -} - -void LLPickItem::setValue(const LLSD& value) -{ - if (!value.isMap()) return;; - if (!value.has("selected")) return; - getChildView("selected_icon")->setVisible( value["selected"]); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -LLClassifiedItem::LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id) - : LLPanel() - , mAvatarId(avatar_id) - , mClassifiedId(classified_id) -{ - buildFromFile("panel_classifieds_list_item.xml"); - - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); -} - -LLClassifiedItem::~LLClassifiedItem() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -void LLClassifiedItem::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO != type) - { - return; - } - - LLAvatarClassifiedInfo* c_info = static_cast(data); - if( !c_info || c_info->classified_id != getClassifiedId() ) - { - return; - } - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setPosGlobal(c_info->pos_global); - - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -BOOL LLClassifiedItem::postBuild() -{ - setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true)); - setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false)); - return TRUE; -} - -void LLClassifiedItem::setValue(const LLSD& value) -{ - if (!value.isMap()) return;; - if (!value.has("selected")) return; - getChildView("selected_icon")->setVisible( value["selected"]); -} - -void LLClassifiedItem::fillIn(LLPanelClassifiedEdit* panel) -{ - if(!panel) - { - return; - } - - setClassifiedName(panel->getClassifiedName()); - setDescription(panel->getDescription()); - setSnapshotId(panel->getSnapshotId()); - setCategory(panel->getCategory()); - setContentType(panel->getContentType()); - setAutoRenew(panel->getAutoRenew()); - setPriceForListing(panel->getPriceForListing()); - setPosGlobal(panel->getPosGlobal()); - setLocationText(panel->getClassifiedLocation()); -} - -void LLClassifiedItem::setClassifiedName(const std::string& name) -{ - getChild("name")->setValue(name); -} - -void LLClassifiedItem::setDescription(const std::string& desc) -{ - getChild("description")->setValue(desc); -} - -void LLClassifiedItem::setSnapshotId(const LLUUID& snapshot_id) -{ - getChild("picture")->setValue(snapshot_id); -} - -LLUUID LLClassifiedItem::getSnapshotId() -{ - return getChild("picture")->getValue(); -} - -//EOF diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h deleted file mode 100644 index 5b42cc4ae5..0000000000 --- a/indra/newview/llpanelpicks.h +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @file llpanelpicks.h - * @brief LLPanelPicks and related class definitions - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLPANELPICKS_H -#define LL_LLPANELPICKS_H - -#include "llpanel.h" -#include "v3dmath.h" -#include "lluuid.h" -#include "llavatarpropertiesprocessor.h" -#include "llpanelavatar.h" -#include "llregistry.h" -#include "rlvdefines.h" - -class LLAccordionCtrlTab; -class LLPanelProfile; -class LLMessageSystem; -class LLVector3d; -class LLPanelProfileTab; -class LLAgent; -class LLMenuGL; -class LLPickItem; -class LLClassifiedItem; -class LLFlatListView; -class LLPanelPickInfo; -class LLPanelPickEdit; -class LLToggleableMenu; -class LLPanelClassifiedInfo; -class LLPanelClassifiedEdit; - -// *TODO -// Panel Picks has been consolidated with Classifieds (EXT-2095), give LLPanelPicks -// and corresponding files (cpp, h, xml) a new name. (new name is TBD at the moment) - -class LLPanelPicks - : public LLPanelProfileTab -{ -public: - LLPanelPicks(); - ~LLPanelPicks(); - - static void* create(void* data); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void onClosePanel(); - - void processProperties(void* data, EAvatarProcessorType type); - - void updateData(); - - // returns the selected pick item - LLPickItem* getSelectedPickItem(); - LLClassifiedItem* getSelectedClassifiedItem(); - LLClassifiedItem* findClassifiedById(const LLUUID& classified_id); - - //*NOTE top down approch when panel toggling is done only by - // parent panels failed to work (picks related code was in my profile panel) - void setProfilePanel(LLPanelProfile* profile_panel); - - void createNewPick(); - void createNewClassified(); - -protected: - /*virtual*/void updateButtons(); - void updateNoItemsLabel(); - -private: - void onClickDelete(); - void onClickTeleport(); - void onClickMap(); - - void onPlusMenuItemClicked(const LLSD& param); - bool isActionEnabled(const LLSD& userdata) const; - - bool isClassifiedPublished(LLClassifiedItem* c_item); - - void onListCommit(const LLFlatListView* f_list); - void onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab); - - // FIRE-15556: Picks can circumvent RLVa @showloc restriction - boost::signals2::connection mRlvBehaviorCallbackConnection; - void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type); - // - - //------------------------------------------------ - // Callbacks which require panel toggling - //------------------------------------------------ - void onClickPlusBtn(); - void onClickInfo(); - void onPanelPickClose(LLPanel* panel); - void onPanelPickSave(LLPanel* panel); - void onPanelClassifiedSave(LLPanelClassifiedEdit* panel); - void onPanelClassifiedClose(LLPanelClassifiedInfo* panel); - void openPickEdit(const LLSD& params); - void onPanelPickEdit(); - void onPanelClassifiedEdit(); - void editClassified(const LLUUID& classified_id); - void onClickMenuEdit(); - - bool onEnableMenuItem(const LLSD& user_data); - - void openPickInfo(); - void openClassifiedInfo(); - void openClassifiedInfo(const LLSD& params); - void openClassifiedEdit(const LLSD& params); - friend class LLPanelProfile; - - void showAccordion(const std::string& name, bool show); - - void buildPickPanel(); - - bool callbackDeletePick(const LLSD& notification, const LLSD& response); - bool callbackDeleteClassified(const LLSD& notification, const LLSD& response); - bool callbackTeleport(const LLSD& notification, const LLSD& response); - - - virtual void onDoubleClickPickItem(LLUICtrl* item); - virtual void onDoubleClickClassifiedItem(LLUICtrl* item); - virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask); - - LLPanelProfile* getProfilePanel(); - - void createPickInfoPanel(); - void createPickEditPanel(); - void createClassifiedInfoPanel(); - void createClassifiedEditPanel(LLPanelClassifiedEdit** panel); - - LLMenuGL* mPopupMenu; - LLPanelProfile* mProfilePanel; - LLPanelPickInfo* mPickPanel; - LLFlatListView* mPicksList; - LLFlatListView* mClassifiedsList; - LLPanelPickInfo* mPanelPickInfo; - LLPanelClassifiedInfo* mPanelClassifiedInfo; - LLPanelPickEdit* mPanelPickEdit; - LLToggleableMenu* mPlusMenu; - LLUICtrl* mNoItemsLabel; - - // - typedef std::map panel_classified_edit_map_t; - - // This map is needed for newly created classifieds. The purpose of panel is to - // sit in this map and listen to LLPanelClassifiedEdit::processProperties callback. - panel_classified_edit_map_t mEditClassifiedPanels; - - LLAccordionCtrlTab* mPicksAccTab; - LLAccordionCtrlTab* mClassifiedsAccTab; - - //true if picks list is empty after processing picks - bool mNoPicks; - //true if classifieds list is empty after processing classifieds - bool mNoClassifieds; -}; - -class LLPickItem : public LLPanel, public LLAvatarPropertiesObserver -{ -public: - - LLPickItem(); - - static LLPickItem* create(); - - void init(LLPickData* pick_data); - - void setPickName(const std::string& name); - - void setPickDesc(const std::string& descr); - - void setPickId(const LLUUID& id); - - void setCreatorId(const LLUUID& id) {mCreatorID = id;}; - - void setSnapshotId(const LLUUID& id) {mSnapshotID = id;}; - - void setNeedData(bool need){mNeedData = need;}; - - const LLUUID& getPickId(); - - const std::string& getPickName(); - - const LLUUID& getCreatorId(); - - const LLUUID& getSnapshotId(); - - const LLVector3d& getPosGlobal(); - - const std::string getDescription(); - - const std::string& getSimName() { return mSimName; } - - const std::string& getUserName() { return mUserName; } - - const std::string& getOriginalName() { return mOriginalName; } - - const std::string& getPickDesc() { return mPickDescription; } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void update(); - - ~LLPickItem(); - - /*virtual*/ BOOL postBuild(); - - /** setting on/off background icon to indicate selected state */ - /*virtual*/ void setValue(const LLSD& value); - -protected: - - LLUUID mPickID; - LLUUID mCreatorID; - LLUUID mParcelID; - LLUUID mSnapshotID; - LLVector3d mPosGlobal; - bool mNeedData; - - std::string mPickName; - std::string mUserName; - std::string mOriginalName; - std::string mPickDescription; - std::string mSimName; -}; - -class LLClassifiedItem : public LLPanel, public LLAvatarPropertiesObserver -{ -public: - - LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id); - - virtual ~LLClassifiedItem(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void setValue(const LLSD& value); - - void fillIn(LLPanelClassifiedEdit* panel); - - LLUUID getAvatarId() {return mAvatarId;} - - void setAvatarId(const LLUUID& avatar_id) {mAvatarId = avatar_id;} - - LLUUID getClassifiedId() {return mClassifiedId;} - - void setClassifiedId(const LLUUID& classified_id) {mClassifiedId = classified_id;} - - void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - - const LLVector3d getPosGlobal() { return mPosGlobal; } - - void setLocationText(const std::string location) { mLocationText = location; } - - std::string getLocationText() { return mLocationText; } - - void setClassifiedName (const std::string& name); - - std::string getClassifiedName() { return getChild("name")->getValue().asString(); } - - void setDescription(const std::string& desc); - - std::string getDescription() { return getChild("description")->getValue().asString(); } - - void setSnapshotId(const LLUUID& snapshot_id); - - LLUUID getSnapshotId(); - - void setCategory(U32 cat) { mCategory = cat; } - - U32 getCategory() { return mCategory; } - - void setContentType(U32 ct) { mContentType = ct; } - - U32 getContentType() { return mContentType; } - - void setAutoRenew(U32 renew) { mAutoRenew = renew; } - - bool getAutoRenew() { return mAutoRenew; } - - void setPriceForListing(S32 price) { mPriceForListing = price; } - - S32 getPriceForListing() { return mPriceForListing; } - -private: - LLUUID mAvatarId; - LLUUID mClassifiedId; - LLVector3d mPosGlobal; - std::string mLocationText; - U32 mCategory; - U32 mContentType; - bool mAutoRenew; - S32 mPriceForListing; -}; - -#endif // LL_LLPANELPICKS_H diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index fb9eca1e7a..87ff5b17e3 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -27,6 +27,8 @@ #include "llviewerprecompiledheaders.h" #include "llpanelplaceinfo.h" +#include "llfloaterprofile.h" +#include "llfloaterreg.h" #include "llavatarname.h" #include "llsdutil.h" @@ -42,7 +44,6 @@ #include "llagent.h" #include "llexpandabletextbox.h" -#include "llpanelpick.h" #include "llslurl.h" #include "lltexturectrl.h" #include "llviewerregion.h" @@ -360,7 +361,7 @@ void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) } } -void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel) +void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global) { LLPickData data; data.pos_global = pos_global; @@ -369,7 +370,12 @@ void LLPanelPlaceInfo::createPick(const LLVector3d& pos_global, LLPanelPickEdit* data.desc = mDescEditor->getText(); data.snapshot_id = mSnapshotCtrl->getImageAssetID(); data.parcel_id = mParcelID; - pick_panel->setPickData(&data); + + LLFloaterProfile* profile_floater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", gAgentID))); + if (profile_floater) + { + profile_floater->createPick(data); + } } // static diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index fe9b26cbb9..d636ea3ce2 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -38,7 +38,6 @@ class LLAvatarName; class LLExpandableTextBox; class LLIconCtrl; class LLInventoryItem; -class LLPanelPickEdit; class LLParcel; class LLScrollContainer; class LLTextBox; @@ -99,7 +98,7 @@ public: // Create a pick for the location specified // by global_pos. - void createPick(const LLVector3d& pos_global, LLPanelPickEdit* pick_panel); + void createPick(const LLVector3d& pos_global); // FIRE-817: Separate place details floater void setHeaderVisible(BOOL visible); diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index fe9d87181f..ec953552f2 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -64,7 +64,6 @@ #include "lllayoutstack.h" #include "llpanellandmarkinfo.h" #include "llpanellandmarks.h" -#include "llpanelpick.h" #include "llpanelplaceprofile.h" #include "llpanelteleporthistory.h" #include "llremoteparcelrequest.h" @@ -251,7 +250,6 @@ LLPanelPlaces::LLPanelPlaces() mFilterEditor(NULL), mPlaceProfile(NULL), mLandmarkInfo(NULL), - mPickPanel(NULL), mItem(NULL), mPlaceMenu(NULL), mLandmarkMenu(NULL), @@ -1019,28 +1017,11 @@ void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) } else if (item == "pick") { - if (mPickPanel == NULL) - { - mPickPanel = LLPanelPickEdit::create(); - addChild(mPickPanel); - - mPickPanel->setExitCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); - mPickPanel->setCancelCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); - mPickPanel->setSaveCallback(boost::bind(&LLPanelPlaces::togglePickPanel, this, FALSE)); - } - - togglePickPanel(TRUE); - mPickPanel->onOpen(LLSD()); - LLPanelPlaceInfo* panel = getCurrentInfoPanel(); if (panel) { - panel->createPick(mPosGlobal, mPickPanel); + panel->createPick(mPosGlobal); } - - LLRect rect = getRect(); - mPickPanel->reshape(rect.getWidth(), rect.getHeight()); - mPickPanel->setRect(rect); } else if (item == "add_to_favbar") { @@ -1117,18 +1098,6 @@ bool LLPanelPlaces::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_t return false; } -void LLPanelPlaces::togglePickPanel(BOOL visible) -{ - if (mPickPanel) - { - mPickPanel->setVisible(visible); - // FIRE-31687: Place profile overlaps landmark panel in places floater when closing create pick panel - //mPlaceProfile->setVisible(!visible); - updateVerbs(); - } - -} - void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) { if (!mPlaceProfile || !mLandmarkInfo) @@ -1390,20 +1359,16 @@ void LLPanelPlaces::updateVerbs() bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; - bool is_pick_panel_visible = false; - if(mPickPanel) - { - is_pick_panel_visible = mPickPanel->isInVisibleChain(); - } + bool have_3d_pos = ! mPosGlobal.isExactlyZero(); - mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); - mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); + mTeleportBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); + mShowOnMapBtn->setVisible(!is_create_landmark_visible && !isLandmarkEditModeOn); mSaveBtn->setVisible(isLandmarkEditModeOn); mCancelBtn->setVisible(isLandmarkEditModeOn); mCloseBtn->setVisible(is_create_landmark_visible && !isLandmarkEditModeOn); // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater - mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn && !is_pick_panel_visible); + mPlaceInfoBtn->setVisible(!is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn); mShowOnMapBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP)); bool show_options_btn = is_place_info_visible && !is_create_landmark_visible && !isLandmarkEditModeOn; diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index f1e11bea9c..41e40797a5 100644 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -38,7 +38,6 @@ class LLLandmark; class LLPanelLandmarkInfo; class LLPanelPlaceProfile; -class LLPanelPickEdit; class LLPanelPlaceInfo; class LLPanelPlacesTab; class LLParcelSelection; @@ -102,7 +101,6 @@ private: void onOverflowButtonClicked(); void onOverflowMenuItemClicked(const LLSD& param); bool onOverflowMenuItemEnable(const LLSD& param); - void onCreateLandmarkButtonClicked(const LLUUID& folder_id); void onBackButtonClicked(); void onProfileButtonClicked(); // FIRE-31033: Keep Teleport/Map/Profile buttons on places floater void onGearMenuClick(); @@ -111,9 +109,6 @@ private: void onRemoveButtonClicked(); bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept); - - void toggleMediaPanel(); - void togglePickPanel(BOOL visible); void togglePlaceInfoPanel(BOOL visible); /*virtual*/ void onVisibilityChange(BOOL new_visibility); @@ -130,7 +125,6 @@ private: LLPanelPlaceProfile* mPlaceProfile; LLPanelLandmarkInfo* mLandmarkInfo; - LLPanelPickEdit* mPickPanel; LLToggleableMenu* mPlaceMenu; LLToggleableMenu* mLandmarkMenu; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 345ac191e3..e1f8fb3c69 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelprofile.cpp * @brief Profile panel implementation * -* $LicenseInfo:firstyear=2009&license=viewerlgpl$ +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* +* Copyright (C) 2022, Linden Research, Inc. +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,59 +27,434 @@ #include "llviewerprecompiledheaders.h" #include "llpanelprofile.h" -#include "llagent.h" -#include "llavataractions.h" -#include "llfloaterreg.h" -#include "llcommandhandler.h" -#include "llnotificationsutil.h" -#include "llpanelpicks.h" +// Common +#include "llavatarnamecache.h" +#include "llsdutil.h" +#include "llslurl.h" +#include "lldateutil.h" //ageFromDate + +// UI +#include "llavatariconctrl.h" +#include "llclipboard.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "lllineeditor.h" +#include "llloadingindicator.h" +#include "llmenubutton.h" #include "lltabcontainer.h" -#include "llviewercontrol.h" -#include "llviewernetwork.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltoggleablemenu.h" +#include "llgrouplist.h" +#include "llurlaction.h" + +// Image +#include "llimagej2c.h" + +// Newview +#include "llagent.h" //gAgent +#include "llagentpicksinfo.h" +#include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" +#include "llcommandhandler.h" +#include "llfloaterprofiletexture.h" +#include "llfloaterreg.h" +#include "llfilepicker.h" +#include "llfirstuse.h" +#include "llgroupactions.h" +#include "lllogchat.h" #include "llmutelist.h" +#include "llnotificationsutil.h" #include "llpanelblockedlist.h" +#include "llpanelprofileclassifieds.h" +#include "llpanelprofilepicks.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" //is_agent_mappable +#include "llviewermenufile.h" +#include "llviewertexturelist.h" +#include "llvoiceclient.h" #include "llweb.h" -static const std::string PANEL_PICKS = "panel_picks"; +#include "fsdata.h" +#include "llviewermenu.h" -std::string getProfileURL(const std::string& agent_name) +static LLPanelInjector t_panel_profile_secondlife("panel_profile_secondlife"); +static LLPanelInjector t_panel_web("panel_profile_web"); +static LLPanelInjector t_panel_picks("panel_profile_picks"); +static LLPanelInjector t_panel_firstlife("panel_profile_firstlife"); +static LLPanelInjector t_panel_notes("panel_profile_notes"); +static LLPanelInjector t_panel_profile("panel_profile"); + +static const std::string PANEL_SECONDLIFE = "panel_profile_secondlife"; +static const std::string PANEL_WEB = "panel_profile_web"; +static const std::string PANEL_PICKS = "panel_profile_picks"; +static const std::string PANEL_CLASSIFIEDS = "panel_profile_classifieds"; +static const std::string PANEL_FIRSTLIFE = "panel_profile_firstlife"; +static const std::string PANEL_NOTES = "panel_profile_notes"; +static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; + +static const std::string PROFILE_PROPERTIES_CAP = "AgentProfile"; +static const std::string PROFILE_IMAGE_UPLOAD_CAP = "UploadAgentProfileImage"; + + +////////////////////////////////////////////////////////////////////////// + +void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id) { - // OpenSim support - //std::string url = "[WEB_PROFILE_URL][AGENT_NAME]"; - //LLSD subs; - //subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); - std::string url; - LLSD subs; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; -#ifdef OPENSIM - if (LLGridManager::instance().isInOpenSim()) - { - url = LLGridManager::getInstance()->getWebProfileURL(); - if (url.empty()) - { - return LLStringUtil::null; - } + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); - std::string match = "?name=[AGENT_NAME]"; - if (url.find(match) == std::string::npos) - { - url += match; - } - } - else -#endif - { - url = "[WEB_PROFILE_URL][AGENT_NAME]"; - subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); - } - // + std::string finalUrl = cap_url + "/" + agent_id.asString(); - subs["AGENT_NAME"] = agent_name; - url = LLWeb::expandURLSubstitutions(url, subs); - LLStringUtil::toLower(url); - return url; + LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Result: " << httpResults << LL_ENDL; + + if (!status + || !result.has("id") + || agent_id != result["id"].asUUID()) + { + LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL; + return; + } + + LLFloater* floater_profile = LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id)); + if (!floater_profile) + { + // floater is dead, so panels are dead as well + return; + } + + LLPanel *panel = floater_profile->findChild(PANEL_PROFILE_VIEW, TRUE); + LLPanelProfile *panel_profile = dynamic_cast(panel); + if (!panel_profile) + { + LL_WARNS() << PANEL_PROFILE_VIEW << " not found" << LL_ENDL; + return; + } + + + // Avatar Data + + LLAvatarData *avatar_data = &panel_profile->mAvatarData; + std::string birth_date; + + avatar_data->agent_id = agent_id; + avatar_data->avatar_id = agent_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()); + + avatar_data->flags = 0; + + if (result["online"].asBoolean()) + { + 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; + } + + 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(); + } + + panel = floater_profile->findChild(PANEL_SECONDLIFE, TRUE); + LLPanelProfileSecondLife *panel_sl = dynamic_cast(panel); + if (panel_sl) + { + panel_sl->processProfileProperties(avatar_data); + } + + panel = floater_profile->findChild(PANEL_WEB, TRUE); + LLPanelProfileWeb *panel_web = dynamic_cast(panel); + if (panel_web) + { + panel_web->setLoaded(); + } + + panel = floater_profile->findChild(PANEL_FIRSTLIFE, TRUE); + LLPanelProfileFirstLife *panel_first = dynamic_cast(panel); + if (panel_first) + { + panel_first->processProperties(avatar_data); + } + + // 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) + { + const LLSD& pick_data = *it; + avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString()); + } + + panel = floater_profile->findChild(PANEL_PICKS, TRUE); + LLPanelProfilePicks *panel_picks = dynamic_cast(panel); + if (panel_picks) + { + // Refresh pick limit before processing + LLAgentPicksInfo::getInstance()->onServerRespond(&avatar_picks); + panel_picks->processProperties(&avatar_picks); + } + + // 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; + 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); + } + + if (panel_sl) + { + panel_sl->processGroupProperties(&avatar_groups); + } + + // Notes + LLAvatarNotes avatar_notes; + + avatar_notes.agent_id = agent_id; + avatar_notes.target_id = agent_id; + avatar_notes.notes = result["notes"].asString(); + + panel = floater_profile->findChild(PANEL_NOTES, TRUE); + LLPanelProfileNotes *panel_notes = dynamic_cast(panel); + if (panel_notes) + { + panel_notes->processProperties(&avatar_notes); + } } +//TODO: changes take two minutes to propagate! +// Add some storage that holds updated data for two minutes +// for new instances to reuse the data +// Profile data is only relevant to won avatar, but notes +// are for everybody +void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("put_avatar_properties_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + std::string finalUrl = cap_url + "/" + agent_id.asString(); + + LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS("AvatarProperties") << "Failed to put agent information " << data << " for id " << agent_id << LL_ENDL; + return; + } + + LL_DEBUGS("AvatarProperties") << "Agent id: " << agent_id << " Data: " << data << " Result: " << httpResults << LL_ENDL; +} + +LLUUID post_profile_image(std::string cap_url, const LLSD &first_data, std::string path_to_image, LLHandle *handle) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("post_profile_image_coro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders; + + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + httpOpts->setFollowRedirects(true); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, first_data, httpOpts, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap " << status.toString() << LL_ENDL; + return LLUUID::null; + } + if (!result.has("uploader")) + { + // todo: notification? + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, response contains no data." << LL_ENDL; + return LLUUID::null; + } + std::string uploader_cap = result["uploader"].asString(); + if (uploader_cap.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to get uploader cap, cap invalid." << LL_ENDL; + return LLUUID::null; + } + + // Upload the image + + LLCore::HttpRequest::ptr_t uploaderhttpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t uploaderhttpHeaders(new LLCore::HttpHeaders); + LLCore::HttpOptions::ptr_t uploaderhttpOpts(new LLCore::HttpOptions); + S64 length; + + { + llifstream instream(path_to_image.c_str(), std::iostream::binary | std::iostream::ate); + if (!instream.is_open()) + { + LL_WARNS("AvatarProperties") << "Failed to open file " << path_to_image << LL_ENDL; + return LLUUID::null; + } + length = instream.tellg(); + } + + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, "application/jp2"); // optional + uploaderhttpHeaders->append(HTTP_OUT_HEADER_CONTENT_LENGTH, llformat("%d", length)); // required! + uploaderhttpOpts->setFollowRedirects(true); + + result = httpAdapter->postFileAndSuspend(uploaderhttpRequest, uploader_cap, path_to_image, uploaderhttpOpts, uploaderhttpHeaders); + + httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + LL_WARNS("AvatarProperties") << result << LL_ENDL; + + if (!status) + { + LL_WARNS("AvatarProperties") << "Failed to upload image " << status.toString() << LL_ENDL; + return LLUUID::null; + } + + if (result["state"].asString() != "complete") + { + if (result.has("message")) + { + LL_WARNS("AvatarProperties") << "Failed to upload image, state " << result["state"] << " message: " << result["message"] << LL_ENDL; + } + else + { + LL_WARNS("AvatarProperties") << "Failed to upload image " << result << LL_ENDL; + } + return LLUUID::null; + } + + return result["new_asset"].asUUID(); +} + +enum EProfileImageType +{ + PROFILE_IMAGE_SL, + PROFILE_IMAGE_FL, +}; + +void post_profile_image_coro(std::string cap_url, EProfileImageType type, std::string path_to_image, LLHandle *handle) +{ + LLSD data; + switch (type) + { + case PROFILE_IMAGE_SL: + data["profile-image-asset"] = "sl_image_id"; + break; + case PROFILE_IMAGE_FL: + data["profile-image-asset"] = "fl_image_id"; + break; + } + + LLUUID result = post_profile_image(cap_url, data, path_to_image, handle); + + // reset loading indicator + if (!handle->isDead()) + { + switch (type) + { + case PROFILE_IMAGE_SL: + { + LLPanelProfileSecondLife* panel = static_cast(handle->get()); + if (result.notNull()) + { + panel->setProfileImageUploaded(result); + } + else + { + // failure, just stop progress indicator + panel->setProfileImageUploading(false); + } + break; + } + case PROFILE_IMAGE_FL: + { + LLPanelProfileFirstLife* panel = static_cast(handle->get()); + if (result.notNull()) + { + panel->setProfileImageUploaded(result); + } + else + { + // failure, just stop progress indicator + panel->setProfileImageUploading(false); + } + break; + } + } + } + + // Cleanup + LLFile::remove(path_to_image); + delete handle; +} + +////////////////////////////////////////////////////////////////////////// +// LLProfileHandler + class LLProfileHandler : public LLCommandHandler { public: @@ -100,6 +475,10 @@ public: }; LLProfileHandler gProfileHandler; + +////////////////////////////////////////////////////////////////////////// +// LLAgentHandler + class LLAgentHandler : public LLCommandHandler { public: @@ -228,273 +607,2400 @@ public: FSAgentSelfHandler gAgentSelfHandler; // -//-- LLPanelProfile::ChildStack begins ---------------------------------------- -LLPanelProfile::ChildStack::ChildStack() -: mParent(NULL) +///---------------------------------------------------------------------------- +/// LLFloaterProfilePermissions +///---------------------------------------------------------------------------- + +class LLFloaterProfilePermissions + : public LLFloater + , public LLFriendObserver +{ +public: + LLFloaterProfilePermissions(LLView * owner, const LLUUID &avatar_id); + ~LLFloaterProfilePermissions(); + BOOL postBuild() override; + void onOpen(const LLSD& key) override; + void draw() override; + void changed(U32 mask) override; // LLFriendObserver + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + bool hasUnsavedChanges() { return mHasUnsavedPermChanges; } + + void onApplyRights(); + +private: + void fillRightsData(); + void rightsConfirmationCallback(const LLSD& notification, const LLSD& response); + void confirmModifyRights(bool grant); + void onCommitSeeOnlineRights(); + void onCommitEditRights(); + void onCancel(); + + LLTextBase* mDescription; + LLCheckBoxCtrl* mOnlineStatus; + LLCheckBoxCtrl* mMapRights; + LLCheckBoxCtrl* mEditObjectRights; + LLButton* mOkBtn; + LLButton* mCancelBtn; + + LLUUID mAvatarID; + F32 mContextConeOpacity; + bool mHasUnsavedPermChanges; + LLHandle mOwnerHandle; + + boost::signals2::connection mAvatarNameCacheConnection; +}; + +LLFloaterProfilePermissions::LLFloaterProfilePermissions(LLView * owner, const LLUUID &avatar_id) + : LLFloater(LLSD()) + , mAvatarID(avatar_id) + , mContextConeOpacity(0.0f) + , mHasUnsavedPermChanges(false) + , mOwnerHandle(owner->getHandle()) +{ + buildFromFile("floater_profile_permissions.xml"); +} + +LLFloaterProfilePermissions::~LLFloaterProfilePermissions() +{ + mAvatarNameCacheConnection.disconnect(); + if (mAvatarID.notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(mAvatarID, this); + } +} + +BOOL LLFloaterProfilePermissions::postBuild() +{ + mDescription = getChild("perm_description"); + mOnlineStatus = getChild("online_check"); + mMapRights = getChild("map_check"); + mEditObjectRights = getChild("objects_check"); + mOkBtn = getChild("perms_btn_ok"); + mCancelBtn = getChild("perms_btn_cancel"); + + mOnlineStatus->setCommitCallback([this](LLUICtrl*, void*) { onCommitSeeOnlineRights(); }, nullptr); + mMapRights->setCommitCallback([this](LLUICtrl*, void*) { mHasUnsavedPermChanges = true; }, nullptr); + mEditObjectRights->setCommitCallback([this](LLUICtrl*, void*) { onCommitEditRights(); }, nullptr); + mOkBtn->setCommitCallback([this](LLUICtrl*, void*) { onApplyRights(); }, nullptr); + mCancelBtn->setCommitCallback([this](LLUICtrl*, void*) { onCancel(); }, nullptr); + + return TRUE; +} + +void LLFloaterProfilePermissions::onOpen(const LLSD& key) +{ + if (LLAvatarActions::isFriend(mAvatarID)) + { + LLAvatarTracker::instance().addParticularFriendObserver(mAvatarID, this); + fillRightsData(); + } + + mCancelBtn->setFocus(true); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(mAvatarID, boost::bind(&LLFloaterProfilePermissions::onAvatarNameCache, this, _1, _2)); +} + +void LLFloaterProfilePermissions::draw() +{ + // drawFrustum + LLView *owner = mOwnerHandle.get(); + static LLCachedControl max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, owner); + LLFloater::draw(); +} + +void LLFloaterProfilePermissions::changed(U32 mask) +{ + if (mask != LLFriendObserver::ONLINE) + { + fillRightsData(); + } +} + +void LLFloaterProfilePermissions::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mAvatarNameCacheConnection.disconnect(); + + LLStringUtil::format_map_t args; + // Fix LL UI/UX design accident + //args["[AGENT_NAME]"] = av_name.getDisplayName(); + args["[AGENT_NAME]"] = av_name.getCompleteName(); + std::string descritpion = getString("description_string", args); + mDescription->setValue(descritpion); +} + +void LLFloaterProfilePermissions::fillRightsData() +{ + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); + // If true - we are viewing friend's profile, enable check boxes and set values. + if (relation) + { + S32 rights = relation->getRightsGrantedTo(); + + BOOL see_online = LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE; + mOnlineStatus->setValue(see_online); + mMapRights->setEnabled(see_online); + mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); + mEditObjectRights->setValue(LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE); + } + else + { + closeFloater(); + LL_INFOS("ProfilePermissions") << "Floater closing since agent is no longer a friend" << LL_ENDL; + } +} + +void LLFloaterProfilePermissions::rightsConfirmationCallback(const LLSD& notification, + const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) // canceled + { + mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE); + } + else + { + mHasUnsavedPermChanges = true; + } +} + +void LLFloaterProfilePermissions::confirmModifyRights(bool grant) +{ + LLSD args; + args["NAME"] = LLSLURL("agent", mAvatarID, "completename").getSLURLString(); + LLNotificationsUtil::add(grant ? "GrantModifyRights" : "RevokeModifyRights", args, LLSD(), + boost::bind(&LLFloaterProfilePermissions::rightsConfirmationCallback, this, _1, _2)); +} + +void LLFloaterProfilePermissions::onCommitSeeOnlineRights() +{ + bool see_online = mOnlineStatus->getValue().asBoolean(); + mMapRights->setEnabled(see_online); + if (see_online) + { + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); + if (relation) + { + S32 rights = relation->getRightsGrantedTo(); + mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); + } + else + { + closeFloater(); + LL_INFOS("ProfilePermissions") << "Floater closing since agent is no longer a friend" << LL_ENDL; + } + } + else + { + mMapRights->setValue(FALSE); + } + mHasUnsavedPermChanges = true; +} + +void LLFloaterProfilePermissions::onCommitEditRights() +{ + const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); + + if (!buddy_relationship) + { + LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Closing floater." << LL_ENDL; + closeFloater(); + return; + } + + bool allow_modify_objects = mEditObjectRights->getValue().asBoolean(); + + // if modify objects checkbox clicked + if (buddy_relationship->isRightGrantedTo( + LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) + { + confirmModifyRights(allow_modify_objects); + } +} + +void LLFloaterProfilePermissions::onApplyRights() +{ + const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); + + if (!buddy_relationship) + { + LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL; + return; + } + + S32 rights = 0; + + if (mOnlineStatus->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_ONLINE_STATUS; + } + if (mMapRights->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_MAP_LOCATION; + } + if (mEditObjectRights->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_MODIFY_OBJECTS; + } + + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(mAvatarID, rights); + + closeFloater(); +} + +void LLFloaterProfilePermissions::onCancel() +{ + closeFloater(); +} + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfileSecondLife + +LLPanelProfileSecondLife::LLPanelProfileSecondLife() + : LLPanelProfileTab() + , mAvatarNameCacheConnection() + , mHasUnsavedDescriptionChanges(false) + , mWaitingForImageUpload(false) + , mAllowPublish(false) + , mRlvBehaviorCallbackConnection() // RLVa support { } -LLPanelProfile::ChildStack::~ChildStack() +LLPanelProfileSecondLife::~LLPanelProfileSecondLife() { - while (mStack.size() != 0) - { - view_list_t& top = mStack.back(); - for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) - { - LLView* viewp = *it; - if (viewp) - { - viewp->die(); - } - } - mStack.pop_back(); - } + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); + } + + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + + // RLVa support + if (mRlvBehaviorCallbackConnection.connected()) + { + mRlvBehaviorCallbackConnection.disconnect(); + } + // } -void LLPanelProfile::ChildStack::setParent(LLPanel* parent) +BOOL LLPanelProfileSecondLife::postBuild() { - llassert_always(parent != NULL); - mParent = parent; + mGroupList = getChild("group_list"); + // Fix LL UI/UX design accident + //mShowInSearchCombo = getChild("show_in_search"); + mShowInSearchCheckbox = getChild("show_in_search"); + // + mSecondLifePic = getChild("2nd_life_pic"); + mSecondLifePicLayout = getChild("image_panel"); + mDescriptionEdit = getChild("sl_description_edit"); + // mAgentActionMenuButton = getChild("agent_actions_menu"); // Fix LL UI/UX design accident + mSaveDescriptionChanges = getChild("save_description_changes"); + mDiscardDescriptionChanges = getChild("discard_description_changes"); + mCanSeeOnlineIcon = getChild("can_see_online"); + mCantSeeOnlineIcon = getChild("cant_see_online"); + mCanSeeOnMapIcon = getChild("can_see_on_map"); + mCantSeeOnMapIcon = getChild("cant_see_on_map"); + mCanEditObjectsIcon = getChild("can_edit_objects"); + mCantEditObjectsIcon = getChild("cant_edit_objects"); + + // Fix LL UI/UX design accident + mStatusText = getChild("status"); + mCopyMenuButton = getChild("copy_btn"); + mGroupInviteButton = getChild("group_invite"); + mDisplayNameButton = getChild("set_name"); + mImageActionMenuButton = getChild("image_action_btn"); + mTeleportButton = getChild("teleport"); + mShowOnMapButton = getChild("show_on_map_btn"); + mBlockButton = getChild("block"); + mUnblockButton = getChild("unblock"); + mAddFriendButton = getChild("add_friend"); + mPayButton = getChild("pay"); + mIMButton = getChild("im"); + mOverflowButton = getChild("overflow_btn"); + // + + // Fix LL UI/UX design accident + //mShowInSearchCombo->setCommitCallback([this](LLUICtrl*, void*) { onShowInSearchCallback(); }, nullptr); + mShowInSearchCheckbox->setCommitCallback([this](LLUICtrl*, void*) { onShowInSearchCallback(); }, nullptr); + mGroupInviteButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("invite_to_group")); }, nullptr); + mDisplayNameButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("edit_display_name")); }, nullptr); + mTeleportButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("offer_teleport")); }, nullptr); + mShowOnMapButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("can_show_on_map")); }, nullptr); + mBlockButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("toggle_block_agent")); }, nullptr); + mUnblockButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("toggle_block_agent")); }, nullptr); + mAddFriendButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("add_friend")); }, nullptr); + mPayButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("pay")); }, nullptr); + mIMButton->setCommitCallback([this](LLUICtrl*, void*) { onCommitMenu(LLSD("im")); }, nullptr); + // + mGroupList->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { LLPanelProfileSecondLife::openGroupProfile(); }); + mGroupList->setReturnCallback([this](LLUICtrl*, const LLSD&) { LLPanelProfileSecondLife::openGroupProfile(); }); + mSaveDescriptionChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveDescriptionChanges(); }, nullptr); + mDiscardDescriptionChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardDescriptionChanges(); }, nullptr); + mDescriptionEdit->setKeystrokeCallback([this](LLTextEditor* caller) { onSetDescriptionDirty(); }); + + //getChild("open_notes")->setCommitCallback([this](LLUICtrl*, void*) { onOpenNotes(); }, nullptr); // Doesn't exist (anymore) + + mCanSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCanSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCanEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mSecondLifePic->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentProfileTexture(); }); + + // RLVa support + mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&LLPanelProfileSecondLife::updateRlvRestrictions, this, _1)); + + return TRUE; } -/// Save current parent's child views and remove them from the child list. -bool LLPanelProfile::ChildStack::push() +void LLPanelProfileSecondLife::onOpen(const LLSD& key) { - view_list_t vlist = *mParent->getChildList(); + LLPanelProfileTab::onOpen(key); - for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it) - { - LLView* viewp = *it; - mParent->removeChild(viewp); - } + resetData(); - mStack.push_back(vlist); - dump(); - return true; + LLUUID avatar_id = getAvatarId(); + + BOOL own_profile = getSelfProfile(); + + mGroupList->setShowNone(!own_profile); + + //childSetVisible("notes_panel", !own_profile); // Doesn't exist (anymore) + // Fix LL UI/UX design accident + //childSetVisible("settings_panel", own_profile); + //childSetVisible("about_buttons_panel", own_profile); + mSaveDescriptionChanges->setVisible(own_profile); + mDiscardDescriptionChanges->setVisible(own_profile); + mShowInSearchCheckbox->setVisible(own_profile); + // + + if (own_profile) + { + // Group list control cannot toggle ForAgent loading + // Less than ideal, but viewing own profile via search is edge case + mGroupList->enableForAgent(false); + } + + // Init menu, menu needs to be created in scope of a registar to work correctly. + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit; + commit.add("Profile.Commit", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); }); + + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable; + enable.add("Profile.EnableItem", [this](LLUICtrl*, const LLSD& userdata) { return onEnableMenu(userdata); }); + enable.add("Profile.CheckItem", [this](LLUICtrl*, const LLSD& userdata) { return onCheckMenu(userdata); }); + + // Fix LL UI/UX design accident + //if (own_profile) + //{ + // mAgentActionMenuButton->setMenu("menu_profile_self.xml", LLMenuButton::MP_BOTTOM_RIGHT); + //} + //else + //{ + // // Todo: use PeopleContextMenu instead? + // mAgentActionMenuButton->setMenu("menu_profile_other.xml", LLMenuButton::MP_BOTTOM_RIGHT); + //} + if (own_profile) + { + mImageActionMenuButton->setVisible(TRUE); + mImageActionMenuButton->setMenu("menu_fs_profile_image_actions.xml", LLMenuButton::MP_BOTTOM_RIGHT); + } + else + { + mImageActionMenuButton->setVisible(FALSE); + LLToggleableMenu* profile_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_fs_profile_overflow.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mOverflowButton->setMenu(profile_menu, LLMenuButton::MP_TOP_RIGHT); + } + + mCopyMenuButton->setMenu("menu_fs_profile_name_field.xml", LLMenuButton::MP_BOTTOM_RIGHT); + // + + mDescriptionEdit->setParseHTML(!own_profile); + + if (!own_profile) + { + mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : TRUE); + updateOnlineStatus(); + fillRightsData(); + } + + // Display agent ID + getChild("user_key")->setValue(avatar_id.asString()); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); } -/// Restore saved children (adding them back to the child list). -bool LLPanelProfile::ChildStack::pop() +void LLPanelProfileSecondLife::updateData() { - if (mStack.size() == 0) - { - LL_WARNS() << "Empty stack" << LL_ENDL; - llassert(mStack.size() == 0); - return false; - } + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); - view_list_t& top = mStack.back(); - for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) - { - LLView* viewp = *it; - mParent->addChild(viewp); - } - - mStack.pop_back(); - dump(); - return true; + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("requestAgentUserInfoCoro", + boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); + } + else + { + LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL; + } + } } -/// Temporarily add all saved children back. -void LLPanelProfile::ChildStack::preParentReshape() +void LLPanelProfileSecondLife::refreshName() { - mSavedStack = mStack; - while(mStack.size() > 0) - { - pop(); - } + if (!mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); + } } -/// Add the temporarily saved children back. -void LLPanelProfile::ChildStack::postParentReshape() +void LLPanelProfileSecondLife::resetData() { - mStack = mSavedStack; - mSavedStack = stack_t(); + resetLoading(); - for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it) - { - const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) - { - LLView* viewp = *list_it; - LL_DEBUGS() << "removing " << viewp->getName() << LL_ENDL; - mParent->removeChild(viewp); - } - } + // Set default image and 1:1 dimensions for it + mSecondLifePic->setValue("Generic_Person_Large"); + mImageId = LLUUID::null; + + // Fix LL UI/UX design accident + //LLRect imageRect = mSecondLifePicLayout->getRect(); + LLRect imageRect = mSecondLifePic->getRect(); + mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight()); + + setDescriptionText(LLStringUtil::null); + mGroups.clear(); + mGroupList->setGroups(mGroups); + + bool own_profile = getSelfProfile(); + mCanSeeOnlineIcon->setVisible(false); + // Fix LL UI/UX design accident + //mCantSeeOnlineIcon->setVisible(!own_profile); + mCantSeeOnlineIcon->setVisible(FALSE); + mCanSeeOnMapIcon->setVisible(false); + // Fix LL UI/UX design accident + //mCantSeeOnMapIcon->setVisible(!own_profile); + mCantSeeOnMapIcon->setVisible(FALSE); + mCanEditObjectsIcon->setVisible(false); + // Fix LL UI/UX design accident + //mCantEditObjectsIcon->setVisible(!own_profile); + mCantEditObjectsIcon->setVisible(FALSE); + + mCanSeeOnlineIcon->setEnabled(false); + mCantSeeOnlineIcon->setEnabled(false); + mCanSeeOnMapIcon->setEnabled(false); + mCantSeeOnMapIcon->setEnabled(false); + mCanEditObjectsIcon->setEnabled(false); + mCantEditObjectsIcon->setEnabled(false); + + // Fix LL UI/UX design accident + //childSetVisible("partner_layout", FALSE); + mStatusText->setVisible(FALSE); + mCopyMenuButton->setVisible(FALSE); + mGroupInviteButton->setVisible(!own_profile); + if (own_profile && LLAvatarName::useDisplayNames()) + { + mDisplayNameButton->setVisible(TRUE); + mDisplayNameButton->setEnabled(TRUE); + } + mShowOnMapButton->setVisible(!own_profile); + mPayButton->setVisible(!own_profile); + mTeleportButton->setVisible(!own_profile); + mIMButton->setVisible(!own_profile); + mAddFriendButton->setVisible(!own_profile); + mBlockButton->setVisible(!own_profile); + mUnblockButton->setVisible(!own_profile); + mGroupList->setShowNone(!own_profile); + mOverflowButton->setVisible(!own_profile); + + updateButtons(); + // } -void LLPanelProfile::ChildStack::dump() +void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) { - unsigned lvl = 0; - LL_DEBUGS() << "child stack dump:" << LL_ENDL; - for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl) - { - std::ostringstream dbg_line; - dbg_line << "lvl #" << lvl << ":"; - const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) - { - dbg_line << " " << (*list_it)->getName(); - } - LL_DEBUGS() << dbg_line.str() << LL_ENDL; - } + LLUUID avatar_id = getAvatarId(); + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + if ((relationship != NULL || gAgent.isGodlike()) && !getSelfProfile()) + { + // Relies onto friend observer to get information about online status updates. + // Once SL-17506 gets implemented, condition might need to become: + // (gAgent.isGodlike() || isRightGrantedFrom || flags & AVATAR_ONLINE) + processOnlineStatus(relationship != NULL, + gAgent.isGodlike() || relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS), + (avatar_data->flags & AVATAR_ONLINE)); + } + + fillCommonData(avatar_data); + + fillPartnerData(avatar_data); + + fillAccountStatus(avatar_data); + + setLoaded(); + + // Fix LL UI/UX design accident + updateButtons(); } -//-- LLPanelProfile::ChildStack ends ------------------------------------------ +void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups) +{ + + LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); + const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end(); + + for (; it_end != it; ++it) + { + LLAvatarGroups::LLGroupData group_data = *it; + mGroups[group_data.group_name] = group_data.group_id; + } + + mGroupList->setGroups(mGroups); +} + +void LLPanelProfileSecondLife::openGroupProfile() +{ + LLUUID group_id = mGroupList->getSelectedUUID(); + LLGroupActions::show(group_id); +} + +void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mAvatarNameCacheConnection.disconnect(); + // Fix LL UI/UX design accident + //getChild("display_name")->setValue(av_name.getDisplayName()); + //getChild("user_name")->setValue(av_name.getAccountName()); + getChild("complete_name")->setValue(av_name.getCompleteName()); + mCopyMenuButton->setVisible(TRUE); + // +} + +void LLPanelProfileSecondLife::setProfileImageUploading(bool loading) +{ + LLLoadingIndicator* indicator = getChild("image_upload_indicator"); + indicator->setVisible(loading); + if (loading) + { + indicator->start(); + } + else + { + indicator->stop(); + } + mWaitingForImageUpload = loading; +} + +void LLPanelProfileSecondLife::setProfileImageUploaded(const LLUUID &image_asset_id) +{ + mSecondLifePic->setValue(image_asset_id); + mImageId = image_asset_id; + + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(image_asset_id); + if (imagep->getFullHeight()) + { + onImageLoaded(true, imagep); + } + else + { + imagep->setLoadedCallback(onImageLoaded, + MAX_DISCARD_LEVEL, + FALSE, + FALSE, + new LLHandle(getHandle()), + NULL, + FALSE); + } + + LLFloater *floater = mFloaterProfileTextureHandle.get(); + if (floater) + { + LLFloaterProfileTexture * texture_view = dynamic_cast(floater); + if (mImageId.notNull()) + { + texture_view->loadAsset(mImageId); + } + else + { + texture_view->resetAsset(); + } + } + + setProfileImageUploading(false); +} + +bool LLPanelProfileSecondLife::hasUnsavedChanges() +{ + LLFloater *floater = mFloaterPermissionsHandle.get(); + if (floater) + { + LLFloaterProfilePermissions* perm = dynamic_cast(floater); + if (perm && perm->hasUnsavedChanges()) + { + return true; + } + } + // if floater + return mHasUnsavedDescriptionChanges; +} + +void LLPanelProfileSecondLife::commitUnsavedChanges() +{ + LLFloater *floater = mFloaterPermissionsHandle.get(); + if (floater) + { + LLFloaterProfilePermissions* perm = dynamic_cast(floater); + if (perm && perm->hasUnsavedChanges()) + { + perm->onApplyRights(); + } + } + if (mHasUnsavedDescriptionChanges) + { + onSaveDescriptionChanges(); + } +} + +void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) +{ + // Refresh avatar id in cache with new info to prevent re-requests + // and to make sure icons in text will be up to date + LLAvatarIconIDCache::getInstance()->add(avatar_data->avatar_id, avatar_data->image_id); + + fillAgeData(avatar_data->born_on); + + setDescriptionText(avatar_data->about_text); + + if (avatar_data->image_id.notNull()) + { + mSecondLifePic->setValue(avatar_data->image_id); + mImageId = avatar_data->image_id; + } + else + { + mSecondLifePic->setValue("Generic_Person_Large"); + mImageId = LLUUID::null; + } + + // Will be loaded as a LLViewerFetchedTexture::BOOST_UI due to mSecondLifePic + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id); + if (imagep->getFullHeight()) + { + onImageLoaded(true, imagep); + } + else + { + imagep->setLoadedCallback(onImageLoaded, + MAX_DISCARD_LEVEL, + FALSE, + FALSE, + new LLHandle(getHandle()), + NULL, + FALSE); + } + + if (getSelfProfile()) + { + mAllowPublish = avatar_data->flags & AVATAR_ALLOW_PUBLISH; + // Fix LL UI/UX design accident + //mShowInSearchCombo->setValue((BOOL)mAllowPublish); + mShowInSearchCheckbox->setValue((BOOL)mAllowPublish); + // + } +} + +void LLPanelProfileSecondLife::fillPartnerData(const LLAvatarData* avatar_data) +{ + // Fix LL UI/UX design accident + //LLTextBox* partner_text_ctrl = getChild("partner_link"); + LLTextEditor* partner_text_ctrl = getChild("partner_link"); + if (avatar_data->partner_id.notNull()) + { + // Fix LL UI/UX design accident + //childSetVisible("partner_layout", TRUE); + //LLStringUtil::format_map_t args; + //args["[LINK]"] = LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString(); + //std::string partner_text = getString("partner_text", args); + //partner_text_ctrl->setText(partner_text); + partner_text_ctrl->setText(LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString()); + // + } + else + { + // Fix LL UI/UX design accident + //childSetVisible("partner_layout", FALSE); + partner_text_ctrl->setText(getString("no_partner_text")); + } +} + +void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data) +{ + LLStringUtil::format_map_t args; + args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(avatar_data); + args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(avatar_data); + + // FSData support + args["[FIRESTORM]"] = ""; + args["[FSSUPP]"] = ""; + args["[FSDEV]"] = ""; + args["[FSQA]"] = ""; + args["[FSGW]"] = ""; + S32 flags = FSData::getInstance()->getAgentFlags(avatar_data->avatar_id); + if (flags != -1) + { + bool separator = false; + std::string text; + if (flags & (FSData::DEVELOPER | FSData::SUPPORT | FSData::QA | FSData::GATEWAY)) + { + args["[FIRESTORM]"] = LLTrans::getString("APP_NAME"); + } + + if (flags & FSData::DEVELOPER) + { + text = getString("FSDev"); + args["[FSDEV]"] = text; + separator = true; + } + + if (flags & FSData::SUPPORT) + { + text = getString("FSSupp"); + if (separator) + { + text = " /" + text; + } + args["[FSSUPP]"] = text; + separator = true; + } + + if (flags & FSData::QA) + { + text = getString("FSQualityAssurance"); + if (separator) + { + text = " /" + text; + } + args["[FSQA]"] = text; + separator = true; + } + + if (flags & FSData::GATEWAY) + { + text = getString("FSGW"); + if (separator) + { + text = " /" + text; + } + args["[FSGW]"] = text; + } + } + // + + std::string caption_text = getString("CaptionTextAcctInfo", args); + getChild("account_info")->setValue(caption_text); +} + +void LLPanelProfileSecondLife::fillRightsData() +{ + if (getSelfProfile()) + { + return; + } + + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + // If true - we are viewing friend's profile, enable check boxes and set values. + if (relation) + { + S32 rights = relation->getRightsGrantedTo(); + bool can_see_online = LLRelationship::GRANT_ONLINE_STATUS & rights; + bool can_see_on_map = LLRelationship::GRANT_MAP_LOCATION & rights; + bool can_edit_objects = LLRelationship::GRANT_MODIFY_OBJECTS & rights; + + mCanSeeOnlineIcon->setVisible(can_see_online); + mCantSeeOnlineIcon->setVisible(!can_see_online); + mCanSeeOnMapIcon->setVisible(can_see_on_map); + mCantSeeOnMapIcon->setVisible(!can_see_on_map); + mCanEditObjectsIcon->setVisible(can_edit_objects); + mCantEditObjectsIcon->setVisible(!can_edit_objects); + + mCanSeeOnlineIcon->setEnabled(true); + mCantSeeOnlineIcon->setEnabled(true); + mCanSeeOnMapIcon->setEnabled(true); + mCantSeeOnMapIcon->setEnabled(true); + mCanEditObjectsIcon->setEnabled(true); + mCantEditObjectsIcon->setEnabled(true); + } + else + { + mCanSeeOnlineIcon->setVisible(false); + mCantSeeOnlineIcon->setVisible(false); + mCanSeeOnMapIcon->setVisible(false); + mCantSeeOnMapIcon->setVisible(false); + mCanEditObjectsIcon->setVisible(false); + mCantEditObjectsIcon->setVisible(false); + } +} + +void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on) +{ + // Fix LL UI/UX design accident + //std::string name_and_date = getString("date_format"); + //LLSD args_name; + //args_name["datetime"] = (S32)born_on.secondsSinceEpoch(); + //LLStringUtil::format(name_and_date, args_name); + //getChild("sl_birth_date")->setValue(name_and_date); + // + + std::string register_date = getString("age_format"); + LLSD args_age; + // Fix LL UI/UX design accident + std::string birth_date = LLTrans::getString("AvatarBirthDateFormat"); + LLStringUtil::format(birth_date, LLSD().with("datetime", (S32)born_on.secondsSinceEpoch())); + args_age["[REG_DATE]"] = birth_date; + // + args_age["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now()); + LLStringUtil::format(register_date, args_age); + getChild("user_age")->setValue(register_date); +} + +void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep) +{ + // Fix LL UI/UX design accident + //LLRect imageRect = mSecondLifePicLayout->getRect(); + LLRect imageRect = mSecondLifePic->getRect(); + if (!success || imagep->getFullWidth() == imagep->getFullHeight()) + { + // Fix LL UI/UX design accident + //mSecondLifePicLayout->reshape(imageRect.getWidth(), imageRect.getWidth()); + mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight()); + } + else + { + // assume 3:4, for sake of firestorm + // Fix LL UI/UX design accident + //mSecondLifePicLayout->reshape(imageRect.getWidth(), imageRect.getWidth() * 3 / 4); + mSecondLifePicLayout->reshape(imageRect.getHeight() * 4 / 3, imageRect.getHeight()); + } +} + +//static +void LLPanelProfileSecondLife::onImageLoaded(BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if (!userdata) return; + + LLHandle* handle = (LLHandle*)userdata; + + if (!handle->isDead()) + { + LLPanelProfileSecondLife* panel = static_cast(handle->get()); + if (panel) + { + panel->onImageLoaded(success, src_vi); + } + } + + if (final || !success) + { + delete handle; + } +} + +// virtual, called by LLAvatarTracker +void LLPanelProfileSecondLife::changed(U32 mask) +{ + updateOnlineStatus(); + if (mask != LLFriendObserver::ONLINE) + { + fillRightsData(); + } + + updateButtons(); // Fix LL UI/UX design accident +} + +// virtual, called by LLVoiceClient +void LLPanelProfileSecondLife::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(getAvatarId()) ? LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) : TRUE); +} + +void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + + LLPanelProfileTab::setAvatarId(avatar_id); + + if (LLAvatarActions::isFriend(getAvatarId())) + { + LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this); + } + } +} + +// method was disabled according to EXT-2022. Re-enabled & improved according to EXT-3880 +void LLPanelProfileSecondLife::updateOnlineStatus() +{ + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + if (relationship != NULL) + { + // For friend let check if he allowed me to see his status + bool online = relationship->isOnline(); + bool perm_granted = relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS); + processOnlineStatus(true, perm_granted, online); + } + // Fix LL UI/UX design accident + //else + //{ + // childSetVisible("frind_layout", false); + // childSetVisible("online_layout", false); + // childSetVisible("offline_layout", false); + //} + // +} + +void LLPanelProfileSecondLife::processOnlineStatus(bool is_friend, bool show_online, bool online) +{ + // Fix LL UI/UX design accident + //childSetVisible("frind_layout", is_friend); + //childSetVisible("online_layout", online && show_online); + //childSetVisible("offline_layout", !online && show_online); + mStatusText->setVisible(show_online); + + std::string status = getString(online ? "status_online" : "status_offline"); + + mStatusText->setValue(status); + mStatusText->setColor(online ? + LLUIColorTable::instance().getColor("StatusUserOnline") : + LLUIColorTable::instance().getColor("StatusUserOffline")); + // +} + +void LLPanelProfileSecondLife::setLoaded() +{ + LLPanelProfileTab::setLoaded(); + + if (getSelfProfile()) + { + // Fix LL UI/UX design accident + //mShowInSearchCombo->setEnabled(TRUE); + mShowInSearchCheckbox->setEnabled(TRUE); + // + mDescriptionEdit->setEnabled(TRUE); + } +} + +// Fix LL UI/UX design accident +void LLPanelProfileSecondLife::updateButtons() +{ + if (getSelfProfile()) + { + mShowInSearchCheckbox->setVisible(TRUE); + mShowInSearchCheckbox->setEnabled(TRUE); + mDescriptionEdit->setEnabled(TRUE); + } + else + { + LLUUID av_id = getAvatarId(); + bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()); + + if (LLAvatarActions::isFriend(av_id)) + { + // RLVa support + //mTeleportButton->setEnabled(is_buddy_online); + const LLRelationship* friend_status = LLAvatarTracker::instance().getBuddyInfo(av_id); + bool can_offer_tp = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) || + (gRlvHandler.isException(RLV_BHVR_TPLURE, av_id, ERlvExceptionCheck::Permissive) || + friend_status->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))); + + mTeleportButton->setEnabled(is_buddy_online && can_offer_tp); + // + //Disable "Add Friend" button for friends. + mAddFriendButton->setEnabled(false); + } + else + { + // RLVa support + //mTeleportButton->setEnabled(true); + bool can_offer_tp = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) || + gRlvHandler.isException(RLV_BHVR_TPLURE, av_id, ERlvExceptionCheck::Permissive)); + mTeleportButton->setEnabled(can_offer_tp); + // + mAddFriendButton->setEnabled(true); + } + + // RLVa support + //bool enable_map_btn = (is_buddy_online && is_agent_mappable(av_id)) || gAgent.isGodlike(); + bool enable_map_btn = ((is_buddy_online && is_agent_mappable(av_id)) || gAgent.isGodlike()) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); + // + mShowOnMapButton->setEnabled(enable_map_btn); + + bool enable_block_btn = LLAvatarActions::canBlock(av_id) && !LLAvatarActions::isBlocked(av_id); + mBlockButton->setVisible(enable_block_btn); + + bool enable_unblock_btn = LLAvatarActions::isBlocked(av_id); + mUnblockButton->setVisible(enable_unblock_btn); + } +} +// + +class LLProfileImagePicker : public LLFilePickerThread +{ +public: + LLProfileImagePicker(EProfileImageType type, LLHandle *handle); + ~LLProfileImagePicker(); + void notify(const std::vector& filenames) override; + +private: + LLHandle *mHandle; + EProfileImageType mType; +}; + +LLProfileImagePicker::LLProfileImagePicker(EProfileImageType type, LLHandle *handle) + : LLFilePickerThread(LLFilePicker::FFLOAD_IMAGE), + mHandle(handle), + mType(type) +{ +} + +LLProfileImagePicker::~LLProfileImagePicker() +{ + delete mHandle; +} + +void LLProfileImagePicker::notify(const std::vector& filenames) +{ + if (mHandle->isDead()) + { + return; + } + if (filenames.empty()) + { + return; + } + std::string file_path = filenames[0]; + if (file_path.empty()) + { + return; + } + + // generate a temp texture file for coroutine + std::string temp_file = gDirUtilp->getTempFilename(); + U32 codec = LLImageBase::getCodecFromExtension(gDirUtilp->getExtension(file_path)); + const S32 MAX_DIM = 256; + if (!LLViewerTextureList::createUploadFile(file_path, temp_file, codec, MAX_DIM)) + { + //todo: image not supported notification + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", failed to open image" << LL_ENDL; + return; + } + + std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); + if (cap_url.empty()) + { + LL_WARNS("AvatarProperties") << "Failed to upload profile image of type " << (S32)PROFILE_IMAGE_SL << ", no cap found" << LL_ENDL; + return; + } + + switch (mType) + { + case PROFILE_IMAGE_SL: + { + LLPanelProfileSecondLife* panel = static_cast(mHandle->get()); + panel->setProfileImageUploading(true); + } + break; + case PROFILE_IMAGE_FL: + { + LLPanelProfileFirstLife* panel = static_cast(mHandle->get()); + panel->setProfileImageUploading(true); + } + break; + } + + LLCoros::instance().launch("postAgentUserImageCoro", + boost::bind(post_profile_image_coro, cap_url, mType, temp_file, mHandle)); + + mHandle = nullptr; // transferred to post_profile_image_coro +} + +void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) +{ + const std::string item_name = userdata.asString(); + const LLUUID agent_id = getAvatarId(); + // todo: consider moving this into LLAvatarActions::onCommit(name, id) + // and making all other flaoters, like people menu do the same + if (item_name == "im") + { + LLAvatarActions::startIM(agent_id); + } + else if (item_name == "offer_teleport") + { + LLAvatarActions::offerTeleport(agent_id); + } + else if (item_name == "request_teleport") + { + LLAvatarActions::teleportRequest(agent_id); + } + else if (item_name == "voice_call") + { + LLAvatarActions::startCall(agent_id); + } + else if (item_name == "chat_history") + { + LLAvatarActions::viewChatHistory(agent_id); + } + else if (item_name == "add_friend") + { + LLAvatarActions::requestFriendshipDialog(agent_id); + } + else if (item_name == "remove_friend") + { + LLAvatarActions::removeFriendDialog(agent_id); + } + else if (item_name == "invite_to_group") + { + LLAvatarActions::inviteToGroup(agent_id); + } + else if (item_name == "can_show_on_map") + { + LLAvatarActions::showOnMap(agent_id); + } + else if (item_name == "share") + { + LLAvatarActions::share(agent_id); + } + else if (item_name == "pay") + { + LLAvatarActions::pay(agent_id); + } + else if (item_name == "toggle_block_agent") + { + LLAvatarActions::toggleBlock(agent_id); + } + else if (item_name == "copy_user_id") + { + LLWString wstr = utf8str_to_wstring(getAvatarId().asString()); + LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size()); + } + else if (item_name == "agent_permissions") + { + onShowAgentPermissionsDialog(); + } + else if (item_name == "copy_display_name" + || item_name == "copy_username") + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(getAvatarId(), &av_name)) + { + // shouldn't happen, option is supposed to be invisible while name is fetching + LL_WARNS() << "Failed to get agent data" << LL_ENDL; + return; + } + LLWString wstr; + if (item_name == "copy_display_name") + { + wstr = utf8str_to_wstring(av_name.getDisplayName(true)); + } + else if (item_name == "copy_username") + { + wstr = utf8str_to_wstring(av_name.getUserName()); + } + LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size()); + } + else if (item_name == "edit_display_name") + { + LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCacheSetName, this, _1, _2)); + LLFirstUse::setDisplayName(false); + } + else if (item_name == "edit_partner") + { + std::string url = "https://[GRID]/my/account/partners.php"; + LLSD subs; + url = LLWeb::expandURLSubstitutions(url, subs); + LLUrlAction::openURL(url); + } + else if (item_name == "upload_photo") + { + (new LLProfileImagePicker(PROFILE_IMAGE_SL, new LLHandle(getHandle())))->getFile(); + + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + if (floaterp) + { + floaterp->closeFloater(); + } + } + else if (item_name == "change_photo") + { + onShowTexturePicker(); + } + else if (item_name == "remove_photo") + { + onCommitProfileImage(LLUUID::null); + + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + if (floaterp) + { + floaterp->closeFloater(); + } + } + // Fix LL UI/UX design accident + else if (item_name == "add_to_contact_set") + { + LLAvatarActions::addToContactSet(agent_id); + } + else if (item_name == "copy_uri") + { + LLWString wstr = utf8str_to_wstring(LLSLURL("agent", agent_id, "about").getSLURLString()); + LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size()); + } + else if (item_name == "kick") + { + LLAvatarActions::kick(agent_id); + } + else if (item_name == "freeze") + { + LLAvatarActions::freeze(agent_id); + } + else if (item_name == "unfreeze") + { + LLAvatarActions::unfreeze(agent_id); + } + else if (item_name == "csr") + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(getAvatarId(), &av_name)) + { + // shouldn't happen, option is supposed to be invisible while name is fetching + LL_WARNS() << "Failed to get agent data" << LL_ENDL; + return; + } + LLAvatarActions::csr(getAvatarId(), av_name.getUserName()); + } + else if (item_name == "report") + { + LLAvatarActions::report(agent_id); + } + // +} + +bool LLPanelProfileSecondLife::onEnableMenu(const LLSD& userdata) +{ + const std::string item_name = userdata.asString(); + const LLUUID agent_id = getAvatarId(); + if (item_name == "offer_teleport" || item_name == "request_teleport") + { + return LLAvatarActions::canOfferTeleport(agent_id); + } + else if (item_name == "voice_call") + { + return mVoiceStatus; + } + else if (item_name == "chat_history") + { + return LLLogChat::isTranscriptExist(agent_id); + } + else if (item_name == "add_friend") + { + return !LLAvatarActions::isFriend(agent_id); + } + else if (item_name == "remove_friend") + { + return LLAvatarActions::isFriend(agent_id); + } + else if (item_name == "can_show_on_map") + { + // RLVa + //return (LLAvatarTracker::instance().isBuddyOnline(agent_id) && is_agent_mappable(agent_id)) + //|| gAgent.isGodlike(); + return ((LLAvatarTracker::instance().isBuddyOnline(agent_id) && is_agent_mappable(agent_id)) + || gAgent.isGodlike()) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP); + // + } + else if (item_name == "toggle_block_agent") + { + return LLAvatarActions::canBlock(agent_id); + } + else if (item_name == "agent_permissions") + { + return LLAvatarActions::isFriend(agent_id); + } + else if (item_name == "copy_display_name" + || item_name == "copy_username") + { + return !mAvatarNameCacheConnection.connected(); + } + else if (item_name == "upload_photo" + || item_name == "change_photo") + { + std::string cap_url = gAgent.getRegionCapability(PROFILE_IMAGE_UPLOAD_CAP); + return !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded(); + } + else if (item_name == "remove_photo") + { + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + return mImageId.notNull() && !cap_url.empty() && !mWaitingForImageUpload && getIsLoaded(); + } + // Fix LL UI/UX design accident + else if (item_name == "kick" || item_name == "freeze" || item_name == "unfreeze" || item_name == "csr") + { + return gAgent.isGodlike(); + } + // + + return false; +} + +bool LLPanelProfileSecondLife::onCheckMenu(const LLSD& userdata) +{ + const std::string item_name = userdata.asString(); + const LLUUID agent_id = getAvatarId(); + if (item_name == "toggle_block_agent") + { + return LLAvatarActions::isBlocked(agent_id); + } + return false; +} + +void LLPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + if (av_name.getDisplayName().empty()) + { + // something is wrong, tell user to try again later + LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); + return; + } + + LL_INFOS("LegacyProfile") << "name-change now " << LLDate::now() << " next_update " + << LLDate(av_name.mNextUpdate) << LL_ENDL; + F64 now_secs = LLDate::now().secondsSinceEpoch(); + + if (now_secs < av_name.mNextUpdate) + { + // if the update time is more than a year in the future, it means updates have been blocked + // show a more general message + static const S32 YEAR = 60*60*24*365; + if (now_secs + YEAR < av_name.mNextUpdate) + { + LLNotificationsUtil::add("SetDisplayNameBlocked"); + return; + } + } + + LLFloaterReg::showInstance("display_name"); +} + +void LLPanelProfileSecondLife::setDescriptionText(const std::string &text) +{ + mSaveDescriptionChanges->setEnabled(FALSE); + mDiscardDescriptionChanges->setEnabled(FALSE); + mHasUnsavedDescriptionChanges = false; + + mDescriptionText = text; + mDescriptionEdit->setValue(mDescriptionText); +} + +void LLPanelProfileSecondLife::onSetDescriptionDirty() +{ + mSaveDescriptionChanges->setEnabled(TRUE); + mDiscardDescriptionChanges->setEnabled(TRUE); + mHasUnsavedDescriptionChanges = true; +} + +void LLPanelProfileSecondLife::onShowInSearchCallback() +{ + // Fix LL UI/UX design accident + //S32 value = mShowInSearchCombo->getValue().asInteger(); + S32 value = mShowInSearchCheckbox->getValue().asInteger(); + // + if (mAllowPublish == (bool)value) + { + return; + } + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + mAllowPublish = value; + LLSD data; + data["allow_publish"] = mAllowPublish; + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), data)); + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } +} + +void LLPanelProfileSecondLife::onSaveDescriptionChanges() +{ + mDescriptionText = mDescriptionEdit->getValue().asString(); + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("sl_about_text", mDescriptionText))); + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } + + mSaveDescriptionChanges->setEnabled(FALSE); + mDiscardDescriptionChanges->setEnabled(FALSE); + mHasUnsavedDescriptionChanges = false; +} + +void LLPanelProfileSecondLife::onDiscardDescriptionChanges() +{ + setDescriptionText(mDescriptionText); +} + +void LLPanelProfileSecondLife::onShowAgentPermissionsDialog() +{ + LLFloater *floater = mFloaterPermissionsHandle.get(); + if (!floater) + { + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) + { + LLFloaterProfilePermissions * perms = new LLFloaterProfilePermissions(parent_floater, getAvatarId()); + mFloaterPermissionsHandle = perms->getHandle(); + perms->openFloater(); + perms->setVisibleAndFrontmost(TRUE); + + parent_floater->addDependentFloater(mFloaterPermissionsHandle); + } + } + else // already open + { + floater->setMinimized(FALSE); + floater->setVisibleAndFrontmost(TRUE); + } +} + +void LLPanelProfileSecondLife::onShowAgentProfileTexture() +{ + if (!getIsLoaded()) + { + return; + } + + LLFloater *floater = mFloaterProfileTextureHandle.get(); + if (!floater) + { + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) + { + LLFloaterProfileTexture * texture_view = new LLFloaterProfileTexture(parent_floater); + mFloaterProfileTextureHandle = texture_view->getHandle(); + if (mImageId.notNull()) + { + texture_view->loadAsset(mImageId); + } + else + { + texture_view->resetAsset(); + } + texture_view->openFloater(); + texture_view->setVisibleAndFrontmost(TRUE); + + parent_floater->addDependentFloater(mFloaterProfileTextureHandle); + } + } + else // already open + { + LLFloaterProfileTexture * texture_view = dynamic_cast(floater); + texture_view->setMinimized(FALSE); + texture_view->setVisibleAndFrontmost(TRUE); + if (mImageId.notNull()) + { + texture_view->loadAsset(mImageId); + } + else + { + texture_view->resetAsset(); + } + } +} + +void LLPanelProfileSecondLife::onShowTexturePicker() +{ + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + + // Show the dialog + if (!floaterp) + { + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) + { + // because inventory construction is somewhat slow + getWindow()->setCursor(UI_CURSOR_WAIT); + LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker( + this, + mImageId, + LLUUID::null, + mImageId, + FALSE, + FALSE, + getString("texture_picker_label"), // "SELECT PHOTO", // Fix LL UI/UX design accident + PERM_NONE, + PERM_NONE, + PERM_NONE, + FALSE, + NULL); + + mFloaterTexturePickerHandle = texture_floaterp->getHandle(); + + texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id) + { + if (op == LLTextureCtrl::TEXTURE_SELECT) + { + LLUUID image_asset_id; + LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get(); + if (floaterp) + { + if (id.notNull()) + { + image_asset_id = id; + } + else + { + image_asset_id = floaterp->getAssetID(); + } + } + + onCommitProfileImage(image_asset_id); + } + }); + texture_floaterp->setLocalTextureEnabled(FALSE); + texture_floaterp->setBakeTextureEnabled(FALSE); + texture_floaterp->setCanApply(false, true); + + parent_floater->addDependentFloater(mFloaterTexturePickerHandle); + + texture_floaterp->openFloater(); + texture_floaterp->setFocus(TRUE); + } + } + else + { + floaterp->setMinimized(FALSE); + floaterp->setVisibleAndFrontmost(TRUE); + } +} + +void LLPanelProfileSecondLife::onCommitProfileImage(const LLUUID& id) +{ + if (mImageId == id) + { + return; + } + + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLSD params; + params["sl_image_id"] = id; + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params)); + + mImageId = id; + if (mImageId == LLUUID::null) + { + mSecondLifePic->setValue("Generic_Person_Large"); + } + else + { + mSecondLifePic->setValue(mImageId); + } + + // Fix LL UI/UX design accident + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(mImageId); + if (imagep->getFullHeight()) + { + onImageLoaded(true, imagep); + } + else + { + imagep->setLoadedCallback(onImageLoaded, + MAX_DISCARD_LEVEL, + FALSE, + FALSE, + new LLHandle(getHandle()), + NULL, + FALSE); + } + // + + LLFloater *floater = mFloaterProfileTextureHandle.get(); + if (floater) + { + LLFloaterProfileTexture * texture_view = dynamic_cast(floater); + if (mImageId == LLUUID::null) + { + texture_view->resetAsset(); + } + else + { + texture_view->loadAsset(mImageId); + } + } + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } +} + +// Doesn't exist (anymore) +//void LLPanelProfileSecondLife::onOpenNotes() +//{ +// LLFloater* parent_floater = gFloaterView->getParentFloater(this); +// if (!parent_floater) +// { +// return; +// } +// +// LLTabContainer* tab_container = parent_floater->findChild("panel_profile_tabs", TRUE); +// if (!tab_container) +// { +// return; +// } +// +// tab_container->selectTabByName(PANEL_NOTES); +//} +// + +// RLVa support +void LLPanelProfileSecondLife::updateRlvRestrictions(ERlvBehaviour behavior) +{ + if (behavior == RLV_BHVR_SHOWLOC || behavior == RLV_BHVR_SHOWWORLDMAP) + { + updateButtons(); + } +} +// + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfileWeb + +LLPanelProfileWeb::LLPanelProfileWeb() + : LLPanelProfileTab() + , mWebBrowser(NULL) + , mAvatarNameCacheConnection() +{ +} + +LLPanelProfileWeb::~LLPanelProfileWeb() +{ + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } +} + +void LLPanelProfileWeb::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileWeb::onAvatarNameCache, this, _1, _2)); +} + +BOOL LLPanelProfileWeb::postBuild() +{ + mWebBrowser = getChild("profile_html"); + mWebBrowser->addObserver(this); + mWebBrowser->setHomePageUrl("about:blank"); + + return TRUE; +} + +void LLPanelProfileWeb::resetData() +{ + mWebBrowser->navigateHome(); +} + +void LLPanelProfileWeb::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull() && !mURLWebProfile.empty()) + { + setIsLoading(); + + mWebBrowser->setVisible(TRUE); + mPerformanceTimer.start(); + mWebBrowser->navigateTo(mURLWebProfile, HTTP_CONTENT_TEXT_HTML); + } +} + +void LLPanelProfileWeb::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mAvatarNameCacheConnection.disconnect(); + + std::string username = av_name.getAccountName(); + if (username.empty()) + { + username = LLCacheName::buildUsername(av_name.getDisplayName()); + } + else + { + LLStringUtil::replaceChar(username, ' ', '.'); + } + + mURLWebProfile = getProfileURL(username, true); + if (mURLWebProfile.empty()) + { + return; + } + + //if the tab was opened before name was resolved, load the panel now + updateData(); +} + +void LLPanelProfileWeb::onCommitLoad(LLUICtrl* ctrl) +{ + if (!mURLHome.empty()) + { + LLSD::String valstr = ctrl->getValue().asString(); + if (valstr.empty()) + { + mWebBrowser->setVisible(TRUE); + mPerformanceTimer.start(); + mWebBrowser->navigateTo( mURLHome, HTTP_CONTENT_TEXT_HTML ); + } + else if (valstr == "popout") + { + // open in viewer's browser, new window + LLWeb::loadURLInternal(mURLHome); + } + else if (valstr == "external") + { + // open in external browser + LLWeb::loadURLExternal(mURLHome); + } + } +} + +void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + childSetValue("status_text", LLSD( self->getStatusText() ) ); + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + if (mFirstNavigate) + { + mFirstNavigate = false; + } + else + { + mPerformanceTimer.start(); + } + } + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LLStringUtil::format_map_t args; + args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32()); + childSetValue("status_text", LLSD( getString("LoadTime", args)) ); + } + break; + + default: + // Having a default case makes the compiler happy. + break; + } +} + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileFirstLife::LLPanelProfileFirstLife() + : LLPanelProfileTab() + , mHasUnsavedChanges(false) +{ +} + +LLPanelProfileFirstLife::~LLPanelProfileFirstLife() +{ +} + +BOOL LLPanelProfileFirstLife::postBuild() +{ + mDescriptionEdit = getChild("fl_description_edit"); + mPicture = getChild("real_world_pic"); + + mUploadPhoto = getChild("fl_upload_image"); + mChangePhoto = getChild("fl_change_image"); + mRemovePhoto = getChild("fl_remove_image"); + mSaveChanges = getChild("fl_save_changes"); + mDiscardChanges = getChild("fl_discard_changes"); + + mUploadPhoto->setCommitCallback([this](LLUICtrl*, void*) { onUploadPhoto(); }, nullptr); + mChangePhoto->setCommitCallback([this](LLUICtrl*, void*) { onChangePhoto(); }, nullptr); + mRemovePhoto->setCommitCallback([this](LLUICtrl*, void*) { onRemovePhoto(); }, nullptr); + mSaveChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveDescriptionChanges(); }, nullptr); + mDiscardChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardDescriptionChanges(); }, nullptr); + mDescriptionEdit->setKeystrokeCallback([this](LLTextEditor* caller) { onSetDescriptionDirty(); }); + + return TRUE; +} + +void LLPanelProfileFirstLife::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + if (!getSelfProfile()) + { + // Otherwise as the only focusable element it will be selected + mDescriptionEdit->setTabStop(FALSE); + } + + resetData(); +} + +void LLPanelProfileFirstLife::setProfileImageUploading(bool loading) +{ + mUploadPhoto->setEnabled(!loading); + mChangePhoto->setEnabled(!loading); + mRemovePhoto->setEnabled(!loading && mImageId.notNull()); + + LLLoadingIndicator* indicator = getChild("image_upload_indicator"); + indicator->setVisible(loading); + if (loading) + { + indicator->start(); + } + else + { + indicator->stop(); + } +} + +void LLPanelProfileFirstLife::setProfileImageUploaded(const LLUUID &image_asset_id) +{ + mPicture->setValue(image_asset_id); + mImageId = image_asset_id; + setProfileImageUploading(false); +} + +void LLPanelProfileFirstLife::commitUnsavedChanges() +{ + if (mHasUnsavedChanges) + { + onSaveDescriptionChanges(); + } +} + +void LLPanelProfileFirstLife::onUploadPhoto() +{ + (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle(getHandle())))->getFile(); + + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + if (floaterp) + { + floaterp->closeFloater(); + } +} + +void LLPanelProfileFirstLife::onChangePhoto() +{ + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + + // Show the dialog + if (!floaterp) + { + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (parent_floater) + { + // because inventory construction is somewhat slow + getWindow()->setCursor(UI_CURSOR_WAIT); + LLFloaterTexturePicker* texture_floaterp = new LLFloaterTexturePicker( + this, + mImageId, + LLUUID::null, + mImageId, + FALSE, + FALSE, + getString("texture_picker_label"), // "SELECT PHOTO", // Fix LL UI/UX design accident + PERM_NONE, + PERM_NONE, + PERM_NONE, + FALSE, + NULL); + + mFloaterTexturePickerHandle = texture_floaterp->getHandle(); + + texture_floaterp->setOnFloaterCommitCallback([this](LLTextureCtrl::ETexturePickOp op, LLUUID id) + { + if (op == LLTextureCtrl::TEXTURE_SELECT) + { + LLUUID image_asset_id; + LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterTexturePickerHandle.get(); + if (floaterp) + { + if (id.notNull()) + { + image_asset_id = id; + } + else + { + image_asset_id = floaterp->getAssetID(); + } + } + + onCommitPhoto(image_asset_id); + } + }); + texture_floaterp->setLocalTextureEnabled(FALSE); + texture_floaterp->setCanApply(false, true); + + parent_floater->addDependentFloater(mFloaterTexturePickerHandle); + + texture_floaterp->openFloater(); + texture_floaterp->setFocus(TRUE); + } + } + else + { + floaterp->setMinimized(FALSE); + floaterp->setVisibleAndFrontmost(TRUE); + } +} + +void LLPanelProfileFirstLife::onRemovePhoto() +{ + onCommitPhoto(LLUUID::null); + + LLFloater* floaterp = mFloaterTexturePickerHandle.get(); + if (floaterp) + { + floaterp->closeFloater(); + } +} + +void LLPanelProfileFirstLife::onCommitPhoto(const LLUUID& id) +{ + if (mImageId == id) + { + return; + } + + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLSD params; + params["fl_image_id"] = id; + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params)); + + mImageId = id; + if (mImageId.notNull()) + { + mPicture->setValue(mImageId); + } + else + { + mPicture->setValue("Generic_Person_Large"); + } + + mRemovePhoto->setEnabled(mImageId.notNull()); + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } +} + +void LLPanelProfileFirstLife::setDescriptionText(const std::string &text) +{ + mSaveChanges->setEnabled(FALSE); + mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; + + mCurrentDescription = text; + mDescriptionEdit->setValue(mCurrentDescription); +} + +void LLPanelProfileFirstLife::onSetDescriptionDirty() +{ + mSaveChanges->setEnabled(TRUE); + mDiscardChanges->setEnabled(TRUE); + mHasUnsavedChanges = true; +} + +void LLPanelProfileFirstLife::onSaveDescriptionChanges() +{ + mCurrentDescription = mDescriptionEdit->getValue().asString(); + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("fl_about_text", mCurrentDescription))); + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } + + mSaveChanges->setEnabled(FALSE); + mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; +} + +void LLPanelProfileFirstLife::onDiscardDescriptionChanges() +{ + setDescriptionText(mCurrentDescription); +} + +void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data) +{ + setDescriptionText(avatar_data->fl_about_text); + + mImageId = avatar_data->fl_image_id; + + if (mImageId.notNull()) + { + mPicture->setValue(mImageId); + } + else + { + mPicture->setValue("Generic_Person_Large"); + } + + setLoaded(); +} + +void LLPanelProfileFirstLife::resetData() +{ + setDescriptionText(std::string()); + mPicture->setValue("Generic_Person_Large"); + mImageId = LLUUID::null; + + mUploadPhoto->setVisible(getSelfProfile()); + mChangePhoto->setVisible(getSelfProfile()); + mRemovePhoto->setVisible(getSelfProfile()); + mSaveChanges->setVisible(getSelfProfile()); + mDiscardChanges->setVisible(getSelfProfile()); +} + +void LLPanelProfileFirstLife::setLoaded() +{ + LLPanelProfileTab::setLoaded(); + + if (getSelfProfile()) + { + mDescriptionEdit->setEnabled(TRUE); + mPicture->setEnabled(TRUE); + mRemovePhoto->setEnabled(mImageId.notNull()); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileNotes::LLPanelProfileNotes() +: LLPanelProfileTab() + , mHasUnsavedChanges(false) +{ + +} + +LLPanelProfileNotes::~LLPanelProfileNotes() +{ +} + +void LLPanelProfileNotes::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); + + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("requestAgentUserInfoCoro", + boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); + } + } +} + +void LLPanelProfileNotes::commitUnsavedChanges() +{ + if (mHasUnsavedChanges) + { + onSaveNotesChanges(); + } +} + +BOOL LLPanelProfileNotes::postBuild() +{ + mNotesEditor = getChild("notes_edit"); + mSaveChanges = getChild("notes_save_changes"); + mDiscardChanges = getChild("notes_discard_changes"); + + mSaveChanges->setCommitCallback([this](LLUICtrl*, void*) { onSaveNotesChanges(); }, nullptr); + mDiscardChanges->setCommitCallback([this](LLUICtrl*, void*) { onDiscardNotesChanges(); }, nullptr); + mNotesEditor->setKeystrokeCallback([this](LLTextEditor* caller) { onSetNotesDirty(); }); + + return TRUE; +} + +void LLPanelProfileNotes::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); +} + +void LLPanelProfileNotes::setNotesText(const std::string &text) +{ + mSaveChanges->setEnabled(FALSE); + mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; + + mCurrentNotes = text; + mNotesEditor->setValue(mCurrentNotes); +} + +void LLPanelProfileNotes::onSetNotesDirty() +{ + mSaveChanges->setEnabled(TRUE); + mDiscardChanges->setEnabled(TRUE); + mHasUnsavedChanges = true; +} + +void LLPanelProfileNotes::onSaveNotesChanges() +{ + mCurrentNotes = mNotesEditor->getValue().asString(); + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("putAgentUserInfoCoro", + boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("notes", mCurrentNotes))); + } + else + { + LL_WARNS("AvatarProperties") << "Failed to update profile data, no cap found" << LL_ENDL; + } + + mSaveChanges->setEnabled(FALSE); + mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; +} + +void LLPanelProfileNotes::onDiscardNotesChanges() +{ + setNotesText(mCurrentNotes); +} + +void LLPanelProfileNotes::processProperties(LLAvatarNotes* avatar_notes) +{ + setNotesText(avatar_notes->notes); + mNotesEditor->setEnabled(TRUE); + setLoaded(); +} + +void LLPanelProfileNotes::resetData() +{ + resetLoading(); + setNotesText(std::string()); +} + +void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLPanelProfileTab::setAvatarId(avatar_id); + } +} + + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfile LLPanelProfile::LLPanelProfile() - : LLPanel() - , mAvatarId(LLUUID::null) + : LLPanelProfileTab() +{ +} + +LLPanelProfile::~LLPanelProfile() { - mChildStack.setParent(this); } BOOL LLPanelProfile::postBuild() { - LLPanelPicks* panel_picks = findChild(PANEL_PICKS); - panel_picks->setProfilePanel(this); - - getTabContainer()[PANEL_PICKS] = panel_picks; - - return TRUE; + return TRUE; } -// virtual -void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent) +void LLPanelProfile::onTabChange() { - // Temporarily add saved children back and reshape them. - mChildStack.preParentReshape(); - LLPanel::reshape(width, height, called_from_parent); - mChildStack.postParentReshape(); + LLPanelProfileTab* active_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (active_panel) + { + active_panel->updateData(); + } } void LLPanelProfile::onOpen(const LLSD& key) { - getTabContainer()[PANEL_PICKS]->onOpen(getAvatarId()); + LLUUID avatar_id = key["id"].asUUID(); - // support commands to open further pieces of UI - if (key.has("show_tab_panel")) - { - std::string panel = key["show_tab_panel"].asString(); - if (panel == "create_classified") - { - LLPanelPicks* picks = dynamic_cast(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewClassified(); - } - } - else if (panel == "classified_details") - { - LLPanelPicks* picks = dynamic_cast(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openClassifiedInfo(params); - } - } - else if (panel == "edit_classified") - { - LLPanelPicks* picks = dynamic_cast(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openClassifiedEdit(params); - } - } - else if (panel == "create_pick") - { - LLPanelPicks* picks = dynamic_cast(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewPick(); - } - } - else if (panel == "edit_pick") - { - LLPanelPicks* picks = dynamic_cast(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openPickEdit(params); - } - } - } + // Don't reload the same profile + if (getAvatarId() == avatar_id) + { + return; + } + + LLPanelProfileTab::onOpen(avatar_id); + + mTabContainer = getChild("panel_profile_tabs"); + mPanelSecondlife = findChild(PANEL_SECONDLIFE); + mPanelWeb = findChild(PANEL_WEB); + mPanelPicks = findChild(PANEL_PICKS); + mPanelClassifieds = findChild(PANEL_CLASSIFIEDS); + mPanelFirstlife = findChild(PANEL_FIRSTLIFE); + mPanelNotes = findChild(PANEL_NOTES); + + mPanelSecondlife->onOpen(avatar_id); + mPanelWeb->onOpen(avatar_id); + mPanelPicks->onOpen(avatar_id); + mPanelClassifieds->onOpen(avatar_id); + mPanelFirstlife->onOpen(avatar_id); + mPanelNotes->onOpen(avatar_id); + + // Always request the base profile info + resetLoading(); + updateData(); + + // Some tabs only request data when opened + mTabContainer->setCommitCallback(boost::bind(&LLPanelProfile::onTabChange, this)); } -void LLPanelProfile::onTabSelected(const LLSD& param) +void LLPanelProfile::updateData() { - std::string tab_name = param.asString(); - if (NULL != getTabContainer()[tab_name]) - { - getTabContainer()[tab_name]->onOpen(getAvatarId()); - } + LLUUID avatar_id = getAvatarId(); + // Todo: getIsloading functionality needs to be expanded to + // include 'inited' or 'data_provided' state to not rerequest + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); + + mPanelSecondlife->setIsLoading(); + mPanelPicks->setIsLoading(); + mPanelFirstlife->setIsLoading(); + mPanelNotes->setIsLoading(); + + std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP); + if (!cap_url.empty()) + { + LLCoros::instance().launch("requestAgentUserInfoCoro", + boost::bind(request_avatar_properties_coro, cap_url, avatar_id)); + } + } } -void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params) +void LLPanelProfile::refreshName() { - // Hide currently visible panel (STORM-690). - mChildStack.push(); - - // Add the panel or bring it to front. - if (panel->getParent() != this) - { - addChild(panel); - } - else - { - sendChildToFront(panel); - } - - panel->setVisible(TRUE); - panel->setFocus(TRUE); // prevent losing focus by the floater - panel->onOpen(params); - - LLRect new_rect = getRect(); - panel->reshape(new_rect.getWidth(), new_rect.getHeight()); - new_rect.setLeftTopAndSize(0, new_rect.getHeight(), new_rect.getWidth(), new_rect.getHeight()); - panel->setRect(new_rect); + mPanelSecondlife->refreshName(); } -void LLPanelProfile::closePanel(LLPanel* panel) +void LLPanelProfile::createPick(const LLPickData &data) { - panel->setVisible(FALSE); - - if (panel->getParent() == this) - { - removeChild(panel); - - // Make the underlying panel visible. - mChildStack.pop(); - - // Prevent losing focus by the floater - const child_list_t* child_list = getChildList(); - if (child_list->size() > 0) - { - child_list->front()->setFocus(TRUE); - } - else - { - LL_WARNS() << "No underlying panel to focus." << LL_ENDL; - } - } + mTabContainer->selectTabPanel(mPanelPicks); + mPanelPicks->createPick(data); } -S32 LLPanelProfile::notifyParent(const LLSD& info) +void LLPanelProfile::showPick(const LLUUID& pick_id) { - std::string action = info["action"]; - // lets update Picks list after Pick was saved - if("save_new_pick" == action) - { - onOpen(info); - return 1; - } - - return LLPanel::notifyParent(info); + if (pick_id.notNull()) + { + mPanelPicks->selectPick(pick_id); + } + mTabContainer->selectTabPanel(mPanelPicks); } + +bool LLPanelProfile::isPickTabSelected() +{ + return (mTabContainer->getCurrentPanel() == mPanelPicks); +} + +bool LLPanelProfile::isNotesTabSelected() +{ + return (mTabContainer->getCurrentPanel() == mPanelNotes); +} + +bool LLPanelProfile::hasUnsavedChanges() +{ + return mPanelSecondlife->hasUnsavedChanges() + || mPanelPicks->hasUnsavedChanges() + || mPanelClassifieds->hasUnsavedChanges() + || mPanelFirstlife->hasUnsavedChanges() + || mPanelNotes->hasUnsavedChanges(); +} + +bool LLPanelProfile::hasUnpublishedClassifieds() +{ + return mPanelClassifieds->hasNewClassifieds(); +} + +void LLPanelProfile::commitUnsavedChanges() +{ + mPanelSecondlife->commitUnsavedChanges(); + mPanelPicks->commitUnsavedChanges(); + mPanelClassifieds->commitUnsavedChanges(); + mPanelFirstlife->commitUnsavedChanges(); + mPanelNotes->commitUnsavedChanges(); +} + +void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit) +{ + if (classified_id.notNull()) + { + mPanelClassifieds->selectClassified(classified_id, edit); + } + mTabContainer->selectTabPanel(mPanelClassifieds); +} + +void LLPanelProfile::createClassified() +{ + mPanelClassifieds->createClassified(); + mTabContainer->selectTabPanel(mPanelClassifieds); +} + diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 63690c0e53..96939dfbac 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -1,25 +1,25 @@ -/** +/** * @file llpanelprofile.h * @brief Profile panel * -* $LicenseInfo:firstyear=2009&license=viewerlgpl$ +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code -* Copyright (C) 2010, Linden Research, Inc. -* +* Copyright (C) 2022, Linden Research, Inc. +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -27,80 +27,411 @@ #ifndef LL_LLPANELPROFILE_H #define LL_LLPANELPROFILE_H +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" +#include "llfloater.h" #include "llpanel.h" #include "llpanelavatar.h" +#include "llmediactrl.h" +#include "llvoiceclient.h" +#include "rlvhandler.h" +// class LLPanelProfileClassifieds; +// class LLTabContainer; + +// class LLPanelProfileSecondLife; +// class LLPanelProfileWeb; +// class LLPanelProfilePicks; +// class LLPanelProfileFirstLife; +// class LLPanelProfileNotes; + +class LLAvatarName; +class LLButton; +class LLCheckBoxCtrl; +class LLComboBox; +class LLIconCtrl; class LLTabContainer; +class LLTextBox; +class LLTextureCtrl; +class LLMediaCtrl; +class LLGroupList; +class LLTextBase; +class LLMenuButton; +class LLLineEditor; +class LLTextEditor; +class LLPanelProfileClassifieds; +class LLPanelProfilePicks; +class LLViewerFetchedTexture; -std::string getProfileURL(const std::string& agent_name); /** -* Base class for Profile View and My Profile. +* Panel for displaying Avatar's second life related info. */ -class LLPanelProfile : public LLPanel +class LLPanelProfileSecondLife + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver { - LOG_CLASS(LLPanelProfile); - public: - /*virtual*/ BOOL postBuild(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void onOpen(const LLSD& key); + LLPanelProfileSecondLife(); + /*virtual*/ ~LLPanelProfileSecondLife(); - virtual void openPanel(LLPanel* panel, const LLSD& params); + void onOpen(const LLSD& key) override; - virtual void closePanel(LLPanel* panel); + /** + * LLFriendObserver trigger + */ + void changed(U32 mask) override; - S32 notifyParent(const LLSD& info); + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + void onChange(EStatusType status, const std::string &channelURI, bool proximal) override; -// [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Added: RVLa-1.2.0f - const LLUUID& getAvatarId() const { return mAvatarId; } -// [/RLVa:KB] + void setAvatarId(const LLUUID& avatar_id) override; + + BOOL postBuild() override; + + void resetData() override; + + /** + * Sends update data request to server. + */ + void updateData() override; + void refreshName(); + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + void setProfileImageUploading(bool loading); + void setProfileImageUploaded(const LLUUID &image_asset_id); + + bool hasUnsavedChanges() override; + void commitUnsavedChanges() override; + + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); protected: + /** + * Process profile related data received from server. + */ + void processProfileProperties(const LLAvatarData* avatar_data); - LLPanelProfile(); + /** + * Processes group related data received from server. + */ + void processGroupProperties(const LLAvatarGroups* avatar_groups); - virtual void onTabSelected(const LLSD& param); + /** + * Fills common for Avatar profile and My Profile fields. + */ + void fillCommonData(const LLAvatarData* avatar_data); -// const LLUUID& getAvatarId() { return mAvatarId; } + /** + * Fills partner data. + */ + void fillPartnerData(const LLAvatarData* avatar_data); - void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } + /** + * Fills account status. + */ + void fillAccountStatus(const LLAvatarData* avatar_data); - typedef std::map profile_tabs_t; + /** + * Sets permissions specific icon + */ + void fillRightsData(); - profile_tabs_t& getTabContainer() { return mTabContainer; } + /** + * Fills user name, display name, age. + */ + void fillAgeData(const LLDate &born_on); + + void onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep); + static void onImageLoaded(BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata); + + /** + * Displays avatar's online status if possible. + * + * Requirements from EXT-3880: + * For friends: + * - Online when online and privacy settings allow to show + * - Offline when offline and privacy settings allow to show + * - Else: nothing + * For other avatars: + * - Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online" + * - Else: Offline + */ + void updateOnlineStatus(); + void processOnlineStatus(bool is_friend, bool show_online, bool online); private: + void setLoaded() override; + void onCommitMenu(const LLSD& userdata); + bool onEnableMenu(const LLSD& userdata); + bool onCheckMenu(const LLSD& userdata); + void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name); - //-- ChildStack begins ---------------------------------------------------- - class ChildStack - { - LOG_CLASS(LLPanelProfile::ChildStack); - public: - ChildStack(); - ~ChildStack(); - void setParent(LLPanel* parent); + void setDescriptionText(const std::string &text); + void onSetDescriptionDirty(); + void onShowInSearchCallback(); + void onSaveDescriptionChanges(); + void onDiscardDescriptionChanges(); + void onShowAgentPermissionsDialog(); + void onShowAgentProfileTexture(); + void onShowTexturePicker(); + void onCommitProfileImage(const LLUUID& id); + //void onOpenNotes(); // Doesn't exist (anymore) - bool push(); - bool pop(); - void preParentReshape(); - void postParentReshape(); + // Fix LL UI/UX design accident + void updateButtons(); - private: - void dump(); +private: + typedef std::map group_map_t; + group_map_t mGroups; + void openGroupProfile(); - typedef LLView::child_list_t view_list_t; - typedef std::list stack_t; + LLTextBox* mStatusText; // Fix LL UI/UX design accident + LLGroupList* mGroupList; + // Fix LL UI/UX design accident + //LLComboBox* mShowInSearchCombo; + LLCheckBoxCtrl* mShowInSearchCheckbox; + // + LLIconCtrl* mSecondLifePic; + LLPanel* mSecondLifePicLayout; + LLTextEditor* mDescriptionEdit; + //LLMenuButton* mAgentActionMenuButton; // Fix LL UI/UX design accident + LLButton* mSaveDescriptionChanges; + LLButton* mDiscardDescriptionChanges; + LLIconCtrl* mCanSeeOnlineIcon; + LLIconCtrl* mCantSeeOnlineIcon; + LLIconCtrl* mCanSeeOnMapIcon; + LLIconCtrl* mCantSeeOnMapIcon; + LLIconCtrl* mCanEditObjectsIcon; + LLIconCtrl* mCantEditObjectsIcon; + // Fix LL UI/UX design accident + LLMenuButton* mCopyMenuButton; + LLButton* mGroupInviteButton; + LLButton* mDisplayNameButton; + LLMenuButton* mImageActionMenuButton; + LLButton* mTeleportButton; + LLButton* mShowOnMapButton; + LLButton* mBlockButton; + LLButton* mUnblockButton; + LLButton* mAddFriendButton; + LLButton* mPayButton; + LLButton* mIMButton; + LLMenuButton* mOverflowButton; + // - stack_t mStack; - stack_t mSavedStack; - LLPanel* mParent; - }; - //-- ChildStack ends ------------------------------------------------------ + LLHandle mFloaterPermissionsHandle; + LLHandle mFloaterProfileTextureHandle; + LLHandle mFloaterTexturePickerHandle; - profile_tabs_t mTabContainer; - ChildStack mChildStack; - LLUUID mAvatarId; + bool mHasUnsavedDescriptionChanges; + bool mVoiceStatus; + bool mWaitingForImageUpload; + bool mAllowPublish; + std::string mDescriptionText; + LLUUID mImageId; + + boost::signals2::connection mAvatarNameCacheConnection; + + // RLVa support + boost::signals2::connection mRlvBehaviorCallbackConnection; + void updateRlvRestrictions(ERlvBehaviour behavior); + // +}; + + +/** +* Panel for displaying Avatar's web profile and home page. +*/ +class LLPanelProfileWeb + : public LLPanelProfileTab + , public LLViewerMediaObserver +{ +public: + LLPanelProfileWeb(); + /*virtual*/ ~LLPanelProfileWeb(); + + void onOpen(const LLSD& key) override; + + BOOL postBuild() override; + + void resetData() override; + + /** + * Loads web profile. + */ + void updateData() override; + + void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override; + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + +protected: + void onCommitLoad(LLUICtrl* ctrl); + +private: + std::string mURLHome; + std::string mURLWebProfile; + LLMediaCtrl* mWebBrowser; + + LLFrameTimer mPerformanceTimer; + bool mFirstNavigate; + + boost::signals2::connection mAvatarNameCacheConnection; +}; + +/** +* Panel for displaying Avatar's first life related info. +*/ +class LLPanelProfileFirstLife + : public LLPanelProfileTab +{ +public: + LLPanelProfileFirstLife(); + /*virtual*/ ~LLPanelProfileFirstLife(); + + void onOpen(const LLSD& key) override; + + BOOL postBuild() override; + + void processProperties(const LLAvatarData* avatar_data); + + void resetData() override; + + void setProfileImageUploading(bool loading); + void setProfileImageUploaded(const LLUUID &image_asset_id); + + bool hasUnsavedChanges() override { return mHasUnsavedChanges; } + void commitUnsavedChanges() override; + + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + +protected: + void setLoaded() override; + + void onUploadPhoto(); + void onChangePhoto(); + void onRemovePhoto(); + void onCommitPhoto(const LLUUID& id); + void setDescriptionText(const std::string &text); + void onSetDescriptionDirty(); + void onSaveDescriptionChanges(); + void onDiscardDescriptionChanges(); + + LLTextEditor* mDescriptionEdit; + LLIconCtrl* mPicture; + LLButton* mUploadPhoto; + LLButton* mChangePhoto; + LLButton* mRemovePhoto; + LLButton* mSaveChanges; + LLButton* mDiscardChanges; + + LLHandle mFloaterTexturePickerHandle; + + std::string mCurrentDescription; + LLUUID mImageId; + bool mHasUnsavedChanges; +}; + +/** + * Panel for displaying Avatar's notes and modifying friend's rights. + */ +class LLPanelProfileNotes + : public LLPanelProfileTab +{ +public: + LLPanelProfileNotes(); + /*virtual*/ ~LLPanelProfileNotes(); + + void setAvatarId(const LLUUID& avatar_id) override; + + void onOpen(const LLSD& key) override; + + BOOL postBuild() override; + + void processProperties(LLAvatarNotes* avatar_notes); + + void resetData() override; + + void updateData() override; + + bool hasUnsavedChanges() override { return mHasUnsavedChanges; } + void commitUnsavedChanges() override; + +protected: + void setNotesText(const std::string &text); + void onSetNotesDirty(); + void onSaveNotesChanges(); + void onDiscardNotesChanges(); + + LLTextEditor* mNotesEditor; + LLButton* mSaveChanges; + LLButton* mDiscardChanges; + + std::string mCurrentNotes; + bool mHasUnsavedChanges; +}; + + +/** +* Container panel for the profile tabs +*/ +class LLPanelProfile + : public LLPanelProfileTab +{ +public: + LLPanelProfile(); + /*virtual*/ ~LLPanelProfile(); + + BOOL postBuild() override; + + void updateData() override; + void refreshName(); + + void onOpen(const LLSD& key) override; + + void createPick(const LLPickData &data); + void showPick(const LLUUID& pick_id = LLUUID::null); + bool isPickTabSelected(); + bool isNotesTabSelected(); + bool hasUnsavedChanges() override; + bool hasUnpublishedClassifieds(); + void commitUnsavedChanges() override; + + void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); + void createClassified(); + + LLAvatarData getAvatarData() { return mAvatarData; }; + + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + +private: + void onTabChange(); + + LLPanelProfileSecondLife* mPanelSecondlife; + LLPanelProfileWeb* mPanelWeb; + LLPanelProfilePicks* mPanelPicks; + LLPanelProfileClassifieds* mPanelClassifieds; + LLPanelProfileFirstLife* mPanelFirstlife; + LLPanelProfileNotes* mPanelNotes; + LLTabContainer* mTabContainer; + + // Todo: due to server taking minutes to update this needs a more long term storage + // to reuse recently saved values if user opens floater again + // Storage implementation depends onto how a cap will be implemented, if cap will be + // enought to fully update LLAvatarPropertiesProcessor, then this storage can be + // implemented there. + LLAvatarData mAvatarData; }; #endif //LL_LLPANELPROFILE_H diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp new file mode 100644 index 0000000000..aa58ba08d9 --- /dev/null +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -0,0 +1,1570 @@ +/** + * @file llpanelprofileclassifieds.cpp + * @brief LLPanelProfileClassifieds and related class implementations + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelprofileclassifieds.h" + +#include "llagent.h" +#include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedflags.h" +#include "llcombobox.h" +#include "llcommandhandler.h" // for classified HTML detail page click tracking +#include "llcorehttputil.h" +#include "lldispatcher.h" +#include "llfloaterclassified.h" +#include "llfloaterreg.h" +#include "llfloatersidepanelcontainer.h" +#include "llfloaterworldmap.h" +#include "lliconctrl.h" +#include "lllineeditor.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llpanelavatar.h" +#include "llparcel.h" +#include "llregistry.h" +#include "llscrollcontainer.h" +#include "llstartup.h" +#include "llstatusbar.h" +#include "lltabcontainer.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewertexture.h" + +#ifdef OPENSIM +#include "llviewernetwork.h" +#endif // OPENSIM + +//*TODO: verify this limit +const S32 MAX_AVATAR_CLASSIFIEDS = 100; + +const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ +const S32 DEFAULT_EDIT_CLASSIFIED_SCROLL_HEIGHT = 530; + +//static +LLPanelProfileClassified::panel_list_t LLPanelProfileClassified::sAllPanels; + +static LLPanelInjector t_panel_profile_classifieds("panel_profile_classifieds"); +static LLPanelInjector t_panel_profile_classified("panel_profile_classified"); + +class LLClassifiedHandler : public LLCommandHandler, public LLAvatarPropertiesObserver +{ +public: + // throttle calls from untrusted browsers + LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {} + + std::set mClassifiedIds; + std::string mRequestVerb; + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + if (LLStartUp::getStartupState() < STATE_STARTED) + { + return true; + } + + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds")) + { + LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + // handle app/classified/create urls first + if (params.size() == 1 && params[0].asString() == "create") + { + LLAvatarActions::createClassified(); + return true; + } + + // then handle the general app/classified/{UUID}/{CMD} urls + if (params.size() < 2) + { + return false; + } + + // get the ID for the classified + LLUUID classified_id; + if (!classified_id.set(params[0], FALSE)) + { + return false; + } + + // show the classified in the side tray. + // need to ask the server for more info first though... + const std::string verb = params[1].asString(); + if (verb == "about") + { + mRequestVerb = verb; + mClassifiedIds.insert(classified_id); + LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); + return true; + } + else if (verb == "edit") + { + LLAvatarActions::showClassified(gAgent.getID(), classified_id, true); + return true; + } + + return false; + } + + void openClassified(LLAvatarClassifiedInfo* c_info) + { + if (mRequestVerb == "about") + { + if (c_info->creator_id == gAgent.getID()) + { + LLAvatarActions::showClassified(gAgent.getID(), c_info->classified_id, false); + } + else + { + LLSD params; + params["id"] = c_info->creator_id; + params["classified_id"] = c_info->classified_id; + params["classified_creator_id"] = c_info->creator_id; + params["classified_snapshot_id"] = c_info->snapshot_id; + params["classified_name"] = c_info->name; + params["classified_desc"] = c_info->description; + params["from_search"] = true; + + LLFloaterClassified* floaterp = LLFloaterReg::getTypedInstance("classified", params); + if (floaterp) + { + floaterp->openFloater(params); + floaterp->setVisibleAndFrontmost(); + } + } + } + } + + void processProperties(void* data, EAvatarProcessorType type) + { + if (APT_CLASSIFIED_INFO != type) + { + return; + } + + // is this the classified that we asked for? + LLAvatarClassifiedInfo* c_info = static_cast(data); + if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end()) + { + return; + } + + // open the detail side tray for this classified + openClassified(c_info); + + // remove our observer now that we're done + mClassifiedIds.erase(c_info->classified_id); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); + } +}; +LLClassifiedHandler gClassifiedHandler; + +////////////////////////////////////////////////////////////////////////// + + +//----------------------------------------------------------------------------- +// LLPanelProfileClassifieds +//----------------------------------------------------------------------------- + +LLPanelProfileClassifieds::LLPanelProfileClassifieds() + : LLPanelProfilePropertiesProcessorTab() + , mClassifiedToSelectOnLoad(LLUUID::null) + , mClassifiedEditOnLoad(false) + , mSheduledClassifiedCreation(false) + , mRlvBehaviorCallbackConnection() // RLVa support +{ +} + +LLPanelProfileClassifieds::~LLPanelProfileClassifieds() +{ + // RLVa support + if (mRlvBehaviorCallbackConnection.connected()) + { + mRlvBehaviorCallbackConnection.disconnect(); + } + // +} + +void LLPanelProfileClassifieds::onOpen(const LLSD& key) +{ + LLPanelProfilePropertiesProcessorTab::onOpen(key); + + resetData(); + + bool own_profile = getSelfProfile(); + if (own_profile) + { + mNewButton->setVisible(TRUE); + mNewButton->setEnabled(FALSE); + + mDeleteButton->setVisible(TRUE); + mDeleteButton->setEnabled(FALSE); + } + + childSetVisible("buttons_header", own_profile); + +} + +void LLPanelProfileClassifieds::selectClassified(const LLUUID& classified_id, bool edit) +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel) + { + if (classified_panel->getClassifiedId() == classified_id) + { + mTabContainer->selectTabPanel(classified_panel); + if (edit) + { + classified_panel->setEditMode(TRUE); + } + break; + } + } + } + } + else + { + mClassifiedToSelectOnLoad = classified_id; + mClassifiedEditOnLoad = edit; + } +} + +void LLPanelProfileClassifieds::createClassified() +{ + if (getIsLoaded()) + { + mNoItemsLabel->setVisible(FALSE); + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + classified_panel->onOpen(LLSD()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(true). + label(classified_panel->getClassifiedName())); + updateButtons(); + } + else + { + mSheduledClassifiedCreation = true; + } +} + +BOOL LLPanelProfileClassifieds::postBuild() +{ + mTabContainer = getChild("tab_classifieds"); + mNoItemsLabel = getChild("classifieds_panel_text"); + mNewButton = getChild("new_btn"); + mDeleteButton = getChild("delete_btn"); + + mNewButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickNewBtn, this)); + mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickDelete, this)); + + // RLVa support + mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&LLPanelProfileClassifieds::updateRlvRestrictions, this, _1, _2)); + // + + return TRUE; +} + +void LLPanelProfileClassifieds::onClickNewBtn() +{ + mNoItemsLabel->setVisible(FALSE); + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + classified_panel->onOpen(LLSD()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(true). + label(classified_panel->getClassifiedName())); + updateButtons(); +} + +void LLPanelProfileClassifieds::onClickDelete() +{ + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (classified_panel) + { + LLUUID classified_id = classified_panel->getClassifiedId(); + LLSD args; + args["CLASSIFIED"] = classified_panel->getClassifiedName(); + LLSD payload; + payload["classified_id"] = classified_id; + payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); + LLNotificationsUtil::add("ProfileDeleteClassified", args, payload, + boost::bind(&LLPanelProfileClassifieds::callbackDeleteClassified, this, _1, _2)); + } +} + +void LLPanelProfileClassifieds::callbackDeleteClassified(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + LLUUID classified_id = notification["payload"]["classified_id"].asUUID(); + S32 tab_idx = notification["payload"]["tab_idx"].asInteger(); + + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->getClassifiedId() == classified_id) + { + mTabContainer->removeTabPanel(classified_panel); + } + + if (classified_id.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(classified_id); + } + + updateButtons(); + + BOOL no_data = !mTabContainer->getTabCount(); + mNoItemsLabel->setVisible(no_data); + } +} + +void LLPanelProfileClassifieds::processProperties(void* data, EAvatarProcessorType type) +{ + if ((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type)) + { + LLUUID avatar_id = getAvatarId(); + + LLAvatarClassifieds* c_info = static_cast(data); + if (c_info && getAvatarId() == c_info->target_id) + { + // do not clear classified list in case we will receive two or more data packets. + // list has been cleared in updateData(). (fix for EXT-6436) + LLUUID selected_id = mClassifiedToSelectOnLoad; + bool has_selection = false; + + LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin(); + for (; c_info->classifieds_list.end() != it; ++it) + { + LLAvatarClassifieds::classified_data c_data = *it; + + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + + LLSD params; + params["classified_creator_id"] = avatar_id; + params["classified_id"] = c_data.classified_id; + params["classified_name"] = c_data.name; + params["from_search"] = (selected_id == c_data.classified_id); //SLURL handling and stats tracking + params["edit"] = (selected_id == c_data.classified_id) && mClassifiedEditOnLoad; + classified_panel->onOpen(params); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(selected_id == c_data.classified_id). + label(c_data.name)); + + if (selected_id == c_data.classified_id) + { + has_selection = true; + } + } + + if (mSheduledClassifiedCreation) + { + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + classified_panel->onOpen(LLSD()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(!has_selection). + label(classified_panel->getClassifiedName())); + has_selection = true; + } + + // reset 'do on load' values + mClassifiedToSelectOnLoad = LLUUID::null; + mClassifiedEditOnLoad = false; + mSheduledClassifiedCreation = false; + + // set even if not visible, user might delete own + // calassified and this string will need to be shown + if (getSelfProfile()) + { + mNoItemsLabel->setValue(LLTrans::getString("NoClassifiedsText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarClassifiedsText")); + } + + bool has_data = mTabContainer->getTabCount() > 0; + mNoItemsLabel->setVisible(!has_data); + if (has_data && !has_selection) + { + mTabContainer->selectFirstTab(); + } + + setLoaded(); + updateButtons(); + } + } +} + +void LLPanelProfileClassifieds::resetData() +{ + resetLoading(); + mTabContainer->deleteAllTabs(); +} + +void LLPanelProfileClassifieds::updateButtons() +{ + if (getSelfProfile()) + { + // RLVa support + //mNewButton->setEnabled(canAddNewClassified()); + mNewButton->setEnabled(canAddNewClassified() && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + // + mDeleteButton->setEnabled(canDeleteClassified()); + } +} + +void LLPanelProfileClassifieds::updateData() +{ + // Send picks request only once + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); + mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); + mNoItemsLabel->setVisible(TRUE); + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(avatar_id); + } +} + +bool LLPanelProfileClassifieds::hasNewClassifieds() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->isNew()) + { + return true; + } + } + return false; +} + +bool LLPanelProfileClassifieds::hasUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->isDirty()) // includes 'new' + { + return true; + } + } + return false; +} + +bool LLPanelProfileClassifieds::canAddNewClassified() +{ + return (mTabContainer->getTabCount() < MAX_AVATAR_CLASSIFIEDS); +} + +bool LLPanelProfileClassifieds::canDeleteClassified() +{ + return (mTabContainer->getTabCount() > 0); +} + +void LLPanelProfileClassifieds::commitUnsavedChanges() +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->isDirty() && !classified_panel->isNew()) + { + classified_panel->doSave(); + } + } + } +} + +// RLVa support +void LLPanelProfileClassifieds::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) +{ + if (behavior == RLV_BHVR_SHOWLOC) + { + updateButtons(); + } +} +// RLV support + +//----------------------------------------------------------------------------- +// LLDispatchClassifiedClickThrough +//----------------------------------------------------------------------------- + +// "classifiedclickthrough" +// strings[0] = classified_id +// strings[1] = teleport_clicks +// strings[2] = map_clicks +// strings[3] = profile_clicks +class LLDispatchClassifiedClickThrough : public LLDispatchHandler +{ +public: + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) + { + if (strings.size() != 4) return false; + LLUUID classified_id(strings[0]); + S32 teleport_clicks = atoi(strings[1].c_str()); + S32 map_clicks = atoi(strings[2].c_str()); + S32 profile_clicks = atoi(strings[3].c_str()); + + LLPanelProfileClassified::setClickThrough( + classified_id, teleport_clicks, map_clicks, profile_clicks, false); + + return true; + } +}; +static LLDispatchClassifiedClickThrough sClassifiedClickThrough; + + +//----------------------------------------------------------------------------- +// LLPanelProfileClassified +//----------------------------------------------------------------------------- + +static const S32 CB_ITEM_MATURE = 0; +static const S32 CB_ITEM_PG = 1; + +LLPanelProfileClassified::LLPanelProfileClassified() + : LLPanelProfilePropertiesProcessorTab() + , mInfoLoaded(false) + , mTeleportClicksOld(0) + , mMapClicksOld(0) + , mProfileClicksOld(0) + , mTeleportClicksNew(0) + , mMapClicksNew(0) + , mProfileClicksNew(0) + , mPriceForListing(0) + , mSnapshotCtrl(NULL) + , mPublishFloater(NULL) + , mIsNew(false) + , mIsNewWithErrors(false) + , mCanClose(false) + , mEditMode(false) + , mEditOnLoad(false) +{ + sAllPanels.push_back(this); +} + +LLPanelProfileClassified::~LLPanelProfileClassified() +{ + sAllPanels.remove(this); + gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler + + // [SL:KB] - Patch : UI-ProfileGroupFloater | Checked: 2010-11-28 (Catznip-2.4.0g) | Added: Catznip-2.4.0g + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } +// [/SL:KB] +} + +//static +LLPanelProfileClassified* LLPanelProfileClassified::create() +{ + LLPanelProfileClassified* panel = new LLPanelProfileClassified(); + panel->buildFromFile("panel_profile_classified.xml"); + return panel; +} + +BOOL LLPanelProfileClassified::postBuild() +{ + mScrollContainer = getChild("profile_scroll"); + mInfoPanel = getChild("info_panel"); + mInfoScroll = getChild("info_scroll_content_panel"); + mEditPanel = getChild("edit_panel"); + + mSnapshotCtrl = getChild("classified_snapshot"); + mEditIcon = getChild("edit_icon"); + + //info + mClassifiedNameText = getChild("classified_name"); + mClassifiedDescText = getChild("classified_desc"); + mLocationText = getChild("classified_location"); + mCategoryText = getChild("category"); + mContentTypeText = getChild("content_type"); + mContentTypeM = getChild("content_type_moderate"); + mContentTypeG = getChild("content_type_general"); + mPriceText = getChild("price_for_listing"); + mAutoRenewText = getChild("auto_renew"); + + mMapButton = getChild("show_on_map_btn"); + mTeleportButton = getChild("teleport_btn"); + mEditButton = getChild("edit_btn"); + + //edit + mClassifiedNameEdit = getChild("classified_name_edit"); + mClassifiedDescEdit = getChild("classified_desc_edit"); + mLocationEdit = getChild("classified_location_edit"); + mCategoryCombo = getChild("category_edit"); + mContentTypeCombo = getChild("content_type_edit"); + mAutoRenewEdit = getChild("auto_renew_edit"); + + mSaveButton = getChild("save_changes_btn"); + mSetLocationButton = getChild("set_to_curr_location_btn"); + mCancelButton = getChild("cancel_btn"); + + mUtilityBtnCnt = getChild("util_buttons_lp"); + mPublishBtnsCnt = getChild("publish_layout_panel"); + mCancelBtnCnt = getChild("cancel_btn_lp"); + mSaveBtnCnt = getChild("save_btn_lp"); + + mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelProfileClassified::onTextureSelected, this)); + mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseEnter, this)); + mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseLeave, this)); + mEditIcon->setVisible(false); + + mMapButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onMapClick, this)); + mTeleportButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onTeleportClick, this)); + mEditButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onEditClick, this)); + mSaveButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSaveClick, this)); + mSetLocationButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSetLocationClick, this)); + mCancelButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onCancelClick, this)); + + LLClassifiedInfo::cat_map::iterator iter; + for (iter = LLClassifiedInfo::sCategories.begin(); + iter != LLClassifiedInfo::sCategories.end(); + iter++) + { + mCategoryCombo->add(LLTrans::getString(iter->second)); + } + + mClassifiedNameEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this), NULL); + mClassifiedDescEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mCategoryCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mContentTypeCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mAutoRenewEdit->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + + return TRUE; +} + +void LLPanelProfileClassified::onOpen(const LLSD& key) +{ + mIsNew = key.isUndefined(); + + resetData(); + resetControls(); + scrollToTop(); + + // classified is not created yet + bool is_new = isNew() || isNewWithErrors(); + + if(is_new) + { + LLPanelProfilePropertiesProcessorTab::setAvatarId(gAgent.getID()); + + setPosGlobal(gAgent.getPositionGlobal()); + + LLUUID snapshot_id = LLUUID::null; + std::string desc; + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + desc = parcel->getDesc(); + snapshot_id = parcel->getSnapshotID(); + } + + std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setClassifiedName(makeClassifiedName()); + setDescription(desc); + setSnapshotId(snapshot_id); + setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); + // server will set valid parcel id + setParcelId(LLUUID::null); + + mSaveButton->setLabelArg("[LABEL]", getString("publish_label")); + + setEditMode(TRUE); + enableSave(true); + enableEditing(true); + resetDirty(); + setInfoLoaded(false); + } + else + { + LLUUID avatar_id = key["classified_creator_id"]; + if(avatar_id.isNull()) + { + return; + } + LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); + + setClassifiedId(key["classified_id"]); + setClassifiedName(key["classified_name"]); + setFromSearch(key["from_search"]); + mEditOnLoad = key["edit"]; + + LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; + + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + + gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); + + if (gAgent.getRegion()) + { + // While we're at it let's get the stats from the new table if that + // capability exists. + std::string url = gAgent.getRegion()->getCapability("SearchStatRequest"); + if (!url.empty()) + { + LL_INFOS() << "Classified stat request via capability" << LL_ENDL; + LLSD body; + LLUUID classifiedId = getClassifiedId(); + body["classified_id"] = classifiedId; + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, + boost::bind(&LLPanelProfileClassified::handleSearchStatResponse, classifiedId, _1)); + } + } + // Update classified click stats. + // *TODO: Should we do this when opening not from search? + if (!fromSearch() ) + { + sendClickMessage("profile"); + } + + setInfoLoaded(false); + } + + + bool is_self = getSelfProfile(); + getChildView("auto_renew_layout_panel")->setVisible(is_self); + getChildView("clickthrough_layout_panel")->setVisible(is_self); + + updateButtons(); +} + +void LLPanelProfileClassified::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_CLASSIFIED_INFO != type) + { + return; + } + + LLAvatarClassifiedInfo* c_info = static_cast(data); + if(c_info && getClassifiedId() == c_info->classified_id) + { + // see LLPanelProfileClassified::sendUpdate() for notes + if (mIsNewWithErrors) + { + // We just published it + setEditMode(FALSE); + } + mIsNewWithErrors = false; + mIsNew = false; + + setClassifiedName(c_info->name); + setDescription(c_info->description); + setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); + setPosGlobal(c_info->pos_global); + setSimName(c_info->sim_name); + + setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); + + mCategoryText->setValue(LLClassifiedInfo::sCategories[c_info->category]); + // *HACK see LLPanelProfileClassified::sendUpdate() + setCategory(c_info->category - 1); + + bool mature = is_cf_mature(c_info->flags); + setContentType(mature); + + bool auto_renew = is_cf_auto_renew(c_info->flags); + std::string auto_renew_str = auto_renew ? getString("auto_renew_on") : getString("auto_renew_off"); + mAutoRenewText->setValue(auto_renew_str); + mAutoRenewEdit->setValue(auto_renew); + + static LLUIString price_str = getString("l$_price"); + price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); + mPriceText->setValue(LLSD(price_str)); + + static std::string date_fmt = getString("date_fmt"); + std::string date_str = date_fmt; + LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); + getChild("creation_date")->setValue(date_str); + + resetDirty(); + setInfoLoaded(true); + enableSave(false); + enableEditing(true); + + // for just created classified - in case user opened edit panel before processProperties() callback + mSaveButton->setLabelArg("[LABEL]", getString("save_label")); + + setLoaded(); + updateButtons(); + + if (mEditOnLoad) + { + setEditMode(TRUE); + } + } + +} + +void LLPanelProfileClassified::setEditMode(BOOL edit_mode) +{ + mEditMode = edit_mode; + + mInfoPanel->setVisible(!edit_mode); + mEditPanel->setVisible(edit_mode); + + // snapshot control is common between info and edit, + // enable it only when in edit mode + mSnapshotCtrl->setEnabled(edit_mode); + + scrollToTop(); + updateButtons(); + updateInfoRect(); +} + +void LLPanelProfileClassified::updateButtons() +{ + bool edit_mode = getEditMode(); + mUtilityBtnCnt->setVisible(!edit_mode); + + // cancel button should either delete unpublished + // classified or not be there at all + mCancelBtnCnt->setVisible(edit_mode && !mIsNew); + mPublishBtnsCnt->setVisible(edit_mode); + mSaveBtnCnt->setVisible(edit_mode); + mEditButton->setVisible(!edit_mode && getSelfProfile()); +} + +void LLPanelProfileClassified::updateInfoRect() +{ + if (getEditMode()) + { + // info_scroll_content_panel contains both info and edit panel + // info panel can be very large and scroll bar will carry over. + // Resize info panel to prevent scroll carry over when in edit mode. + mInfoScroll->reshape(mInfoScroll->getRect().getWidth(), DEFAULT_EDIT_CLASSIFIED_SCROLL_HEIGHT, FALSE); + } + else + { + // Adjust text height to make description scrollable. + S32 new_height = mClassifiedDescText->getTextBoundingRect().getHeight(); + LLRect visible_rect = mClassifiedDescText->getVisibleDocumentRect(); + S32 delta_height = new_height - visible_rect.getHeight() + 5; + + LLRect rect = mInfoScroll->getRect(); + mInfoScroll->reshape(rect.getWidth(), rect.getHeight() + delta_height, FALSE); + } +} + +void LLPanelProfileClassified::enableEditing(bool enable) +{ + mEditButton->setEnabled(enable); + mClassifiedNameEdit->setEnabled(enable); + mClassifiedDescEdit->setEnabled(enable); + mSetLocationButton->setEnabled(enable); + mCategoryCombo->setEnabled(enable); + mContentTypeCombo->setEnabled(enable); + mAutoRenewEdit->setEnabled(enable); +} + +void LLPanelProfileClassified::resetControls() +{ + updateButtons(); + + mCategoryCombo->setCurrentByIndex(0); + mContentTypeCombo->setCurrentByIndex(0); + mAutoRenewEdit->setValue(false); + // FIRE-9814 - Don't hardcode a classified listing fee + //mPriceForListing = MINIMUM_PRICE_FOR_LISTING; + mPriceForListing = getClassifiedFee(); + // +} + +// FIRE-9814 - Don't hardcode a classified listing fee +S32 LLPanelProfileClassified::getClassifiedFee() +{ + S32 fee = MINIMUM_PRICE_FOR_LISTING; +#ifdef OPENSIM + if (LLGridManager::getInstance()->isInOpenSim()) + { + fee = LLGridManager::getInstance()->getClassifiedFee(); + } +#endif // OPENSIM + return fee; +} +// + +void LLPanelProfileClassified::onEditClick() +{ + setEditMode(TRUE); +} + +void LLPanelProfileClassified::onCancelClick() +{ + if (isNew()) + { + mClassifiedNameEdit->setValue(mClassifiedNameText->getValue()); + mClassifiedDescEdit->setValue(mClassifiedDescText->getValue()); + mLocationEdit->setValue(mLocationText->getValue()); + mCategoryCombo->setCurrentByIndex(0); + mContentTypeCombo->setCurrentByIndex(0); + mAutoRenewEdit->setValue(false); + // FIRE-9814 - Don't hardcode a classified listing fee + //mPriceForListing = MINIMUM_PRICE_FOR_LISTING; + mPriceForListing = getClassifiedFee(); + // + } + else + { + // Reload data to undo changes to forms + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + } + + setInfoLoaded(false); + + setEditMode(FALSE); +} + +void LLPanelProfileClassified::onSaveClick() +{ + mCanClose = false; + + if(!isValidName()) + { + notifyInvalidName(); + return; + } + if(isNew() || isNewWithErrors()) + { + if(gStatusBar->getBalance() < getPriceForListing()) + { + LLNotificationsUtil::add("ClassifiedInsufficientFunds"); + return; + } + + mPublishFloater = LLFloaterReg::findTypedInstance( + "publish_classified", LLSD()); + + if(!mPublishFloater) + { + mPublishFloater = LLFloaterReg::getTypedInstance( + "publish_classified", LLSD()); + + mPublishFloater->setPublishClickedCallback(boost::bind + (&LLPanelProfileClassified::onPublishFloaterPublishClicked, this)); + } + + // set spinner value before it has focus or value wont be set + mPublishFloater->setPrice(getPriceForListing()); + mPublishFloater->openFloater(mPublishFloater->getKey()); + mPublishFloater->center(); + } + else + { + doSave(); + } +} + +/*static*/ +void LLPanelProfileClassified::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ + S32 teleport = result["teleport_clicks"].asInteger(); + S32 map = result["map_clicks"].asInteger(); + S32 profile = result["profile_clicks"].asInteger(); + S32 search_teleport = result["search_teleport_clicks"].asInteger(); + S32 search_map = result["search_map_clicks"].asInteger(); + S32 search_profile = result["search_profile_clicks"].asInteger(); + + LLPanelProfileClassified::setClickThrough(classifiedId, + teleport + search_teleport, + map + search_map, + profile + search_profile, + true); +} + +void LLPanelProfileClassified::resetData() +{ + setClassifiedName(LLStringUtil::null); + setDescription(LLStringUtil::null); + setClassifiedLocation(LLStringUtil::null); + setClassifiedId(LLUUID::null); + setSnapshotId(LLUUID::null); + setPosGlobal(LLVector3d::zero); + setParcelId(LLUUID::null); + setSimName(LLStringUtil::null); + setFromSearch(false); + + // reset click stats + mTeleportClicksOld = 0; + mMapClicksOld = 0; + mProfileClicksOld = 0; + mTeleportClicksNew = 0; + mMapClicksNew = 0; + mProfileClicksNew = 0; + + // FIRE-9814 - Don't hardcode a classified listing fee + //mPriceForListing = MINIMUM_PRICE_FOR_LISTING; + mPriceForListing = getClassifiedFee(); + // + + mCategoryText->setValue(LLStringUtil::null); + mContentTypeText->setValue(LLStringUtil::null); + getChild("click_through_text")->setValue(LLStringUtil::null); + mEditButton->setValue(LLStringUtil::null); + getChild("creation_date")->setValue(LLStringUtil::null); + mContentTypeM->setVisible(FALSE); + mContentTypeG->setVisible(FALSE); +} + +void LLPanelProfileClassified::setClassifiedName(const std::string& name) +{ + mClassifiedNameText->setValue(name); + mClassifiedNameEdit->setValue(name); +} + +std::string LLPanelProfileClassified::getClassifiedName() +{ + return mClassifiedNameEdit->getValue().asString(); +} + +void LLPanelProfileClassified::setDescription(const std::string& desc) +{ + mClassifiedDescText->setValue(desc); + mClassifiedDescEdit->setValue(desc); + + updateInfoRect(); +} + +std::string LLPanelProfileClassified::getDescription() +{ + return mClassifiedDescEdit->getValue().asString(); +} + +void LLPanelProfileClassified::setClassifiedLocation(const std::string& location) +{ + mLocationText->setValue(location); + mLocationEdit->setValue(location); +} + +std::string LLPanelProfileClassified::getClassifiedLocation() +{ + return mLocationText->getValue().asString(); +} + +void LLPanelProfileClassified::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setValue(id); +} + +LLUUID LLPanelProfileClassified::getSnapshotId() +{ + return mSnapshotCtrl->getValue().asUUID(); +} + +// static +void LLPanelProfileClassified::setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table) +{ + LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: [" + << teleport << ", " << map << ", " << profile << "] (" + << (from_new_table ? "new" : "old") << ")" << LL_ENDL; + + for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + { + LLPanelProfileClassified* self = *iter; + if (self->getClassifiedId() != classified_id) + { + continue; + } + + // *HACK: Skip LLPanelProfileClassified instances: they don't display clicks data. + // Those instances should not be in the list at all. + if (typeid(*self) != typeid(LLPanelProfileClassified)) + { + continue; + } + + LL_INFOS() << "Updating classified info panel" << LL_ENDL; + + // We need to check to see if the data came from the new stat_table + // or the old classified table. We also need to cache the data from + // the two separate sources so as to display the aggregate totals. + + if (from_new_table) + { + self->mTeleportClicksNew = teleport; + self->mMapClicksNew = map; + self->mProfileClicksNew = profile; + } + else + { + self->mTeleportClicksOld = teleport; + self->mMapClicksOld = map; + self->mProfileClicksOld = profile; + } + + static LLUIString ct_str = self->getString("click_through_text_fmt"); + + ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); + ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); + ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); + + self->getChild("click_through_text")->setValue(ct_str.getString()); + // *HACK: remove this when there is enough room for click stats in the info panel + self->getChildView("click_through_text")->setToolTip(ct_str.getString()); + + LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) + << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) + << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) + << LL_ENDL; + } +} + +// static +std::string LLPanelProfileClassified::createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global) +{ + std::string location_text; + + location_text.append(original_name); + + if (!sim_name.empty()) + { + if (!location_text.empty()) + location_text.append(", "); + location_text.append(sim_name); + } + + if (!location_text.empty()) + location_text.append(" "); + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + + return location_text; +} + +void LLPanelProfileClassified::scrollToTop() +{ + if (mScrollContainer) + { + mScrollContainer->goToTop(); + } +} + +//info +// static +// *TODO: move out of the panel +void LLPanelProfileClassified::sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name) +{ + if (gAgent.getRegion()) + { + // You're allowed to click on your own ads to reassure yourself + // that the system is working. + LLSD body; + body["type"] = type; + body["from_search"] = from_search; + body["classified_id"] = classified_id; + body["parcel_id"] = parcel_id; + body["dest_pos_global"] = global_pos.getValue(); + body["region_name"] = sim_name; + + std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); + LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; + LL_INFOS() << "body: [" << body << "]" << LL_ENDL; + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); + } +} + +void LLPanelProfileClassified::sendClickMessage(const std::string& type) +{ + sendClickMessage( + type, + fromSearch(), + getClassifiedId(), + getParcelId(), + getPosGlobal(), + getSimName()); +} + +void LLPanelProfileClassified::onMapClick() +{ + sendClickMessage("map"); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelProfileClassified::onTeleportClick() +{ + if (!getPosGlobal().isExactlyZero()) + { + sendClickMessage("teleport"); + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +BOOL LLPanelProfileClassified::isDirty() const +{ + if(mIsNew) + { + return TRUE; + } + + BOOL dirty = false; + dirty |= mSnapshotCtrl->isDirty(); + dirty |= mClassifiedNameEdit->isDirty(); + dirty |= mClassifiedDescEdit->isDirty(); + dirty |= mCategoryCombo->isDirty(); + dirty |= mContentTypeCombo->isDirty(); + dirty |= mAutoRenewEdit->isDirty(); + + return dirty; +} + +void LLPanelProfileClassified::resetDirty() +{ + mSnapshotCtrl->resetDirty(); + mClassifiedNameEdit->resetDirty(); + + // call blockUndo() to really reset dirty(and make isDirty work as intended) + mClassifiedDescEdit->blockUndo(); + mClassifiedDescEdit->resetDirty(); + + mCategoryCombo->resetDirty(); + mContentTypeCombo->resetDirty(); + mAutoRenewEdit->resetDirty(); +} + +bool LLPanelProfileClassified::canClose() +{ + return mCanClose; +} + +U32 LLPanelProfileClassified::getContentType() +{ + return mContentTypeCombo->getCurrentIndex(); +} + +void LLPanelProfileClassified::setContentType(bool mature) +{ + static std::string mature_str = getString("type_mature"); + static std::string pg_str = getString("type_pg"); + mContentTypeText->setValue(mature ? mature_str : pg_str); + mContentTypeM->setVisible(mature); + mContentTypeG->setVisible(!mature); + mContentTypeCombo->setCurrentByIndex(mature ? CB_ITEM_MATURE : CB_ITEM_PG); + mContentTypeCombo->resetDirty(); +} + +bool LLPanelProfileClassified::getAutoRenew() +{ + return mAutoRenewEdit->getValue().asBoolean(); +} + +void LLPanelProfileClassified::sendUpdate() +{ + LLAvatarClassifiedInfo c_data; + + if(getClassifiedId().isNull()) + { + setClassifiedId(LLUUID::generateNewID()); + } + + c_data.agent_id = gAgent.getID(); + c_data.classified_id = getClassifiedId(); + // *HACK + // Categories on server start with 1 while combo-box index starts with 0 + c_data.category = getCategory() + 1; + c_data.name = getClassifiedName(); + c_data.description = getDescription(); + c_data.parcel_id = getParcelId(); + c_data.snapshot_id = getSnapshotId(); + c_data.pos_global = getPosGlobal(); + c_data.flags = getFlags(); + c_data.price_for_listing = getPriceForListing(); + + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); + + if(isNew()) + { + // Lets assume there will be some error. + // Successful sendClassifiedInfoUpdate will trigger processProperties and + // let us know there was no error. + mIsNewWithErrors = true; + } +} + +U32 LLPanelProfileClassified::getCategory() +{ + return mCategoryCombo->getCurrentIndex(); +} + +void LLPanelProfileClassified::setCategory(U32 category) +{ + mCategoryCombo->setCurrentByIndex(category); + mCategoryCombo->resetDirty(); +} + +U8 LLPanelProfileClassified::getFlags() +{ + bool auto_renew = mAutoRenewEdit->getValue().asBoolean(); + + bool mature = mContentTypeCombo->getCurrentIndex() == CB_ITEM_MATURE; + + return pack_classified_flags_request(auto_renew, false, mature, false); +} + +void LLPanelProfileClassified::enableSave(bool enable) +{ + mSaveButton->setEnabled(enable); +} + +std::string LLPanelProfileClassified::makeClassifiedName() +{ + std::string name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + name = parcel->getName(); + } + + if(!name.empty()) + { + return name; + } + + LLViewerRegion* region = gAgent.getRegion(); + if(region) + { + name = region->getName(); + } + + return name; +} + +void LLPanelProfileClassified::onSetLocationClick() +{ + setPosGlobal(gAgent.getPositionGlobal()); + setParcelId(LLUUID::null); + + std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); + + // mark classified as dirty + setValue(LLSD()); + + onChange(); +} + +void LLPanelProfileClassified::onChange() +{ + enableSave(isDirty()); +} + +void LLPanelProfileClassified::doSave() +{ + //*TODO: Fix all of this + + mCanClose = true; + sendUpdate(); + updateTabLabel(getClassifiedName()); + resetDirty(); + + if (!canClose()) + { + return; + } + + if (!isNew() && !isNewWithErrors()) + { + setEditMode(FALSE); + return; + } + + updateButtons(); +} + +void LLPanelProfileClassified::onPublishFloaterPublishClicked() +{ + setPriceForListing(mPublishFloater->getPrice()); + + doSave(); +} + +std::string LLPanelProfileClassified::getLocationNotice() +{ + static std::string location_notice = getString("location_notice"); + return location_notice; +} + +bool LLPanelProfileClassified::isValidName() +{ + std::string name = getClassifiedName(); + if (name.empty()) + { + return false; + } + if (!isalnum(name[0])) + { + return false; + } + + return true; +} + +void LLPanelProfileClassified::notifyInvalidName() +{ + std::string name = getClassifiedName(); + if (name.empty()) + { + LLNotificationsUtil::add("BlankClassifiedName"); + } + else if (!isalnum(name[0])) + { + LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric"); + } +} + +void LLPanelProfileClassified::onTexturePickerMouseEnter() +{ + mEditIcon->setVisible(TRUE); +} + +void LLPanelProfileClassified::onTexturePickerMouseLeave() +{ + mEditIcon->setVisible(FALSE); +} + +void LLPanelProfileClassified::onTextureSelected() +{ + setSnapshotId(mSnapshotCtrl->getValue().asUUID()); + onChange(); +} + +void LLPanelProfileClassified::updateTabLabel(const std::string& title) +{ + setLabel(title); + LLTabContainer* parent = dynamic_cast(getParent()); + if (parent) + { + parent->setCurrentTabName(title); + } +} + + +//----------------------------------------------------------------------------- +// LLPublishClassifiedFloater +//----------------------------------------------------------------------------- + +LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key) + : LLFloater(key) +{ +} + +LLPublishClassifiedFloater::~LLPublishClassifiedFloater() +{ +} + +BOOL LLPublishClassifiedFloater::postBuild() +{ + LLFloater::postBuild(); + + childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); + childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); + + return TRUE; +} + +void LLPublishClassifiedFloater::setPrice(S32 price) +{ + getChild("price_for_listing")->setValue(price); +} + +S32 LLPublishClassifiedFloater::getPrice() +{ + return getChild("price_for_listing")->getValue().asInteger(); +} + +void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild("publish_btn")->setClickedCallback(cb); +} + +void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild("cancel_btn")->setClickedCallback(cb); +} diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h new file mode 100644 index 0000000000..56deb05b18 --- /dev/null +++ b/indra/newview/llpanelprofileclassifieds.h @@ -0,0 +1,352 @@ +/** + * @file llpanelprofileclassifieds.h + * @brief LLPanelProfileClassifieds and related class implementations + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_PANELPROFILECLASSIFIEDS_H +#define LL_PANELPROFILECLASSIFIEDS_H + +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedinfo.h" +#include "llfloater.h" +#include "llpanel.h" +#include "llpanelavatar.h" +#include "llrect.h" +#include "lluuid.h" +#include "v3dmath.h" +#include "llcoros.h" +#include "lleventcoro.h" + +#include "rlvhandler.h" + +class LLCheckBoxCtrl; +class LLLineEditor; +class LLMediaCtrl; +class LLScrollContainer; +class LLTabContainer; +class LLTextEditor; +class LLTextureCtrl; +class LLUICtrl; + + +class LLPublishClassifiedFloater : public LLFloater +{ +public: + LLPublishClassifiedFloater(const LLSD& key); + virtual ~LLPublishClassifiedFloater(); + + BOOL postBuild() override; + + void setPrice(S32 price); + S32 getPrice(); + + void setPublishClickedCallback(const commit_signal_t::slot_type& cb); + void setCancelClickedCallback(const commit_signal_t::slot_type& cb); +}; + + +/** +* Panel for displaying Avatar's picks. +*/ +class LLPanelProfileClassifieds + : public LLPanelProfilePropertiesProcessorTab +{ +public: + LLPanelProfileClassifieds(); + /*virtual*/ ~LLPanelProfileClassifieds(); + + BOOL postBuild() override; + + void onOpen(const LLSD& key) override; + + void selectClassified(const LLUUID& classified_id, bool edit); + + void createClassified(); + + void processProperties(void* data, EAvatarProcessorType type) override; + + void resetData() override; + + void updateButtons(); + + void updateData() override; + + bool hasNewClassifieds(); + bool hasUnsavedChanges() override; + // commits changes to existing classifieds, but does not publish new classified! + void commitUnsavedChanges() override; + +private: + void onClickNewBtn(); + void onClickDelete(); + void callbackDeleteClassified(const LLSD& notification, const LLSD& response); + + bool canAddNewClassified(); + bool canDeleteClassified(); + + // RLVa support + boost::signals2::connection mRlvBehaviorCallbackConnection; + void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type); + // + + LLTabContainer* mTabContainer; + LLUICtrl* mNoItemsLabel; + LLButton* mNewButton; + LLButton* mDeleteButton; + + LLUUID mClassifiedToSelectOnLoad; + bool mClassifiedEditOnLoad; + bool mSheduledClassifiedCreation; +}; + + +class LLPanelProfileClassified + : public LLPanelProfilePropertiesProcessorTab +{ +public: + + static LLPanelProfileClassified* create(); + + LLPanelProfileClassified(); + + /*virtual*/ ~LLPanelProfileClassified(); + + BOOL postBuild() override; + + void onOpen(const LLSD& key) override; + + void processProperties(void* data, EAvatarProcessorType type) override; + + void setSnapshotId(const LLUUID& id); + + LLUUID getSnapshotId(); + + void setClassifiedId(const LLUUID& id) { mClassifiedId = id; } + + LLUUID& getClassifiedId() { return mClassifiedId; } + + void setClassifiedName(const std::string& name); + + std::string getClassifiedName(); + + void setDescription(const std::string& desc); + + std::string getDescription(); + + void setClassifiedLocation(const std::string& location); + + std::string getClassifiedLocation(); + + void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } + + LLVector3d& getPosGlobal() { return mPosGlobal; } + + void setParcelId(const LLUUID& id) { mParcelId = id; } + + LLUUID getParcelId() { return mParcelId; } + + void setSimName(const std::string& sim_name) { mSimName = sim_name; } + + std::string getSimName() { return mSimName; } + + void setFromSearch(bool val) { mFromSearch = val; } + + bool fromSearch() { return mFromSearch; } + + bool getInfoLoaded() { return mInfoLoaded; } + + void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } + + BOOL isDirty() const override; + + void resetDirty() override; + + bool isNew() { return mIsNew; } + + bool isNewWithErrors() { return mIsNewWithErrors; } + + bool canClose(); + + U32 getCategory(); + + void setCategory(U32 category); + + U32 getContentType(); + + void setContentType(bool mature); + + bool getAutoRenew(); + + S32 getPriceForListing() { return mPriceForListing; } + + void setEditMode(BOOL edit_mode); + bool getEditMode() {return mEditMode;} + + static void setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table); + + static void sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name); + + void doSave(); + +protected: + + void resetData() override; + + void resetControls(); + + void updateButtons(); + void updateInfoRect(); + + static std::string createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global); + + void sendClickMessage(const std::string& type); + + void scrollToTop(); + + void onEditClick(); + void onCancelClick(); + void onSaveClick(); + void onMapClick(); + void onTeleportClick(); + + void sendUpdate(); + + void enableSave(bool enable); + + void enableEditing(bool enable); + + std::string makeClassifiedName(); + + void setPriceForListing(S32 price) { mPriceForListing = price; } + + U8 getFlags(); + + std::string getLocationNotice(); + + bool isValidName(); + + void notifyInvalidName(); + + void onSetLocationClick(); + void onChange(); + + void onPublishFloaterPublishClicked(); + + void onTexturePickerMouseEnter(); + void onTexturePickerMouseLeave(); + + void onTextureSelected(); + + void updateTabLabel(const std::string& title); + +private: + + LLTextureCtrl* mSnapshotCtrl; + LLUICtrl* mEditIcon; + LLUICtrl* mClassifiedNameText; + LLTextEditor* mClassifiedDescText; + LLLineEditor* mClassifiedNameEdit; + LLTextEditor* mClassifiedDescEdit; + LLUICtrl* mLocationText; + LLUICtrl* mLocationEdit; + LLUICtrl* mCategoryText; + LLComboBox* mCategoryCombo; + LLUICtrl* mContentTypeText; + LLIconCtrl* mContentTypeM; + LLIconCtrl* mContentTypeG; + LLComboBox* mContentTypeCombo; + LLUICtrl* mPriceText; + LLUICtrl* mAutoRenewText; + LLUICtrl* mAutoRenewEdit; + + LLButton* mMapButton; + LLButton* mTeleportButton; + LLButton* mEditButton; + LLButton* mSaveButton; + LLButton* mSetLocationButton; + LLButton* mCancelButton; + + LLPanel* mUtilityBtnCnt; + LLPanel* mPublishBtnsCnt; + LLPanel* mSaveBtnCnt; + LLPanel* mCancelBtnCnt; + + LLScrollContainer* mScrollContainer; + LLView* mInfoPanel; + LLPanel* mInfoScroll; + LLPanel* mEditPanel; + + + LLUUID mClassifiedId; + LLVector3d mPosGlobal; + LLUUID mParcelId; + std::string mSimName; + bool mFromSearch; + bool mInfoLoaded; + bool mEditMode; + + // Needed for stat tracking + S32 mTeleportClicksOld; + S32 mMapClicksOld; + S32 mProfileClicksOld; + S32 mTeleportClicksNew; + S32 mMapClicksNew; + S32 mProfileClicksNew; + + S32 mPriceForListing; + +public: // Need this public for fspanelclassified + static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + +private: // + + typedef std::list panel_list_t; + static panel_list_t sAllPanels; + + + bool mIsNew; + bool mIsNewWithErrors; + bool mCanClose; + bool mEditOnLoad; + + LLPublishClassifiedFloater* mPublishFloater; + + S32 getClassifiedFee(); // FIRE-9814 - Don't hardcode a classified listing fee +}; + +#endif // LL_PANELPROFILECLASSIFIEDS_H diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp new file mode 100644 index 0000000000..665add06b9 --- /dev/null +++ b/indra/newview/llpanelprofilepicks.cpp @@ -0,0 +1,916 @@ +/** + * @file llpanelprofilepicks.cpp + * @brief LLPanelProfilePicks and related class implementations + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelprofilepicks.h" + +#include "llagent.h" +#include "llagentbenefits.h" +#include "llagentpicksinfo.h" +#include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" +#include "llcommandhandler.h" +#include "lldispatcher.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llstartup.h" +#include "llpanelavatar.h" +#include "llpanelprofile.h" +#include "llparcel.h" +#include "llstartup.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +static LLPanelInjector t_panel_profile_picks("panel_profile_picks"); +static LLPanelInjector t_panel_profile_pick("panel_profile_pick"); + + +class LLPickHandler : public LLCommandHandler +{ +public: + + // requires trusted browser to trigger + LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (LLStartUp::getStartupState() < STATE_STARTED) + { + return true; + } + + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnablePicks")) + { + LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + // handle app/pick/create urls first + if (params.size() == 1 && params[0].asString() == "create") + { + LLAvatarActions::createPick(); + return true; + } + + // then handle the general app/pick/{UUID}/{CMD} urls + if (params.size() < 2) + { + return false; + } + + // get the ID for the pick_id + LLUUID pick_id; + if (!pick_id.set(params[0], FALSE)) + { + return false; + } + + // edit the pick in the side tray. + // need to ask the server for more info first though... + const std::string verb = params[1].asString(); + if (verb == "edit") + { + LLAvatarActions::showPick(gAgent.getID(), pick_id); + return true; + } + else + { + LL_WARNS() << "unknown verb " << verb << LL_ENDL; + return false; + } + } +}; +LLPickHandler gPickHandler; + + +//----------------------------------------------------------------------------- +// LLPanelProfilePicks +//----------------------------------------------------------------------------- + +LLPanelProfilePicks::LLPanelProfilePicks() + : LLPanelProfilePropertiesProcessorTab() + , mPickToSelectOnLoad(LLUUID::null) + , mRlvBehaviorCallbackConnection() // FIRE-15556: Picks can circumvent RLVa @showloc restriction +{ +} + +LLPanelProfilePicks::~LLPanelProfilePicks() +{ + // FIRE-15556: Picks can circumvent RLVa @showloc restriction + if (mRlvBehaviorCallbackConnection.connected()) + { + mRlvBehaviorCallbackConnection.disconnect(); + } + // +} + +void LLPanelProfilePicks::onOpen(const LLSD& key) +{ + LLPanelProfilePropertiesProcessorTab::onOpen(key); + + resetData(); + + bool own_profile = getSelfProfile(); + if (own_profile) + { + mNewButton->setVisible(TRUE); + mNewButton->setEnabled(FALSE); + + mDeleteButton->setVisible(TRUE); + mDeleteButton->setEnabled(FALSE); + } + + childSetVisible("buttons_header", own_profile); +} + +void LLPanelProfilePicks::createPick(const LLPickData &data) +{ + if (getIsLoaded()) + { + if (canAddNewPick()) + { + mNoItemsLabel->setVisible(FALSE); + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + pick_panel->setAvatarId(getAvatarId()); + pick_panel->processProperties(&data); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(true). + label(pick_panel->getPickName())); + updateButtons(); + } + else + { + // This means that something doesn't properly check limits + // before creating a pick + LL_WARNS() << "failed to add pick" << LL_ENDL; + } + } + else + { + mSheduledPickCreation.push_back(data); + } +} + +void LLPanelProfilePicks::selectPick(const LLUUID& pick_id) +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + if (pick_panel->getPickId() == pick_id) + { + mTabContainer->selectTabPanel(pick_panel); + break; + } + } + } + } + else + { + mPickToSelectOnLoad = pick_id; + } +} + +BOOL LLPanelProfilePicks::postBuild() +{ + mTabContainer = getChild("tab_picks"); + mNoItemsLabel = getChild("picks_panel_text"); + mNewButton = getChild("new_btn"); + mDeleteButton = getChild("delete_btn"); + + mNewButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickNewBtn, this)); + mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickDelete, this)); + + // FIRE-15556: Picks can circumvent RLVa @showloc restriction + mRlvBehaviorCallbackConnection = gRlvHandler.setBehaviourCallback(boost::bind(&LLPanelProfilePicks::updateRlvRestrictions, this, _1, _2)); + + // Replace hardcoded "Second Life" with grid label + LLTextBox* intro_txt = getChild("header_text"); + intro_txt->setTextArg("[GRID]", LLTrans::getString("SECOND_LIFE")); + // + + return TRUE; +} + +void LLPanelProfilePicks::onClickNewBtn() +{ + mNoItemsLabel->setVisible(FALSE); + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + pick_panel->setAvatarId(getAvatarId()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(true). + label(pick_panel->getPickName())); + updateButtons(); +} + +void LLPanelProfilePicks::onClickDelete() +{ + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (pick_panel) + { + LLUUID pick_id = pick_panel->getPickId(); + LLSD args; + args["PICK"] = pick_panel->getPickName(); + LLSD payload; + payload["pick_id"] = pick_id; + payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); + LLNotificationsUtil::add("ProfileDeletePick", args, payload, + boost::bind(&LLPanelProfilePicks::callbackDeletePick, this, _1, _2)); + } +} + +void LLPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + LLUUID pick_id = notification["payload"]["pick_id"].asUUID(); + S32 tab_idx = notification["payload"]["tab_idx"].asInteger(); + + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel && pick_panel->getPickId() == pick_id) + { + mTabContainer->removeTabPanel(pick_panel); + } + + if (pick_id.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id); + } + + updateButtons(); + } +} + +void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PICKS == type) + { + LLAvatarPicks* avatar_picks = static_cast(data); + if (avatar_picks && getAvatarId() == avatar_picks->target_id) + { + processProperties(avatar_picks); + } + } +} + +void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) +{ + LLUUID selected_id = mPickToSelectOnLoad; + bool has_selection = false; + if (mPickToSelectOnLoad.isNull()) + { + if (mTabContainer->getTabCount() > 0) + { + LLPanelProfilePick* active_pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (active_pick_panel) + { + selected_id = active_pick_panel->getPickId(); + } + } + } + + mTabContainer->deleteAllTabs(); + + LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); + for (; avatar_picks->picks_list.end() != it; ++it) + { + LLUUID pick_id = it->first; + std::string pick_name = it->second; + + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + + pick_panel->setPickId(pick_id); + pick_panel->setPickName(pick_name); + pick_panel->setAvatarId(getAvatarId()); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(selected_id == pick_id). + label(pick_name)); + + if (selected_id == pick_id) + { + has_selection = true; + } + } + + while (!mSheduledPickCreation.empty() && canAddNewPick()) + { + const LLPickData data = + mSheduledPickCreation.back(); + + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + pick_panel->setAvatarId(getAvatarId()); + pick_panel->processProperties(&data); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(!has_selection). + label(pick_panel->getPickName())); + + mSheduledPickCreation.pop_back(); + has_selection = true; + } + + // reset 'do on load' values + mPickToSelectOnLoad = LLUUID::null; + mSheduledPickCreation.clear(); + + if (getSelfProfile()) + { + mNoItemsLabel->setValue(LLTrans::getString("NoPicksText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText")); + } + + bool has_data = mTabContainer->getTabCount() > 0; + mNoItemsLabel->setVisible(!has_data); + if (has_data && !has_selection) + { + mTabContainer->selectFirstTab(); + } + + setLoaded(); + updateButtons(); +} + +void LLPanelProfilePicks::resetData() +{ + resetLoading(); + mTabContainer->deleteAllTabs(); +} + +void LLPanelProfilePicks::updateButtons() +{ + if (getSelfProfile()) + { + // RLVa support + //mNewButton->setEnabled(canAddNewPick()); + mNewButton->setEnabled(canAddNewPick() && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + // + mDeleteButton->setEnabled(canDeletePick()); + } +} + +void LLPanelProfilePicks::apply() +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + pick_panel->apply(); + } + } + } +} + +void LLPanelProfilePicks::updateData() +{ + // Send picks request only once + LLUUID avatar_id = getAvatarId(); + if (!getStarted() && avatar_id.notNull()) + { + setIsLoading(); + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); + } + if (!getIsLoaded()) + { + mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); + mNoItemsLabel->setVisible(TRUE); + } +} + +bool LLPanelProfilePicks::hasUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel && (pick_panel->isDirty() || pick_panel->isDirty())) + { + return true; + } + } + return false; +} + +void LLPanelProfilePicks::commitUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + pick_panel->apply(); + } + } +} + +// FIRE-15556: Picks can circumvent RLVa @showloc restriction +void LLPanelProfilePicks::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type) +{ + if (behavior == RLV_BHVR_SHOWLOC) + { + updateButtons(); + } +} + +bool LLPanelProfilePicks::canAddNewPick() +{ + return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() && + // FIRE-15556: Picks can circumvent RLVa @showloc restriction + //mTabContainer->getTabCount() < LLAgentBenefitsMgr::current().getPicksLimit()); + mTabContainer->getTabCount() < LLAgentBenefitsMgr::current().getPicksLimit() && + !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + // +} + +bool LLPanelProfilePicks::canDeletePick() +{ + return (mTabContainer->getTabCount() > 0); +} + + +//----------------------------------------------------------------------------- +// LLPanelProfilePick +//----------------------------------------------------------------------------- + +LLPanelProfilePick::LLPanelProfilePick() + : LLPanelProfilePropertiesProcessorTab() + , LLRemoteParcelInfoObserver() + , mSnapshotCtrl(NULL) + , mPickId(LLUUID::null) + , mParcelId(LLUUID::null) + , mRequestedId(LLUUID::null) + , mLocationChanged(false) + , mNewPick(false) + , mIsEditing(false) +{ +} + +//static +LLPanelProfilePick* LLPanelProfilePick::create() +{ + LLPanelProfilePick* panel = new LLPanelProfilePick(); + panel->buildFromFile("panel_profile_pick.xml"); + return panel; +} + +LLPanelProfilePick::~LLPanelProfilePick() +{ + if (mParcelId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); + } +} + +void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.isNull()) + { + return; + } + LLPanelProfilePropertiesProcessorTab::setAvatarId(avatar_id); + + // creating new Pick + if (getPickId().isNull() && getSelfProfile()) + { + mNewPick = true; + + setPosGlobal(gAgent.getPositionGlobal()); + + LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null; + std::string pick_name, pick_desc, region_name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + parcel_id = parcel->getID(); + pick_name = parcel->getName(); + pick_desc = parcel->getDesc(); + snapshot_id = parcel->getSnapshotID(); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setParcelID(parcel_id); + setPickName(pick_name.empty() ? region_name : pick_name); + setPickDesc(pick_desc); + setSnapshotId(snapshot_id); + setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal())); + + enableSaveButton(TRUE); + } + else + { + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId()); + + enableSaveButton(FALSE); + } + + resetDirty(); + + if (getSelfProfile()) + { + mPickName->setEnabled(TRUE); + mPickDescription->setEnabled(TRUE); + mSetCurrentLocationButton->setVisible(TRUE); + } + else + { + mSnapshotCtrl->setEnabled(FALSE); + } +} + +BOOL LLPanelProfilePick::postBuild() +{ + mPickName = getChild("pick_name"); + mPickDescription = getChild("pick_desc"); + mSaveButton = getChild("save_changes_btn"); + mCreateButton = getChild("create_changes_btn"); + mCancelButton = getChild("cancel_changes_btn"); + mSetCurrentLocationButton = getChild("set_to_curr_location_btn"); + + mSnapshotCtrl = getChild("pick_snapshot"); + mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this)); + + childSetAction("teleport_btn", boost::bind(&LLPanelProfilePick::onClickTeleport, this)); + childSetAction("show_on_map_btn", boost::bind(&LLPanelProfilePick::onClickMap, this)); + + mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); + mCreateButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); + mCancelButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickCancel, this)); + mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this)); + + mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL); + mPickName->setEnabled(FALSE); + + mPickDescription->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1)); + mPickDescription->setFocusReceivedCallback(boost::bind(&LLPanelProfilePick::onDescriptionFocusReceived, this)); + + getChild("pick_location")->setEnabled(FALSE); + + return TRUE; +} + +void LLPanelProfilePick::onDescriptionFocusReceived() +{ + if (!mIsEditing && getSelfProfile()) + { + mIsEditing = true; + mPickDescription->setParseHTML(false); + } +} + +void LLPanelProfilePick::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PICK_INFO != type) + { + return; + } + + LLPickData* pick_info = static_cast(data); + if (!pick_info + || pick_info->creator_id != getAvatarId() + || pick_info->pick_id != getPickId()) + { + return; + } + + processProperties(pick_info); +} + +void LLPanelProfilePick::processProperties(const LLPickData* pick_info) +{ + mIsEditing = false; + mPickDescription->setParseHTML(true); + mParcelId = pick_info->parcel_id; + setSnapshotId(pick_info->snapshot_id); + if (!getSelfProfile()) + { + mSnapshotCtrl->setEnabled(FALSE); + } + setPickName(pick_info->name); + setPickDesc(pick_info->desc); + setPosGlobal(pick_info->pos_global); + + // Send remote parcel info request to get parcel name and sim (region) name. + sendParcelInfoRequest(); + + // *NOTE dzaporozhan + // We want to keep listening to APT_PICK_INFO because user may + // edit the Pick and we have to update Pick info panel. + // revomeObserver is called from onClickBack + + setLoaded(); +} + +void LLPanelProfilePick::apply() +{ + if ((mNewPick || getIsLoaded()) && isDirty()) + { + sendUpdate(); + } +} + +void LLPanelProfilePick::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setImageAssetID(id); + mSnapshotCtrl->setValid(TRUE); +} + +void LLPanelProfilePick::setPickName(const std::string& name) +{ + mPickName->setValue(name); +} + +const std::string LLPanelProfilePick::getPickName() +{ + return mPickName->getValue().asString(); +} + +void LLPanelProfilePick::setPickDesc(const std::string& desc) +{ + mPickDescription->setValue(desc); +} + +void LLPanelProfilePick::setPickLocation(const std::string& location) +{ + getChild("pick_location")->setValue(location); +} + +void LLPanelProfilePick::onClickMap() +{ + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelProfilePick::onClickTeleport() +{ + if (!getPosGlobal().isExactlyZero()) + { + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +void LLPanelProfilePick::enableSaveButton(BOOL enable) +{ + childSetVisible("save_changes_lp", enable); + + childSetVisible("save_btn_lp", enable && !mNewPick); + childSetVisible("create_btn_lp", enable && mNewPick); + childSetVisible("cancel_btn_lp", enable && !mNewPick); +} + +void LLPanelProfilePick::onSnapshotChanged() +{ + enableSaveButton(TRUE); +} + +void LLPanelProfilePick::onPickChanged(LLUICtrl* ctrl) +{ + if (ctrl && ctrl == mPickName) + { + updateTabLabel(mPickName->getText()); + } + + enableSaveButton(isDirty()); +} + +void LLPanelProfilePick::resetDirty() +{ + LLPanel::resetDirty(); + + mPickName->resetDirty(); + mPickDescription->resetDirty(); + mSnapshotCtrl->resetDirty(); + mLocationChanged = false; +} + +BOOL LLPanelProfilePick::isDirty() const +{ + if (mNewPick + || LLPanel::isDirty() + || mLocationChanged + || mSnapshotCtrl->isDirty() + || mPickName->isDirty() + || mPickDescription->isDirty()) + { + return TRUE; + } + return FALSE; +} + +void LLPanelProfilePick::onClickSetLocation() +{ + // Save location for later use. + setPosGlobal(gAgent.getPositionGlobal()); + + std::string parcel_name, region_name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + mParcelId = parcel->getID(); + parcel_name = parcel->getName(); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal())); + + mLocationChanged = true; + enableSaveButton(TRUE); +} + +void LLPanelProfilePick::onClickSave() +{ + sendUpdate(); + + mLocationChanged = false; +} + +void LLPanelProfilePick::onClickCancel() +{ + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId()); + mLocationChanged = false; + enableSaveButton(FALSE); +} + +std::string LLPanelProfilePick::getLocationNotice() +{ + static const std::string notice = getString("location_notice"); + return notice; +} + +void LLPanelProfilePick::sendParcelInfoRequest() +{ + if (mParcelId != mRequestedId) + { + if (mRequestedId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this); + } + LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId); + + mRequestedId = mParcelId; + } +} + +void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data) +{ + setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name, parcel_data.sim_name, getPosGlobal())); + + // We have received parcel info for the requested ID so clear it now. + mRequestedId.setNull(); + + if (mParcelId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); + } +} + +void LLPanelProfilePick::sendUpdate() +{ + LLPickData pick_data; + + // If we don't have a pick id yet, we'll need to generate one, + // otherwise we'll keep overwriting pick_id 00000 in the database. + if (getPickId().isNull()) + { + getPickId().generate(); + } + + pick_data.agent_id = gAgentID; + pick_data.session_id = gAgent.getSessionID(); + pick_data.pick_id = getPickId(); + pick_data.creator_id = gAgentID;; + + //legacy var need to be deleted + pick_data.top_pick = FALSE; + pick_data.parcel_id = mParcelId; + pick_data.name = getPickName(); + pick_data.desc = mPickDescription->getValue().asString(); + pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + pick_data.pos_global = getPosGlobal(); + pick_data.sort_order = 0; + pick_data.enabled = TRUE; + + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data); + + if(mNewPick) + { + // Assume a successful create pick operation, make new number of picks + // available immediately. Actual number of picks will be requested in + // LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond. + LLAgentPicksInfo::getInstance()->incrementNumberOfPicks(); + } +} + +// static +std::string LLPanelProfilePick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global) +{ + std::string location_text(owner_name); + if (!original_name.empty()) + { + if (!location_text.empty()) + { + location_text.append(", "); + } + location_text.append(original_name); + + } + + if (!sim_name.empty()) + { + if (!location_text.empty()) + { + location_text.append(", "); + } + location_text.append(sim_name); + } + + if (!location_text.empty()) + { + location_text.append(" "); + } + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + return location_text; +} + +void LLPanelProfilePick::updateTabLabel(const std::string& title) +{ + setLabel(title); + LLTabContainer* parent = dynamic_cast(getParent()); + if (parent) + { + parent->setCurrentTabName(title); + } +} + diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h new file mode 100644 index 0000000000..34407d37d5 --- /dev/null +++ b/indra/newview/llpanelprofilepicks.h @@ -0,0 +1,255 @@ +/** + * @file llpanelprofilepicks.h + * @brief LLPanelProfilePicks and related class definitions + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPICKS_H +#define LL_LLPANELPICKS_H + +#include "llpanel.h" +#include "lluuid.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelavatar.h" +#include "llremoteparcelrequest.h" + +#include "rlvhandler.h" + +class LLTabContainer; +class LLTextureCtrl; +class LLMediaCtrl; +class LLLineEditor; +class LLTextEditor; + + +/** +* Panel for displaying Avatar's picks. +*/ +class LLPanelProfilePicks + : public LLPanelProfilePropertiesProcessorTab +{ +public: + LLPanelProfilePicks(); + /*virtual*/ ~LLPanelProfilePicks(); + + BOOL postBuild() override; + + void onOpen(const LLSD& key) override; + + void createPick(const LLPickData &data); + void selectPick(const LLUUID& pick_id); + + void processProperties(void* data, EAvatarProcessorType type) override; + void processProperties(const LLAvatarPicks* avatar_picks); + + void resetData() override; + + void updateButtons(); + + /** + * Saves changes. + */ + virtual void apply(); + + /** + * Sends update data request to server. + */ + void updateData() override; + + bool hasUnsavedChanges() override; + void commitUnsavedChanges() override; + + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); + +private: + void onClickNewBtn(); + void onClickDelete(); + void callbackDeletePick(const LLSD& notification, const LLSD& response); + + // FIRE-15556: Picks can circumvent RLVa @showloc restriction + boost::signals2::connection mRlvBehaviorCallbackConnection; + void updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType type); + // + + bool canAddNewPick(); + bool canDeletePick(); + + LLTabContainer* mTabContainer; + LLUICtrl* mNoItemsLabel; + LLButton* mNewButton; + LLButton* mDeleteButton; + + LLUUID mPickToSelectOnLoad; + std::list mSheduledPickCreation; +}; + + +class LLPanelProfilePick + : public LLPanelProfilePropertiesProcessorTab + , public LLRemoteParcelInfoObserver +{ +public: + + // Creates new panel + static LLPanelProfilePick* create(); + + LLPanelProfilePick(); + + /*virtual*/ ~LLPanelProfilePick(); + + BOOL postBuild() override; + + void setAvatarId(const LLUUID& avatar_id) override; + + void setPickId(const LLUUID& id) { mPickId = id; } + virtual LLUUID& getPickId() { return mPickId; } + + virtual void setPickName(const std::string& name); + const std::string getPickName(); + + void processProperties(void* data, EAvatarProcessorType type) override; + void processProperties(const LLPickData* pick_data); + + /** + * Returns true if any of Pick properties was changed by user. + */ + BOOL isDirty() const override; + + /** + * Saves changes. + */ + virtual void apply(); + + void updateTabLabel(const std::string& title); + + //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing + void processParcelInfo(const LLParcelData& parcel_data) override; + void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; } + void setErrorStatus(S32 status, const std::string& reason) override {}; + +protected: + + /** + * Sends remote parcel info request to resolve parcel name from its ID. + */ + void sendParcelInfoRequest(); + + /** + * "Location text" is actually the owner name, the original + * name that owner gave the parcel, and the location. + */ + static std::string createLocationText( + const std::string& owner_name, + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global); + + /** + * Sets snapshot id. + * + * Will mark snapshot control as valid if id is not null. + * Will mark snapshot control as invalid if id is null. If null id is a valid value, + * you have to manually mark snapshot is valid. + */ + virtual void setSnapshotId(const LLUUID& id); + virtual void setPickDesc(const std::string& desc); + virtual void setPickLocation(const std::string& location); + + virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } + virtual LLVector3d& getPosGlobal() { return mPosGlobal; } + + /** + * Callback for "Map" button, opens Map + */ + void onClickMap(); + + /** + * Callback for "Teleport" button, teleports user to Pick location. + */ + void onClickTeleport(); + + /** + * Enables/disables "Save" button + */ + void enableSaveButton(BOOL enable); + + /** + * Called when snapshot image changes. + */ + void onSnapshotChanged(); + + /** + * Callback for Pick snapshot, name and description changed event. + */ + void onPickChanged(LLUICtrl* ctrl); + + /** + * Resets panel and all cantrols to unedited state + */ + void resetDirty() override; + + /** + * Callback for "Set Location" button click + */ + void onClickSetLocation(); + + /** + * Callback for "Save" and "Create" button click + */ + void onClickSave(); + + /** + * Callback for "Save" button click + */ + void onClickCancel(); + + std::string getLocationNotice(); + + /** + * Sends Pick properties to server. + */ + void sendUpdate(); + +protected: + + LLTextureCtrl* mSnapshotCtrl; + LLLineEditor* mPickName; + LLTextEditor* mPickDescription; + LLButton* mSetCurrentLocationButton; + LLButton* mSaveButton; + LLButton* mCreateButton; + LLButton* mCancelButton; + + LLVector3d mPosGlobal; + LLUUID mParcelId; + LLUUID mPickId; + LLUUID mRequestedId; + + bool mLocationChanged; + bool mNewPick; + bool mIsEditing; + + void onDescriptionFocusReceived(); +}; + +#endif // LL_LLPANELPICKS_H diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index bf3d552e7f..98456a9a52 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -542,7 +542,12 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent) // add space for dimensions and aspect ratio S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD; - + // Texture preview mode + //if (getChild("buttons_panel")->getVisible()) + //{ + // info_height += getChild("buttons_panel")->getRect().getHeight(); + //} + // LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0); client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD); @@ -605,6 +610,18 @@ void LLPreviewTexture::openToSave() mPreviewToSave = TRUE; } +// Texture preview mode +//void LLPreviewTexture::hideCtrlButtons() +//{ +// getChildView("desc txt")->setVisible(false); +// getChildView("desc")->setVisible(false); +// getChild("preview_stack")->collapsePanel(getChild("buttons_panel"), true); +// getChild("buttons_panel")->setVisible(false); +// getChild("combo_aspect_ratio")->setCurrentByIndex(0); //unconstrained +// reshape(getRect().getWidth(), getRect().getHeight()); +//} +// + // static void LLPreviewTexture::onFileLoadedForSaveTGA(BOOL success, LLViewerFetchedTexture *src_vi, diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index 297eac8b80..c621b988b5 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -93,6 +93,9 @@ public: static void onSaveAsBtn(LLUICtrl* ctrl, void* data); + // Texture preview mode + //void hideCtrlButtons(); + /*virtual*/ void setObjectID(const LLUUID& object_id); // texture comment metadata reader diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 85540c580f..347b420e49 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -215,7 +215,12 @@ void LLRemoteParcelInfoProcessor::regionParcelInfoCoro(std::string url, if (!status) { - observer->setErrorStatus(status.getStatus(), status.getMessage()); + std::string message = status.getMessage(); + if (message.empty()) + { + message = status.toString(); + } + observer->setErrorStatus(status.getStatus(), message); } else { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 382a31720f..ec90fb88cc 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -97,6 +97,7 @@ #include "llfloateravatarpicker.h" #include "llcallbacklist.h" #include "llcallingcard.h" +#include "llclassifiedinfo.h" #include "llconsole.h" #include "llcontainerview.h" #include "llconversationlog.h" @@ -128,8 +129,6 @@ // [FS Login Panel] #include "llmutelist.h" #include "llavatarpropertiesprocessor.h" -#include "llpanelclassified.h" -#include "llpanelpick.h" #include "llpanelgrouplandmoney.h" #include "llpanelgroupnotices.h" #include "llparcel.h" @@ -198,6 +197,7 @@ #include "llavatariconctrl.h" #include "llvoicechannel.h" #include "llpathfindingmanager.h" +#include "llremoteparcelrequest.h" // [RLVa:KB] - Checked: RLVa-1.2.0 #include "rlvhandler.h" // [/RLVa:KB] @@ -3572,7 +3572,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); -// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); msg->setHandlerFunc("ScriptDialog", process_script_dialog); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 91aa77942e..c3bec10156 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -51,6 +51,7 @@ #include "llviewerinventory.h" #include "llviewermenufile.h" // LLFilePickerReplyThread #include "llpermissions.h" +#include "llpreviewtexture.h" #include "llsaleinfo.h" #include "llassetstorage.h" #include "lltextbox.h" @@ -1473,14 +1474,13 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mNeedsRawImageData( FALSE ), mValid( TRUE ), mShowLoadingPlaceholder( TRUE ), + mOpenTexPreview(!p.enabled), // For texture preview mode mImageAssetID(p.image_id), mDefaultImageAssetID(p.default_image_id), mDefaultImageName(p.default_image_name), mFallbackImage(p.fallback_image), // Mask texture if desired - mIsMasked(FALSE), - // Mask texture if desired - mPreviewMode(!p.enabled) // For texture preview mode + mIsMasked(FALSE) { // Default of defaults is white image for diff tex @@ -1606,7 +1606,7 @@ void LLTextureCtrl::setEnabled( BOOL enabled ) // Texture preview mode //LLView::setEnabled( enabled ); LLView::setEnabled( (enabled || getValue().asUUID().notNull()) ); - mPreviewMode = !enabled; + mOpenTexPreview = !enabled; // } @@ -1744,13 +1744,7 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) if (!handled && mBorder->parentPointInView(x, y)) { - // Texture preview mode - //showPicker(FALSE); - ////grab textures first... - //LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); - ////...then start full inventory fetch. - //LLInventoryModelBackgroundFetch::instance().start(); - if (!mPreviewMode) + if (!mOpenTexPreview) { showPicker(FALSE); //grab textures first... @@ -1758,6 +1752,23 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) //...then start full inventory fetch. LLInventoryModelBackgroundFetch::instance().start(); } + // Texture preview mode + //else + //{ + // if (getImageAssetID().notNull()) + // { + // LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance("preview_texture", getValue()); + // if (preview_texture && !preview_texture->isDependent()) + // { + // LLFloater* root_floater = gFloaterView->getParentFloater(this); + // if (root_floater) + // { + // root_floater->addDependentFloater(preview_texture); + // preview_texture->hideCtrlButtons(); + // } + // } + // } + //} else if (!mIsMasked) { // Open the preview floater for the texture @@ -1955,7 +1966,7 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, // FIRE-10125: Texture picker allows dragging of textures while in preview mode //if (getEnabled() && - if (getEnabled() && !mPreviewMode && + if (getEnabled() && !mOpenTexPreview && // ((cargo_type == DAD_TEXTURE) || is_mesh) && allowDrop(item)) @@ -2171,7 +2182,7 @@ BOOL LLTextureCtrl::handleUnicodeCharHere(llwchar uni_char) { // Texture preview mode //showPicker(TRUE); - if (!mPreviewMode) + if (!mOpenTexPreview) { showPicker(TRUE); //grab textures first... @@ -2199,7 +2210,7 @@ void LLTextureCtrl::setValue( const LLSD& value ) //setImageAssetID(value.asUUID()); LLUUID uuid = value.asUUID(); setImageAssetID(uuid); - LLView::setEnabled( (!mPreviewMode || uuid.notNull()) ); + LLView::setEnabled( (!mOpenTexPreview || uuid.notNull()) ); // } diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index de9ce95079..3c8057ef33 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -170,6 +170,8 @@ public: void setBlankImageAssetID( const LLUUID& id ) { mBlankImageAssetID = id; } const LLUUID& getBlankImageAssetID() const { return mBlankImageAssetID; } + void setOpenTexPreview(bool open_preview) { mOpenTexPreview = open_preview; } + void setCaption(const std::string& caption); void setCanApplyImmediately(BOOL b); @@ -252,9 +254,8 @@ private: BOOL mShowLoadingPlaceholder; std::string mLoadingPlaceholderString; S32 mLabelWidth; - - // Texture preview mode - BOOL mPreviewMode; + bool mOpenTexPreview; + BOOL mBakeTextureEnabled; // Mask texture if desired BOOL mIsMasked; diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index c9e3b530fc..afd63f2766 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -32,6 +32,8 @@ #include "fsradar.h" #include "lggcontactsets.h" #include "llagent.h" +#include "llfloaterprofile.h" +#include "llfloaterreg.h" #include "llviewercontrol.h" #include "llviewerregion.h" #include "llvoavatar.h" @@ -223,12 +225,14 @@ class LLDisplayNameUpdate : public LLHTTPNode } else { - FSRadar* radar = FSRadar::getInstance(); - if (radar) - { - radar->updateName(agent_id); - } + FSRadar::getInstance()->updateName(agent_id); } + + LLFloaterProfile* profile_floater = dynamic_cast(LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id))); + if (profile_floater) + { + profile_floater->refreshName(); + } } }; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index c47c22f65e..9a694ff6dc 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -57,11 +57,13 @@ #include "llfloatercamera.h" #include "llfloatercamerapresets.h" #include "llfloaterchatvoicevolume.h" +#include "llfloaterclassified.h" #include "llfloaterconversationlog.h" #include "llfloaterconversationpreview.h" #include "llfloatercreatelandmark.h" #include "llfloaterdeleteprefpreset.h" #include "llfloaterdestinations.h" +#include "llfloaterdisplayname.h" #include "llfloatereditextdaycycle.h" #include "llfloaterenvironmentadjust.h" #include "llfloaterexperienceprofile.h" @@ -114,6 +116,7 @@ #include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" #include "llfloaterpreviewtrash.h" +#include "llfloaterprofile.h" #include "llfloaterproperties.h" #include "llfloaterregiondebugconsole.h" #include "llfloaterregioninfo.h" @@ -143,7 +146,6 @@ #include "llfloateruipreview.h" #include "llfloatervoiceeffect.h" #include "llfloaterwebcontent.h" -#include "llfloaterwebprofile.h" #include "llfloatervoicevolume.h" #include "llfloaterwhitelistentry.h" #include "llfloaterwindowsize.h" @@ -161,7 +163,7 @@ #include "fsfloaternearbychat.h" // [FS communication UI] #include "llpanelblockedlist.h" -#include "llpanelclassified.h" +#include "llpanelprofileclassifieds.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" @@ -198,7 +200,6 @@ #include "fsfloaterpartialinventory.h" #include "fsfloaterplacedetails.h" #include "fsfloaterposestand.h" -#include "fsfloaterprofile.h" #include "fsfloaterprotectedfolders.h" #include "fsfloaterradar.h" #include "fsfloatersearch.h" @@ -209,7 +210,7 @@ #include "fsfloatervramusage.h" #include "fsfloaterwearablefavorites.h" #include "fsmoneytracker.h" -#include "fspanelclassified.h" +//#include "fspanelclassified.h" #include "lggbeamcolormapfloater.h" #include "lggbeammapfloater.h" #include "llfloaterdisplayname.h" @@ -289,6 +290,7 @@ void LLViewerFloaterReg::registerFloaters() //LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); LLFloaterReg::add("fs_nearby_chat", "floater_fs_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); // [FS communication UI] + LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -343,7 +345,7 @@ void LLViewerFloaterReg::registerFloaters() LLInspectRemoteObjectUtil::registerFloater(); LLFloaterVoiceVolumeUtil::registerFloater(); LLNotificationsUI::registerFloater(); - LLFloaterDisplayNameUtil::registerFloater(); // Bring back display name floater + LLFloaterDisplayNameUtil::registerFloater(); LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -396,7 +398,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("picks", "floater_picks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build/*, "preview"*/); LLFloaterReg::add("preview_conversation", "floater_conversation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -455,8 +456,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("outfit_snapshot", "floater_outfit_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); // Search floater is deferred to login now so we can tell what grid we're in. //LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); - LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); + LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("guidebook", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("big_preview", "floater_big_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -484,7 +484,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("export_collada", "floater_export_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("delete_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("flickr", "floater_flickr.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("fs_floater_profile", "floater_fs_profile_view.xml", &LLFloaterReg::build); LLFloaterReg::add("fs_asset_blacklist", "floater_fs_asset_blacklist.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_avatar_render_settings", "floater_fs_avatar_render_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("fs_blocklist", "floater_fs_blocklist.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); @@ -513,7 +512,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add(PHOTOTOOLS_FLOATER, "floater_phototools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("phototools_camera", "floater_phototools_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("publish_classified_fs", "floater_publish_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("quickprefs", "floater_quickprefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("region_tracker", "floater_region_tracker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("search_replace", "floater_search_replace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index e5d4d66039..e25ee42a17 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -48,7 +48,7 @@ #include "llmutelist.h" #include "llnotifications.h" #include "llnotificationsutil.h" -#include "llpanelprofile.h" +#include "llavataractions.h" #include "llparcel.h" #include "llpluginclassmedia.h" #include "llurldispatcher.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index fb12953f68..2b8db468bc 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -4411,6 +4411,11 @@ bool my_profile_visible() return floaterp && floaterp->isInVisibleChain(); } +bool picks_tab_visible() +{ + return my_profile_visible() && LLAvatarActions::isPickTabSelected(gAgentID); +} + bool enable_freeze_eject(const LLSD& avatar_id) { // [SL:KB] - Patch: UI-AvatarNearbyActions | Checked: 2011-05-13 (Catznip-2.6.0a) | Added: Catznip-2.6.0a @@ -7809,6 +7814,29 @@ class LLAvatarToggleMyProfile : public view_listener_t } }; +class LLAvatarTogglePicks : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloater * instance = LLAvatarActions::getProfileFloater(gAgent.getID()); + if (LLFloater::isMinimized(instance) || (instance && !instance->hasFocus() && !instance->getIsChrome())) + { + instance->setMinimized(FALSE); + instance->setFocus(TRUE); + LLAvatarActions::showPicks(gAgent.getID()); + } + else if (picks_tab_visible()) + { + instance->closeFloater(); + } + else + { + LLAvatarActions::showPicks(gAgent.getID()); + } + return true; + } +}; + class LLAvatarToggleSearch : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8396,6 +8424,15 @@ class LLShowAgentProfile : public view_listener_t } }; +class LLShowAgentProfilePicks : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLAvatarActions::showPicks(gAgent.getID()); + return true; + } +}; + class LLToggleAgentProfile : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -12281,12 +12318,14 @@ void initialize_menus() view_listener_t::addMenu(new LLAvatarTexRefresh(), "Avatar.TexRefresh"); // ## Zi: Texture Refresh view_listener_t::addMenu(new LLAvatarToggleMyProfile(), "Avatar.ToggleMyProfile"); + view_listener_t::addMenu(new LLAvatarTogglePicks(), "Avatar.TogglePicks"); view_listener_t::addMenu(new LLAvatarToggleSearch(), "Avatar.ToggleSearch"); view_listener_t::addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); view_listener_t::addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); view_listener_t::addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); view_listener_t::addMenu(new LLAvatarResetSelfSkeletonAndAnimations(), "Avatar.ResetSelfSkeletonAndAnimations"); enable.add("Avatar.IsMyProfileOpen", boost::bind(&my_profile_visible)); + enable.add("Avatar.IsPicksTabOpen", boost::bind(&picks_tab_visible)); commit.add("Avatar.OpenMarketplace", boost::bind(&LLWeb::loadURLExternal, gSavedSettings.getString("MarketplaceURL"))); @@ -12371,6 +12410,7 @@ void initialize_menus() view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); view_listener_t::addMenu(new LLToggleShaderControl(), "ToggleShaderControl"); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index b70e6dfc55..f2b319b1ad 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -273,14 +273,13 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) return; } - LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! - if (!world_inst) + if (!LLWorld::instanceExists()) { LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL; return; } - regionp = world_inst->getRegionFromHandle(regionHandle); + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; @@ -328,7 +327,6 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) regionp = NULL; impl = NULL; - world_inst = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); if (STATE_WORLD_INIT > LLStartUp::getStartupState()) @@ -339,41 +337,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) if (LLApp::isExiting() || gDisconnected) { + LL_DEBUGS("AppInit", "Capabilities") << "Shutting down" << LL_ENDL; return; } - world_inst = LLWorld::getInstance(); - if (!world_inst) - { - LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; - return; - } - - regionp = world_inst->getRegionFromHandle(regionHandle); - if (!regionp) //region was removed - { - LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; - return; // this error condition is not recoverable. - } - - impl = regionp->getRegionImplNC(); - - // Fix seed cap retry count - //++impl->mSeedCapAttempts; - - if (id != impl->mHttpResponderID) // region is no longer referring to this request - { - LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; - // setup for retry. - ++(impl->mSeedCapAttempts); // Fix seed cap retry count - continue; - } - if (!result.isMap() || result.has("error")) { LL_WARNS("AppInit", "Capabilities") << "Malformed response" << LL_ENDL; // setup for retry. - ++(impl->mSeedCapAttempts); // Fix seed cap retry count continue; } @@ -383,13 +354,38 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) { LL_WARNS("AppInit", "Capabilities") << "HttpStatus error " << LL_ENDL; // setup for retry. - ++(impl->mSeedCapAttempts); // Fix seed cap retry count continue; } // remove the http_result from the llsd result.erase("http_result"); + if (!LLWorld::instanceExists()) + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + if (!regionp) //region was removed + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; + return; // this error condition is not recoverable. + } + + impl = regionp->getRegionImplNC(); + + // Fix seed cap retry count + //++(impl->mSeedCapAttempts); + + if (id != impl->mHttpResponderID) // region is no longer referring to this request + { + LL_WARNS("AppInit", "Capabilities") << "Received results for a stale capabilities request!" << LL_ENDL; + // setup for retry. + ++(impl->mSeedCapAttempts); // Fix seed cap retry count + continue; + } + LLSD::map_const_iterator iter; for (iter = result.beginMap(); iter != result.endMap(); ++iter) { @@ -3223,6 +3219,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("AcceptFriendship"); capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("AgentPreferences"); + capabilityNames.append("AgentProfile"); capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); capabilityNames.append("AvatarPickerSearch"); @@ -3329,6 +3326,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UpdateSettingsAgentInventory"); capabilityNames.append("UpdateSettingsTaskInventory"); + capabilityNames.append("UploadAgentProfileImage"); capabilityNames.append("UpdateMaterialAgentInventory"); capabilityNames.append("UpdateMaterialTaskInventory"); capabilityNames.append("UploadBakedTexture"); diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 3741616f45..57625c81a4 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1178,7 +1178,8 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) BOOL LLViewerTextureList::createUploadFile(const std::string& filename, const std::string& out_filename, - const U8 codec) + const U8 codec, + const S32 max_image_dimentions) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Load the image @@ -1207,7 +1208,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, return FALSE; } // Convert to j2c (JPEG2000) and save the file locally - LLPointer compressedImage = convertToUploadFile(raw_image); + LLPointer compressedImage = convertToUploadFile(raw_image, max_image_dimentions); if (compressedImage.isNull()) { image->setLastError("Couldn't convert the image to jpeg2000."); @@ -1232,10 +1233,10 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, } // note: modifies the argument raw_image!!!! -LLPointer LLViewerTextureList::convertToUploadFile(LLPointer raw_image) +LLPointer LLViewerTextureList::convertToUploadFile(LLPointer raw_image, const S32 max_image_dimentions) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + raw_image->biasedScaleToPowerOfTwo(max_image_dimentions); LLPointer compressedImage = new LLImageJ2C(); if (gSavedSettings.getBOOL("LosslessJ2CUpload") && diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 12e61bfeaf..340b402db1 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -92,8 +92,11 @@ class LLViewerTextureList friend class LLLocalBitmap; public: - static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec); - static LLPointer convertToUploadFile(LLPointer raw_image); + static BOOL createUploadFile(const std::string& filename, + const std::string& out_filename, + const U8 codec, + const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + static LLPointer convertToUploadFile(LLPointer raw_image, const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data ); static void receiveImageHeader(LLMessageSystem *msg, void **user_data); static void receiveImagePacket(LLMessageSystem *msg, void **user_data); diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 0d553657d8..f2d7e4585a 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -36,7 +36,7 @@ #include "llstring.h" // newview -#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions +#include "llavataractions.h" // for getProfileURL() #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals #include "llcorehttputil.h" diff --git a/indra/newview/skins/default/textures/icons/CopyBright.png b/indra/newview/skins/default/textures/icons/CopyBright.png new file mode 100644 index 0000000000..8d21c47295 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/CopyBright.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png b/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png new file mode 100644 index 0000000000..aeba6b70f7 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Friend_Offline.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png b/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png new file mode 100644 index 0000000000..d668fd8dfa Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Friend_Online.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png new file mode 100644 index 0000000000..8f8caa10d8 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Disabled.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png new file mode 100644 index 0000000000..42a209dda5 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Find_Enabled.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png new file mode 100644 index 0000000000..644edf0ef6 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Disabled.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png new file mode 100644 index 0000000000..629c05ecb8 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Objects_Enabled.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png new file mode 100644 index 0000000000..ecf66c0ee1 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Disabled.png differ diff --git a/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png new file mode 100644 index 0000000000..26123938fa Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Profile_Perm_Online_Enabled.png differ diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png new file mode 100644 index 0000000000..3a2ed399b2 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off.png differ diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png new file mode 100644 index 0000000000..789f59a491 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_off_pressed.png differ diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png new file mode 100644 index 0000000000..4fb56c389c Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on.png differ diff --git a/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png new file mode 100644 index 0000000000..ae04a256a4 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/profile_group_visibility_eye_on_pressed.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 29f22d1674..66e71e63f5 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -206,6 +206,8 @@ with the same filename but different name + + @@ -609,6 +611,19 @@ with the same filename but different name + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/da/panel_me.xml b/indra/newview/skins/default/xui/da/panel_me.xml deleted file mode 100644 index f98ced5f91..0000000000 --- a/indra/newview/skins/default/xui/da/panel_me.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/indra/newview/skins/default/xui/de/floater_fs_profile_view.xml b/indra/newview/skins/default/xui/de/floater_profile.xml similarity index 52% rename from indra/newview/skins/default/xui/de/floater_fs_profile_view.xml rename to indra/newview/skins/default/xui/de/floater_profile.xml index 833cdebc6a..9cbabe9135 100644 --- a/indra/newview/skins/default/xui/de/floater_fs_profile_view.xml +++ b/indra/newview/skins/default/xui/de/floater_profile.xml @@ -1,16 +1,16 @@ - + - + - + -