diff options
55 files changed, 2078 insertions, 1132 deletions
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index deac3d1780..ec378761c2 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 3; const S32 LL_VERSION_MINOR = 2; -const S32 LL_VERSION_PATCH = 5; +const S32 LL_VERSION_PATCH = 6; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llui/lllayoutstack.h b/indra/llui/lllayoutstack.h index ede6149a80..3b308a359d 100644 --- a/indra/llui/lllayoutstack.h +++ b/indra/llui/lllayoutstack.h @@ -191,13 +191,12 @@ public: return min_dim; } + F32 getCollapseFactor(); void setOrientation(LLLayoutStack::ELayoutOrientation orientation) { mOrientation = orientation; } protected: LLLayoutPanel(const Params& p); - F32 getCollapseFactor(); - bool mExpandedMinDimSpecified; S32 mExpandedMinDim; diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index cd33938226..f620201020 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -135,6 +135,8 @@ public: const LLColor4& getBackgroundColor() const { return mBgOpaqueColor; } void setTransparentColor(const LLColor4& color) { mBgAlphaColor = color; } const LLColor4& getTransparentColor() const { return mBgAlphaColor; } + void setBackgroundImage(LLUIImage* image) { mBgOpaqueImage = image; } + void setTransparentImage(LLUIImage* image) { mBgAlphaImage = image; } LLPointer<LLUIImage> getBackgroundImage() const { return mBgOpaqueImage; } LLPointer<LLUIImage> getTransparentImage() const { return mBgAlphaImage; } LLColor4 getBackgroundImageOverlay() { return mBgOpaqueImageOverlay; } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 486babb0ab..d2966fbe98 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1090,6 +1090,11 @@ void LLView::drawChildren() { child_list_reverse_iter_t child = child_iter++; LLView *viewp = *child; + + if (viewp == NULL) + { + continue; + } if (viewp->getVisible() && viewp->getRect().isValid()) { diff --git a/indra/llui/llwindowshade.cpp b/indra/llui/llwindowshade.cpp index cf76202215..f39499e50c 100644 --- a/indra/llui/llwindowshade.cpp +++ b/indra/llui/llwindowshade.cpp @@ -37,10 +37,13 @@ const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30; const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100; +static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade"); + LLWindowShade::Params::Params() : bg_image("bg_image"), modal("modal", false), text_color("text_color"), + shade_color("shade_color"), can_close("can_close", true) { changeDefault(mouse_opaque, false); @@ -48,7 +51,6 @@ LLWindowShade::Params::Params() LLWindowShade::LLWindowShade(const LLWindowShade::Params& params) : LLUICtrl(params), - mNotification(params.notification), mModal(params.modal), mFormHeight(0), mTextColor(params.text_color) @@ -72,7 +74,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) addChild(stackp); LLLayoutPanel::Params panel_p; - panel_p.rect = LLRect(0, 30, 800, 0); + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0); panel_p.name = "notification_area"; panel_p.visible = false; panel_p.user_resize = false; @@ -89,7 +91,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) panel_p.name = "background_area"; panel_p.mouse_opaque = false; panel_p.background_visible = false; - panel_p.bg_alpha_color = LLColor4(0.f, 0.f, 0.f, 0.2f); + panel_p.bg_alpha_color = params.shade_color; LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); stackp->addChild(dummy_panel); @@ -107,11 +109,11 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) LLIconCtrl::Params icon_p; icon_p.name = "notification_icon"; - icon_p.rect = LLRect(5, 23, 21, 8); + icon_p.rect = LLRect(5, 25, 21, 10); panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p)); LLTextBox::Params text_p; - text_p.rect = LLRect(31, 20, panel->getRect().getWidth() - 5, 0); + text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3); text_p.follows.flags = FOLLOWS_ALL; text_p.text_color = mTextColor; text_p.font = LLFontGL::getFontSansSerifSmall(); @@ -125,41 +127,132 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) panel_p.auto_resize = false; panel_p.user_resize = false; panel_p.name="form_elements"; - panel_p.rect = LLRect(0, 30, 130, 0); + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0); LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); stackp->addChild(form_elements_panel); - if (params.can_close) + panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); + panel_p.auto_resize = false; + panel_p.user_resize = false; + panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0); + panel_p.name = "close_panel"; + LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); + stackp->addChild(close_panel); + + LLButton::Params button_p; + button_p.name = "close_notification"; + button_p.rect = LLRect(5, 23, 21, 7); + button_p.image_color.control="DkGray_66"; + button_p.image_unselected.name="Icon_Close_Foreground"; + button_p.image_selected.name="Icon_Close_Press"; + button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); + + close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); + + close_panel->setVisible(params.can_close); +} + +void LLWindowShade::draw() +{ + LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); + + LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); + + notification_area->reshape(notification_area->getRect().getWidth(), + llclamp(message_rect.getHeight() + 15, + llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT), + MAX_NOTIFICATION_AREA_HEIGHT)); + + LLUICtrl::draw(); + + while(!mNotifications.empty() && !mNotifications.back()->isActive()) { - panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>(); - panel_p.auto_resize = false; - panel_p.user_resize = false; - panel_p.rect = LLRect(0, 30, 25, 0); - LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p); - stackp->addChild(close_panel); - - LLButton::Params button_p; - button_p.name = "close_notification"; - button_p.rect = LLRect(5, 23, 21, 7); - button_p.image_color.control="DkGray_66"; - button_p.image_unselected.name="Icon_Close_Foreground"; - button_p.image_selected.name="Icon_Close_Press"; - button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this); - - close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p)); + mNotifications.pop_back(); + // go ahead and hide + hide(); } - LLSD payload = mNotification->getPayload(); + if (mNotifications.empty()) + { + hide(); + } + else if (notification_area->getCollapseFactor() < 0.01f) + { + displayLatestNotification(); + } + + if (!notification_area->getVisible() && (notification_area->getCollapseFactor() < 0.001f)) + { + getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); + setMouseOpaque(false); + } +} + +void LLWindowShade::hide() +{ + getChildRef<LLLayoutPanel>("notification_area").setVisible(false); +} + +void LLWindowShade::onCloseNotification() +{ + if (!mNotifications.empty()) + LLNotifications::instance().cancel(mNotifications.back()); +} + +void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +{ + LLNotificationPtr notify = getCurrentNotification(); + if (!notify) return; + + bool check = ctrl->getValue().asBoolean(); + if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + notify->setIgnored(check); +} + +void LLWindowShade::onClickNotificationButton(const std::string& name) +{ + LLNotificationPtr notify = getCurrentNotification(); + if (!notify) return; + + mNotificationResponse[name] = true; + + notify->respond(mNotificationResponse); +} + +void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) +{ + mNotificationResponse[name] = ctrl->getValue().asString(); +} + +void LLWindowShade::show(LLNotificationPtr notification) +{ + mNotifications.push_back(notification); + + displayLatestNotification(); +} + +void LLWindowShade::displayLatestNotification() +{ + if (mNotifications.empty()) return; + + LLNotificationPtr notification = mNotifications.back(); - LLNotificationFormPtr formp = mNotification->getForm(); + LLSD payload = notification->getPayload(); + + LLNotificationFormPtr formp = notification->getForm(); LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area"); - notification_area.getChild<LLUICtrl>("notification_icon")->setValue(mNotification->getIcon()); - notification_area.getChild<LLUICtrl>("notification_text")->setValue(mNotification->getMessage()); - notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(mNotification->getMessage()); + notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon()); + notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage()); + notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage()); LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements"); form_elements.deleteAllChildren(); + form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT); const S32 FORM_PADDING_HORIZONTAL = 10; const S32 FORM_PADDING_VERTICAL = 3; @@ -229,7 +322,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) label_p.v_pad = 5; LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p); textbox->reshapeToFitText(); - textbox->reshape(textbox->getRect().getWidth(), form_elements.getRect().getHeight() - 2 * FORM_PADDING_VERTICAL); + textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL); form_elements.addChild(textbox); cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL; @@ -249,7 +342,7 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) } } - mFormHeight = form_elements.getRect().getHeight() - (cur_y - FORM_PADDING_VERTICAL) + WIDGET_HEIGHT; + mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL); form_elements.reshape(form_width, mFormHeight); form_elements.setMinDim(form_width); @@ -261,68 +354,39 @@ void LLWindowShade::initFromParams(const LLWindowShade::Params& params) { (*it)->translate(0, delta_y); } -} -void LLWindowShade::show() -{ getChildRef<LLLayoutPanel>("notification_area").setVisible(true); getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal); setMouseOpaque(mModal); } -void LLWindowShade::draw() +void LLWindowShade::setBackgroundImage(LLUIImage* image) { - LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect(); - - LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area"); - - notification_area->reshape(notification_area->getRect().getWidth(), - llclamp(message_rect.getHeight() + 10, - llmin(mFormHeight, MAX_NOTIFICATION_AREA_HEIGHT), - MAX_NOTIFICATION_AREA_HEIGHT)); - - LLUICtrl::draw(); - if (mNotification && !mNotification->isActive()) - { - hide(); - } + getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image); } -void LLWindowShade::hide() +void LLWindowShade::setTextColor(LLColor4 color) { - getChildRef<LLLayoutPanel>("notification_area").setVisible(false); - getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false); - - setMouseOpaque(false); + getChild<LLTextBox>("notification_text")->setColor(color); } -void LLWindowShade::onCloseNotification() +bool LLWindowShade::isShown() const { - LLNotifications::instance().cancel(mNotification); + return getChildRef<LLLayoutPanel>("notification_area").getVisible(); } -void LLWindowShade::onClickIgnore(LLUICtrl* ctrl) +void LLWindowShade::setCanClose(bool can_close) { - bool check = ctrl->getValue().asBoolean(); - if (mNotification && mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) - { - // question was "show again" so invert value to get "ignore" - check = !check; - } - mNotification->setIgnored(check); + getChildView("close_panel")->setVisible(can_close); } -void LLWindowShade::onClickNotificationButton(const std::string& name) +LLNotificationPtr LLWindowShade::getCurrentNotification() { - if (!mNotification) return; - - mNotificationResponse[name] = true; - - mNotification->respond(mNotificationResponse); + if (mNotifications.empty()) + { + return LLNotificationPtr(); + } + return mNotifications.back(); } -void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name) -{ - mNotificationResponse[name] = ctrl->getValue().asString(); -} diff --git a/indra/llui/llwindowshade.h b/indra/llui/llwindowshade.h index 09ffc2cd54..6d753d1161 100644 --- a/indra/llui/llwindowshade.h +++ b/indra/llui/llwindowshade.h @@ -36,20 +36,28 @@ class LLWindowShade : public LLUICtrl public: struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> { - Mandatory<LLNotificationPtr> notification; Optional<LLUIImage*> bg_image; - Optional<LLUIColor> text_color; + Optional<LLUIColor> text_color, + shade_color; Optional<bool> modal, can_close; Params(); }; - void show(); + void show(LLNotificationPtr); /*virtual*/ void draw(); void hide(); + + bool isShown() const; + + void setBackgroundImage(LLUIImage* image); + void setTextColor(LLColor4 color); + void setCanClose(bool can_close); private: + void displayLatestNotification(); + LLNotificationPtr getCurrentNotification(); friend class LLUICtrlFactory; LLWindowShade(const Params& p); @@ -60,7 +68,7 @@ private: void onEnterNotificationText(LLUICtrl* ctrl, const std::string& name); void onClickIgnore(LLUICtrl* ctrl); - LLNotificationPtr mNotification; + std::vector<LLNotificationPtr> mNotifications; LLSD mNotificationResponse; bool mModal; S32 mFormHeight; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6b2fe1e45a..0a4874ae92 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -216,6 +216,7 @@ set(viewer_SOURCE_FILES llfloaternotificationsconsole.cpp llfloaterobjectweights.cpp llfloateropenobject.cpp + llfloateroutbox.cpp llfloaterpay.cpp llfloaterperms.cpp llfloaterpostprocess.cpp @@ -314,6 +315,7 @@ set(viewer_SOURCE_FILES llmaniprotate.cpp llmanipscale.cpp llmaniptranslate.cpp + llmarketplacefunctions.cpp llmediactrl.cpp llmediadataclient.cpp llmemoryview.cpp @@ -770,6 +772,7 @@ set(viewer_HEADER_FILES llfloaternotificationsconsole.h llfloaterobjectweights.h llfloateropenobject.h + llfloateroutbox.h llfloaterpay.h llfloaterperms.h llfloaterpostprocess.h @@ -868,6 +871,7 @@ set(viewer_HEADER_FILES llmaniprotate.h llmanipscale.h llmaniptranslate.h + llmarketplacefunctions.h llmediactrl.h llmediadataclient.h llmemoryview.h diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index a44b895f7b..c12d22adc3 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -135,6 +135,16 @@ is_running_function="Floater.IsOpen" is_running_parameters="moveview" /> + <command name="outbox" + available_in_toybox="true" + icon="Command_Outbox_Icon" + label_ref="Command_Outbox_Label" + tooltip_ref="Command_Outbox_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="outbox" + is_running_function="Floater.IsOpen" + is_running_parameters="outbox" + /> <command name="people" available_in_toybox="true" icon="Command_People_Icon" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index aa8ad53a3d..a6d859aab2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4260,16 +4260,38 @@ <key>Value</key> <integer>0</integer> </map> - <key>InventoryMarketplaceUserStatus</key> + <key>InventoryOutboxMaxFolderCount</key> <map> <key>Comment</key> - <string>Marketplace user status.</string> + <string>Maximum number of subfolders allowed in a listing in the merchant outbox.</string> <key>Persist</key> - <integer>1</integer> + <integer>0</integer> <key>Type</key> - <string>String</string> + <string>U32</string> <key>Value</key> - <string /> + <integer>20</integer> + </map> + <key>InventoryOutboxMaxFolderDepth</key> + <map> + <key>Comment</key> + <string>Maximum number of nested levels of subfolders allowed in a listing in the merchant outbox.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>4</integer> + </map> + <key>InventoryOutboxMaxItemCount</key> + <map> + <key>Comment</key> + <string>Maximum number of items allowed in a listing in the merchant outbox.</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>200</integer> </map> <key>InventorySortOrder</key> <map> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0861fe85a8..16d3c115ae 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -45,6 +45,7 @@ #include "llwindow.h" #include "llviewerstats.h" #include "llviewerstatsrecorder.h" +#include "llmarketplacefunctions.h" #include "llmd5.h" #include "llmeshrepository.h" #include "llpumpio.h" @@ -4402,6 +4403,9 @@ void LLAppViewer::idle() // update media focus LLViewerMediaFocus::getInstance()->update(); + + // Update marketplace importer + LLMarketplaceInventoryImporter::update(); // objects and camera should be in sync, do LOD calculations now { diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 8ca621538f..e7e098e423 100755 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -707,7 +707,7 @@ std::set<LLUUID> LLAvatarActions::getInventorySelectedUUIDs() LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { - inventory_selected_uuids = sidepanel_inventory->getInboxOrOutboxSelectionList(); + inventory_selected_uuids = sidepanel_inventory->getInboxSelectionList(); } } diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index a076374903..9626b93690 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -296,6 +296,13 @@ void LLIMWellChiclet::createMenu() void LLIMWellChiclet::messageCountChanged(const LLSD& session_data) { + // The singleton class LLChicletBar instance might be already deleted + // so don't create a new one. + if (!LLChicletBar::instanceExists()) + { + return; + } + const LLUUID& session_id = session_data["session_id"]; const S32 counter = LLChicletBar::getInstance()->getTotalUnreadIMCount(); const bool im_not_visible = !LLFloaterReg::instanceVisible("im_container") diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp new file mode 100644 index 0000000000..725e521e58 --- /dev/null +++ b/indra/newview/llfloateroutbox.cpp @@ -0,0 +1,471 @@ +/** + * @file llfloateroutbox.cpp + * @brief Implementation of the merchant outbox window + * + * $LicenseInfo:firstyear=2001&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 "llfloateroutbox.h" + +#include "llfloaterreg.h" +#include "llfolderview.h" +#include "llinventorybridge.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" +#include "llmarketplacefunctions.h" +#include "llnotificationhandler.h" +#include "llnotificationsutil.h" +#include "lltextbox.h" +#include "lltransientfloatermgr.h" +#include "lltrans.h" +#include "llviewernetwork.h" +#include "llwindowshade.h" + + +///---------------------------------------------------------------------------- +/// LLOutboxNotification class +///---------------------------------------------------------------------------- + +bool LLNotificationsUI::LLOutboxNotification::processNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (notification) + { + LLFloaterOutbox* outbox_floater = LLFloaterReg::getTypedInstance<LLFloaterOutbox>("outbox"); + + outbox_floater->showNotification(notification); + } + + return false; +} + + +///---------------------------------------------------------------------------- +/// LLOutboxAddedObserver helper class +///---------------------------------------------------------------------------- + +class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver +{ +public: + LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater) + : LLInventoryCategoryAddedObserver() + , mOutboxFloater(outboxFloater) + { + } + + void done() + { + for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it) + { + LLViewerInventoryCategory* added_category = *it; + + LLFolderType::EType added_category_type = added_category->getPreferredType(); + + if (added_category_type == LLFolderType::FT_OUTBOX) + { + mOutboxFloater->setupOutbox(added_category->getUUID()); + } + } + } + +private: + LLFloaterOutbox * mOutboxFloater; +}; + +///---------------------------------------------------------------------------- +/// LLFloaterOutbox +///---------------------------------------------------------------------------- + +LLFloaterOutbox::LLFloaterOutbox(const LLSD& key) + : LLFloater(key) + , mCategoriesObserver(NULL) + , mCategoryAddedObserver(NULL) + , mOutboxId(LLUUID::null) + , mOutboxInventoryPanel(NULL) + , mOutboxItemCount(0) + , mInventoryFolderCountText(NULL) + , mInventoryImportInProgress(NULL) + , mInventoryPlaceholder(NULL) + , mInventoryText(NULL) + , mInventoryTitle(NULL) + , mImportButton(NULL) + , mWindowShade(NULL) +{ +} + +LLFloaterOutbox::~LLFloaterOutbox() +{ + if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) + { + gInventory.removeObserver(mCategoriesObserver); + } + delete mCategoriesObserver; + + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + } + delete mCategoryAddedObserver; +} + +BOOL LLFloaterOutbox::postBuild() +{ + mInventoryFolderCountText = getChild<LLTextBox>("outbox_folder_count"); + mInventoryImportInProgress = getChild<LLView>("import_progress_indicator"); + mInventoryPlaceholder = getChild<LLView>("outbox_inventory_placeholder_panel"); + mInventoryText = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_text"); + mInventoryTitle = mInventoryPlaceholder->getChild<LLTextBox>("outbox_inventory_placeholder_title"); + + mImportButton = getChild<LLButton>("outbox_import_btn"); + mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this)); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this)); + + return TRUE; +} + +void LLFloaterOutbox::onClose(bool app_quitting) +{ + if (mWindowShade) + { + delete mWindowShade; + + mWindowShade = NULL; + } +} + +void LLFloaterOutbox::onOpen(const LLSD& key) +{ + // + // Look for an outbox and set up the inventory API + // + + if (mOutboxId.isNull()) + { + const bool do_not_create_folder = false; + const bool do_not_find_in_library = false; + + const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, do_not_create_folder, do_not_find_in_library); + + if (outbox_id.isNull()) + { + // Observe category creation to catch outbox creation + mCategoryAddedObserver = new LLOutboxAddedObserver(this); + gInventory.addObserver(mCategoryAddedObserver); + } + else + { + setupOutbox(outbox_id); + } + } + + updateView(); + + // + // Trigger fetch of outbox contents + // + + fetchOutboxContents(); +} + +void LLFloaterOutbox::onFocusReceived() +{ + fetchOutboxContents(); +} + +void LLFloaterOutbox::fetchOutboxContents() +{ + if (mOutboxId.notNull()) + { + LLInventoryModelBackgroundFetch::instance().start(mOutboxId); + } +} + +void LLFloaterOutbox::setupOutbox(const LLUUID& outboxId) +{ + llassert(outboxId.notNull()); + llassert(mOutboxId.isNull()); + llassert(mCategoriesObserver == NULL); + + mOutboxId = outboxId; + + // No longer need to observe new category creation + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + delete mCategoryAddedObserver; + mCategoryAddedObserver = NULL; + } + + // Create observer for outbox modifications + mCategoriesObserver = new LLInventoryCategoriesObserver(); + gInventory.addObserver(mCategoriesObserver); + + mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); + + // + // Set up the outbox inventory view + // + + mOutboxInventoryPanel = + LLUICtrlFactory::createFromFile<LLInventoryPanel>("panel_outbox_inventory.xml", + mInventoryPlaceholder->getParent(), + LLInventoryPanel::child_registry_t::instance()); + + llassert(mOutboxInventoryPanel); + + // Reshape the inventory to the proper size + LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect(); + mOutboxInventoryPanel->setShape(inventory_placeholder_rect); + + // Set the sort order newest to oldest + mOutboxInventoryPanel->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); + mOutboxInventoryPanel->getFilter()->markDefault(); + + fetchOutboxContents(); + + // + // Initialize the marketplace import API + // + + LLMarketplaceInventoryImporter::getInstance()->initialize(); + LLMarketplaceInventoryImporter::getInstance()->setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); + LLMarketplaceInventoryImporter::getInstance()->setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); +} + +void LLFloaterOutbox::updateItemCount() +{ + S32 item_count = 0; + + if (mOutboxId.notNull()) + { + LLInventoryModel::cat_array_t * cats; + LLInventoryModel::item_array_t * items; + gInventory.getDirectDescendentsOf(mOutboxId, cats, items); + + item_count = cats->count() + items->count(); + } + + mOutboxItemCount = item_count; + + if (mOutboxInventoryPanel) + { + switch (mOutboxItemCount) + { + case 0: mInventoryFolderCountText->setText(getString("OutboxFolderCount0")); break; + case 1: mInventoryFolderCountText->setText(getString("OutboxFolderCount1")); break; + default: + { + std::string item_count_str = llformat("%d", mOutboxItemCount); + + LLStringUtil::format_map_t args; + args["[NUM]"] = item_count_str; + + mInventoryFolderCountText->setText(getString("OutboxFolderCountN", args)); + break; + } + } + } + + mImportButton->setEnabled(mOutboxItemCount > 0); +} + +void LLFloaterOutbox::updateView() +{ + updateItemCount(); + + if (mOutboxItemCount > 0) + { + mOutboxInventoryPanel->setVisible(TRUE); + mInventoryPlaceholder->setVisible(FALSE); + } + else + { + if (mOutboxInventoryPanel) + { + mOutboxInventoryPanel->setVisible(FALSE); + } + + mInventoryPlaceholder->setVisible(TRUE); + + std::string outbox_text; + std::string outbox_title; + std::string outbox_tooltip; + + LLStringUtil::format_map_t subs = getMarketplaceStringSubstitutions(); + + if (mOutboxId.notNull()) + { + outbox_text = LLTrans::getString("InventoryOutboxNoItems", subs); + outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle"); + outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip"); + } + else + { + outbox_text = LLTrans::getString("InventoryOutboxNotMerchant", subs); + outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); + outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); + } + + mInventoryText->setValue(outbox_text); + mInventoryTitle->setValue(outbox_title); + mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip); + } +} + +BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + if ((mOutboxInventoryPanel == NULL) || + (mWindowShade && mWindowShade->isShown()) || + LLMarketplaceInventoryImporter::getInstance()->isImportInProgress()) + { + return FALSE; + } + + LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + BOOL handled = (handled_view != NULL); + + // Pass all drag and drop for this floater to the outbox inventory control + if (!handled || (*accept == ACCEPT_NO)) + { + // Always assume we are going to move the drag and drop operation to the outbox root folder + bool move_to_root = true; + + // If the inventory panel is visible, then only override it to the outbox root if we're outside the inventory panel + // (otherwise the inventory panel itself will handle the drag and drop operation, without any override) + if (mOutboxInventoryPanel->getVisible()) + { + S32 inv_x, inv_y; + localPointToOtherView(x, y, &inv_x, &inv_y, mOutboxInventoryPanel); + + const LLRect& inv_rect = mOutboxInventoryPanel->getRect(); + + move_to_root = !inv_rect.pointInRect(inv_x, inv_y); + } + + // Handle the drag and drop directly to the root of the outbox + if (move_to_root) + { + LLFolderView * root_folder = mOutboxInventoryPanel->getRootFolder(); + + handled = root_folder->handleDragAndDropToRoot(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + } + + return handled; +} + +void LLFloaterOutbox::onImportButtonClicked() +{ + mOutboxInventoryPanel->clearSelection(); + + LLMarketplaceInventoryImporter::instance().triggerImport(); +} + +void LLFloaterOutbox::onOutboxChanged() +{ + llassert(!mOutboxId.isNull()); + + if (mOutboxInventoryPanel) + { + mOutboxInventoryPanel->requestSort(); + } + + fetchOutboxContents(); + updateView(); +} + +void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content) +{ + if (status == MarketplaceErrorCodes::IMPORT_DONE) + { + LLNotificationsUtil::add("OutboxImportComplete"); + } + else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) + { + LLNotificationsUtil::add("OutboxImportHadErrors"); + } + else + { + char status_string[16]; + sprintf(status_string, "%d", status); + + LLSD subs; + subs["[ERROR_CODE]"] = status_string; + + //llassert(status == MarketplaceErrorCodes::IMPORT_JOB_FAILED); + LLNotificationsUtil::add("OutboxImportFailed", subs); + } + + updateView(); +} + +void LLFloaterOutbox::importStatusChanged(bool inProgress) +{ + if (inProgress) + { + mImportButton->setEnabled(false); + + mInventoryImportInProgress->setVisible(true); + } + else + { + mInventoryImportInProgress->setVisible(false); + + mImportButton->setEnabled(mOutboxItemCount > 0); + } +} + +void LLFloaterOutbox::showNotification(LLNotificationPtr notify) +{ + if (mWindowShade) + { + delete mWindowShade; + } + + LLRect floater_rect = getLocalRect(); + floater_rect.mTop -= getHeaderHeight(); + floater_rect.stretch(-5, 0); + + LLWindowShade::Params params; + params.name = "notification_shade"; + params.rect = floater_rect; + params.follows.flags = FOLLOWS_ALL; + params.modal = true; + params.can_close = false; + params.shade_color = LLColor4::white % 0.25f; + params.text_color = LLColor4::white; + + mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); + + addChild(mWindowShade); + mWindowShade->show(notify); +} + diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h new file mode 100644 index 0000000000..5222db1142 --- /dev/null +++ b/indra/newview/llfloateroutbox.h @@ -0,0 +1,105 @@ +/** + * @file llfloateroutbox.h + * @brief LLFloaterOutbox + * class definition + * + * $LicenseInfo:firstyear=2001&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 + * ABILITY 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_LLFLOATEROUTBOX_H +#define LL_LLFLOATEROUTBOX_H + +#include "llfloater.h" +#include "llfoldertype.h" +#include "llnotificationptr.h" + + +class LLButton; +class LLInventoryCategoriesObserver; +class LLInventoryCategoryAddedObserver; +class LLInventoryPanel; +class LLLoadingIndicator; +class LLNotification; +class LLTextBox; +class LLView; +class LLWindowShade; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFloaterOutbox +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFloaterOutbox : public LLFloater +{ +public: + LLFloaterOutbox(const LLSD& key); + ~LLFloaterOutbox(); + + void setupOutbox(const LLUUID& outboxId); + + // virtuals + BOOL postBuild(); + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + void showNotification(LLNotificationPtr notify); + +protected: + void fetchOutboxContents(); + + void importReportResults(U32 status, const LLSD& content); + void importStatusChanged(bool inProgress); + + void onClose(bool app_quitting); + void onOpen(const LLSD& key); + + void onFocusReceived(); + + void onImportButtonClicked(); + void onOutboxChanged(); + + void updateItemCount(); + void updateView(); + +private: + LLInventoryCategoriesObserver * mCategoriesObserver; + LLInventoryCategoryAddedObserver * mCategoryAddedObserver; + + LLUUID mOutboxId; + LLInventoryPanel * mOutboxInventoryPanel; + U32 mOutboxItemCount; + + LLTextBox * mInventoryFolderCountText; + LLView * mInventoryImportInProgress; + LLView * mInventoryPlaceholder; + LLTextBox * mInventoryText; + LLTextBox * mInventoryTitle; + + LLButton * mImportButton; + + LLWindowShade * mWindowShade; +}; + +#endif // LL_LLFLOATEROUTBOX_H diff --git a/indra/newview/llfloatertranslationsettings.cpp b/indra/newview/llfloatertranslationsettings.cpp index 959edff713..428a02e9f0 100644 --- a/indra/newview/llfloatertranslationsettings.cpp +++ b/indra/newview/llfloatertranslationsettings.cpp @@ -29,6 +29,7 @@ #include "llfloatertranslationsettings.h" // Viewer includes +#include "llnearbychatbar.h" #include "lltranslate.h" #include "llviewercontrol.h" // for gSavedSettings @@ -292,5 +293,6 @@ void LLFloaterTranslationSettings::onBtnOK() gSavedSettings.setString("TranslationService", getSelectedService()); gSavedSettings.setString("BingTranslateAPIKey", getEnteredBingKey()); gSavedSettings.setString("GoogleTranslateAPIKey", getEnteredGoogleKey()); + LLNearbyChatBar::getInstance()->enableTranslationCheckbox(LLTranslate::isTranslationConfigured()); closeFloater(false); } diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 6ec2598e44..b8515c2953 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1945,9 +1945,9 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (!handled) { if (getListener()->getUUID().notNull()) - { - handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } + { + handled = LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } else { if (!mFolders.empty()) diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index f27fd035db..526800d4be 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -2276,33 +2276,16 @@ BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, EAcceptance* accept, std::string& tooltip_msg) { - LLFolderView* root_view = getRoot(); - BOOL handled = FALSE; - if(mIsOpen) + + if (mIsOpen) { - handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg) != NULL; + handled = (childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) != NULL); } if (!handled) { - BOOL accepted = mListener && mListener->dragOrDrop(mask, drop,cargo_type,cargo_data, tooltip_msg); - - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - - if (!drop && accepted) - { - root_view->autoOpenTest(this); - } + handleDragAndDropToRoot(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; } @@ -2310,6 +2293,33 @@ BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, return TRUE; } +BOOL LLFolderViewFolder::handleDragAndDropToRoot(MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL accepted = mListener && mListener->dragOrDrop(mask, drop, cargo_type, cargo_data, tooltip_msg); + + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + + if (!drop && accepted) + { + getRoot()->autoOpenTest(this); + } + + return TRUE; +} + BOOL LLFolderViewFolder::handleRightMouseDown( S32 x, S32 y, MASK mask ) { diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 3433e3f7f3..02461fb144 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -547,6 +547,11 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + BOOL handleDragAndDropToRoot(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); virtual void draw(); time_t getCreationDate() const; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 0c092e9a56..ff980955e0 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -60,6 +60,7 @@ #include "llpreviewtexture.h" #include "llselectmgr.h" #include "llsidepanelappearance.h" +#include "lltooldraganddrop.h" #include "lltrans.h" #include "llviewerassettype.h" #include "llviewerfoldertype.h" @@ -71,7 +72,8 @@ #include "llwearablelist.h" // Marketplace outbox current disabled -#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 0 // keep in sync with ENABLE_INVENTORY_DISPLAY_OUTBOX, ENABLE_MERCHANT_OUTBOX_PANEL +#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 1 +#define BLOCK_WORN_ITEMS_IN_OUTBOX 0 typedef std::pair<LLUUID, LLUUID> two_uuids_t; typedef std::list<two_uuids_t> two_uuids_list_t; @@ -616,7 +618,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } - // Don't allow items to be pasted directly into the COF or the inbox + // Don't allow items to be pasted directly into the COF or the inbox/outbox if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder()) { items.push_back(std::string("Paste")); @@ -1101,6 +1103,8 @@ BOOL LLInvFVBridge::canListOnMarketplace() const BOOL LLInvFVBridge::canListOnMarketplaceNow() const { #if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU + +#if BLOCK_WORN_ITEMS_IN_OUTBOX if (get_is_item_worn(mUUID)) { return FALSE; @@ -1112,6 +1116,7 @@ BOOL LLInvFVBridge::canListOnMarketplaceNow() const { return FALSE; } +#endif // BLOCK_WORN_ITEMS_IN_OUTBOX return TRUE; #else @@ -1787,30 +1792,35 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const static BOOL can_move_to_outbox(LLInventoryItem* inv_item, std::string& tooltip_msg) { - bool worn = get_is_item_worn(inv_item->getUUID()); + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + if (linked_item != NULL) + { + inv_item = linked_item; + } + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); if (!allow_transfer) { tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); + return false; } - else if(worn) + +#if BLOCK_WORN_ITEMS_IN_OUTBOX + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) { tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); + return false; } +#endif - return !worn && allow_transfer; + return true; } - -void LLFolderBridge::dropFolderToOutbox(LLInventoryCategory* inv_cat) -{ - copy_folder_to_outbox(inv_cat, getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false), inv_cat->getUUID()); -} - - - int get_folder_levels(LLInventoryCategory* inv_cat) { LLInventoryModel::cat_array_t* cats; @@ -1865,28 +1875,28 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (!isAgentAvatarValid()) return FALSE; if (!isAgentInventory()) return FALSE; // cannot drag categories into library + const LLUUID &cat_id = inv_cat->getUUID(); + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); + const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + + const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id); // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); - const BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL) + const BOOL is_agent_inventory = (model->getCategory(cat_id) != NULL) && (LLToolDragAndDrop::SOURCE_AGENT == source); - const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - BOOL accept = FALSE; if (is_agent_inventory) { - const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); - const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_cat->getUUID(), outbox_id); //-------------------------------------------------------------------------------- // Determine if folder can be moved. @@ -1941,24 +1951,58 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } if (move_is_into_outbox) { - for (S32 i=0; i < descendent_items.count(); ++i) - { - LLInventoryItem* item = descendent_items[i]; - if (!can_move_to_outbox(item, tooltip_msg)) - { - is_movable = FALSE; - break; - } - } - int nested_folder_levels = get_folder_path_length(outbox_id, mUUID) + get_folder_levels(inv_cat); - - if (nested_folder_levels > 4) + + if (nested_folder_levels > gSavedSettings.getU32("InventoryOutboxMaxFolderDepth")) { tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels"); is_movable = FALSE; } - + else + { + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); + + int existing_item_count = 0; + int existing_folder_count = LLToolDragAndDrop::instance().getCargoIDsCount(); + + if (master_folder != NULL) + { + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; + + gInventory.collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); + + existing_item_count += existing_items.count(); + existing_folder_count += existing_categories.count(); + } + + const int nested_folder_count = existing_folder_count + descendent_categories.count(); + const int nested_item_count = existing_item_count + descendent_items.count(); + + if (nested_folder_count > gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) + { + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders"); + is_movable = FALSE; + } + else if (nested_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects"); + is_movable = FALSE; + } + + if (is_movable == TRUE) + { + for (S32 i=0; i < descendent_items.count(); ++i) + { + LLInventoryItem* item = descendent_items[i]; + if (!can_move_to_outbox(item, tooltip_msg)) + { + is_movable = FALSE; + break; + } + } + } + } } // @@ -1999,7 +2043,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // Recursively create links in target outfit. LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; - gInventory.collectDescendents(inv_cat->getUUID(), cats, items, LLInventoryModel::EXCLUDE_TRASH); + gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); } } @@ -2017,7 +2061,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const std::string empty_description = ""; link_inventory_item( gAgent.getID(), - inv_cat->getUUID(), + cat_id, mUUID, inv_cat->getName(), empty_description, @@ -2029,13 +2073,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (move_is_into_outbox && !move_is_from_outbox) { - dropFolderToOutbox(inv_cat); + copy_folder_to_outbox(inv_cat, mUUID, cat_id); } else { - if (gInventory.isObjectDescendentOf(inv_cat->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false))) + if (gInventory.isObjectDescendentOf(cat_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false))) { - set_dad_inbox_object(inv_cat->getUUID()); + set_dad_inbox_object(cat_id); } // Reparent the folder and restamp children if it's moving @@ -2050,15 +2094,28 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - // content category has same ID as object itself - LLUUID object_id = inv_cat->getUUID(); - LLUUID category_id = mUUID; - accept = move_inv_category_world_to_agent(object_id, category_id, drop); + if (move_is_into_outbox) + { + tooltip_msg = tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + accept = FALSE; + } + else + { + accept = move_inv_category_world_to_agent(cat_id, mUUID, drop); + } } else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) { - // Accept folders that contain complete outfits. - accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(inv_cat->getUUID()); + if (move_is_into_outbox) + { + tooltip_msg = tooltip_msg = LLTrans::getString("TooltipOutboxNoTransferLibrary"); + accept = FALSE; + } + else + { + // Accept folders that contain complete outfits. + accept = move_is_into_current_outfit && LLAppearanceMgr::instance().getCanMakeFolderIntoOutfit(cat_id); + } if (accept && drop) { @@ -2875,11 +2932,17 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else if(isOutboxFolder()) { + mItems.push_back(std::string("Rename")); mItems.push_back(std::string("Delete")); + + if ((flags & FIRST_SELECTED_ITEM) == 0) + { + mDisabledItems.push_back(std::string("Rename")); + } } else if(isAgentInventory()) // do not allow creating in library { - LLViewerInventoryCategory *cat = getCategory(); + LLViewerInventoryCategory *cat = getCategory(); // BAP removed protected check to re-enable standard ops in untyped folders. // Not sure what the right thing is to do here. if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) @@ -3307,8 +3370,8 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { LLInventoryModel* model = getInventoryModel(); - if(!model || !inv_item) return FALSE; - if(!isAgentInventory()) return FALSE; // cannot drag into library + if (!model || !inv_item) return FALSE; + if (!isAgentInventory()) return FALSE; // cannot drag into library if (!isAgentAvatarValid()) return FALSE; const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); @@ -3376,10 +3439,14 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, accept = TRUE; if (!is_movable) + { accept = FALSE; - if ((mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) + } + else if ((mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) + { accept = FALSE; - if (move_is_into_current_outfit || move_is_into_outfit) + } + else if (move_is_into_current_outfit || move_is_into_outfit) { accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); } @@ -3390,9 +3457,32 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, else if (move_is_into_outbox) { accept = can_move_to_outbox(inv_item, tooltip_msg); + + if (accept) + { + const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); + + int existing_item_count = LLToolDragAndDrop::instance().getCargoIDsCount(); + + if (master_folder != NULL) + { + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; + + gInventory.collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); + + existing_item_count += existing_items.count(); + } + + if (existing_item_count > gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects"); + accept = FALSE; + } + } } - if(accept && drop) + if (accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE && LLGestureMgr::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash) @@ -3441,9 +3531,16 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { dropToOutfit(inv_item, move_is_into_current_outfit); } - else if (move_is_into_outbox && !move_is_from_outbox) + else if (move_is_into_outbox) { - copy_item_to_outbox(inv_item, outbox_id, LLUUID::null); + if (move_is_from_outbox) + { + move_item_within_outbox(inv_item, mUUID); + } + else + { + copy_item_to_outbox(inv_item, mUUID, LLUUID::null); + } } // NORMAL or TRASH folder // (move the item, restamp if into trash) @@ -3464,7 +3561,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, // //-------------------------------------------------------------------------------- - } } else if (LLToolDragAndDrop::SOURCE_WORLD == source) @@ -3473,7 +3569,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, // anonymous objects, it would be possible to bypass // permissions. object = gObjectList.findObject(inv_item->getParentUUID()); - if(!object) + if (!object) { llinfos << "Object not found for drop." << llendl; return FALSE; @@ -3483,10 +3579,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, // move/copy this item. LLPermissions perm(inv_item->getPermissions()); BOOL is_move = FALSE; - if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) + if ((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) // || gAgent.isGodlike()) - { accept = TRUE; } @@ -3502,7 +3597,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, // Don't allow placing an original item into Current Outfit or an outfit folder // because they must contain only links to wearable items. // *TODO: Probably we should create a link to an item if it was dragged to outfit or COF. - if(move_is_into_current_outfit || move_is_into_outfit) + if (move_is_into_current_outfit || move_is_into_outfit) { accept = FALSE; } @@ -3513,8 +3608,13 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = FALSE; } - - if(drop && accept) + else if (move_is_into_outbox) + { + tooltip_msg = tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + accept = FALSE; + } + + if (accept && drop) { LLMoveInv* move_inv = new LLMoveInv; move_inv->mObjectID = inv_item->getParentUUID(); @@ -3536,15 +3636,22 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLNotifications::instance().forceResponse(params, 0); } } - } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { - // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder - // because they must contain only links to wearable items. - accept = !(move_is_into_current_outfit || move_is_into_outfit); - - if(accept && drop) + if (move_is_into_outbox) + { + tooltip_msg = tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + accept = FALSE; + } + else + { + // Don't allow placing an original item from a notecard to Current Outfit or an outfit folder + // because they must contain only links to wearable items. + accept = !(move_is_into_current_outfit || move_is_into_outfit); + } + + if (accept && drop) { copy_inventory_from_notecard(mUUID, // Drop to the chosen destination folder LLToolDragAndDrop::getInstance()->getObjectID(), @@ -3559,7 +3666,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = TRUE; - if (move_is_into_current_outfit || move_is_into_outfit) + if (move_is_into_outbox) + { + tooltip_msg = tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + accept = FALSE; + } + else if (move_is_into_current_outfit || move_is_into_outfit) { accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); } @@ -3724,29 +3836,29 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + if (isOutboxFolder()) { items.push_back(std::string("Delete")); } else { - items.push_back(std::string("Share")); - if (!canShare()) + if (isItemInTrash()) { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Sound Open")); - items.push_back(std::string("Properties")); + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + items.push_back(std::string("Sound Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); - } + getClipboardEntries(true, items, disabled_items, flags); + } - if (!isOutboxFolder()) - { items.push_back(std::string("Sound Separator")); items.push_back(std::string("Sound Play")); } @@ -3782,29 +3894,29 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items; lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + if(isOutboxFolder()) { items.push_back(std::string("Delete")); } else { - items.push_back(std::string("Share")); - if (!canShare()) + if(isItemInTrash()) { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Landmark Open")); - items.push_back(std::string("Properties")); + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + items.push_back(std::string("Landmark Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); - } + getClipboardEntries(true, items, disabled_items, flags); + } - if (!isOutboxFolder()) - { items.push_back(std::string("Landmark Separator")); items.push_back(std::string("About Landmark")); } @@ -4337,36 +4449,35 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t disabled_items; lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; - if(isItemInTrash()) - { - addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + if(isOutboxFolder()) { items.push_back(std::string("Delete")); } else { - items.push_back(std::string("Share")); - if (!canShare()) + if(isItemInTrash()) { - disabled_items.push_back(std::string("Share")); - } - items.push_back(std::string("Animation Open")); - items.push_back(std::string("Properties")); + addTrashContextMenuOptions(items, disabled_items); + } + else + { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + items.push_back(std::string("Animation Open")); + items.push_back(std::string("Properties")); - getClipboardEntries(true, items, disabled_items, flags); - } + getClipboardEntries(true, items, disabled_items, flags); + } - if (!isOutboxFolder()) - { items.push_back(std::string("Animation Separator")); items.push_back(std::string("Animation Play")); items.push_back(std::string("Animation Audition")); } hide_context_entries(menu, items, disabled_items); - } // virtual @@ -5360,7 +5471,6 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) getClipboardEntries(true, items, disabled_items, flags); } - hide_context_entries(menu, items, disabled_items); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 2d625befb4..126a28f74c 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -306,8 +306,6 @@ protected: void dropToFavorites(LLInventoryItem* inv_item); void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); - void dropToOutbox(LLInventoryItem* inv_item); - void dropFolderToOutbox(LLInventoryCategory* inv_cat); //-------------------------------------------------------------------- // Messy hacks for handling folder options diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 5fb3f15cd5..6c5325620e 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -588,40 +588,72 @@ void move_to_outbox_cb(const LLSD& notification, const LLSD& response) parent = next_parent; } } - } } void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder) { - if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + // Collapse links directly to items/folders + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + if (linked_category != NULL) { - // when moving item directly into outbox create folder with that name - if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + copy_folder_to_outbox(linked_category, dest_folder, top_level_folder); + } + else + { + LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); + if (linked_item != NULL) { - dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_item->getName()); - gInventory.notifyObservers(); + inv_item = (LLInventoryItem *) linked_item; + } + + // Check for copy permissions + if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // when moving item directly into outbox create folder with that name + if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + { + dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_item->getName()); + gInventory.notifyObservers(); + } + + copy_inventory_item(gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + dest_folder, + inv_item->getName(), + LLPointer<LLInventoryCallback>(NULL)); + } + else + { + LLSD args; + args["ITEM_NAME"] = inv_item->getName(); + LLSD payload; + payload["item_id"] = inv_item->getUUID(); + payload["dest_folder_id"] = dest_folder; + payload["top_level_folder"] = top_level_folder; + LLNotificationsUtil::add("ConfirmNoCopyToOutbox", args, payload, boost::bind(&move_to_outbox_cb, _1, _2)); } - - copy_inventory_item( - gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - dest_folder, - inv_item->getName(), - LLPointer<LLInventoryCallback>(NULL)); } - else - { - LLSD args; - args["ITEM_NAME"] = inv_item->getName(); - LLSD payload; - payload["item_id"] = inv_item->getUUID(); - payload["dest_folder_id"] = dest_folder; - payload["top_level_folder"] = top_level_folder; - LLNotificationsUtil::add("ConfirmNoCopyToOutbox", args, payload, boost::bind(&move_to_outbox_cb, _1, _2)); +} + +void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder) +{ + // when moving item directly into outbox create folder with that name + if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + { + dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_item->getName()); + gInventory.notifyObservers(); } + + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; + + change_item_parent(&gInventory, + viewer_inv_item, + dest_folder, + false); } void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 7b452537f8..9f0ee0571a 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -75,6 +75,7 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s void append_path(const LLUUID& id, std::string& path); void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder); +void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder); void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index dc25689fa3..2fb9c53857 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -217,6 +217,38 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons return NULL; } +// +// Search up the parent chain until we get to the specified parent, then return the first child category under it +// +const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const +{ + if (master_parent_id == obj_id) + { + return NULL; + } + + const LLViewerInventoryCategory* current_cat = getCategory(obj_id); + + if (current_cat == NULL) + { + current_cat = getCategory(getObject(obj_id)->getParentUUID()); + } + + while (current_cat != NULL) + { + const LLUUID& current_parent_id = current_cat->getParentUUID(); + + if (current_parent_id == master_parent_id) + { + return current_cat; + } + + current_cat = getCategory(current_parent_id); + } + + return NULL; +} + // Get the object by id. Returns NULL if not found. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 340c1b0c22..1740c4151d 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -238,6 +238,9 @@ public: // Get whatever special folder this object is a child of, if any. const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; + + // Get first descendant of the child object under the specified parent + const LLViewerInventoryCategory *getFirstDescendantOf(const LLUUID& master_parent_id, const LLUUID& obj_id) const; // Get the object by id. Returns NULL if not found. // NOTE: Use the pointer returned for read operations - do diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d06374d232..af1d2b8528 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1105,30 +1105,23 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) return FALSE; } - LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - - // A. If the inventory side panel floater is open, use that preferably. - if (is_inventorysp_active()) - { - // Get the floater's z order to compare it to other inventory floaters' order later. - res = sidepanel_inventory->getActivePanel(); - z_min = gFloaterView->getZOrder(floater_inventory); - active_inv_floaterp = floater_inventory; - } + LLSidepanelInventory *inventory_panel = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - // B. Iterate through the inventory floaters and return whichever is on top. + // Iterate through the inventory floaters and return whichever is on top. LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) { - LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter); - if (iv && iv->getVisible()) + LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter); + inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel"); + + if (inventory_floater && inventory_panel && inventory_floater->getVisible()) { - S32 z_order = gFloaterView->getZOrder(iv); + S32 z_order = gFloaterView->getZOrder(inventory_floater); if (z_order < z_min) { - res = iv->getPanel(); + res = inventory_panel->getActivePanel(); z_min = z_order; - active_inv_floaterp = iv; + active_inv_floaterp = inventory_floater; } } } @@ -1145,7 +1138,7 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) { floater_inventory->openFloater(); - res = sidepanel_inventory->getActivePanel(); + res = inventory_panel->getActivePanel(); } return res; @@ -1164,7 +1157,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L LLViewerInventoryCategory * cat = gInventory.getCategory(obj_id); bool in_inbox = false; - bool in_outbox = false; LLViewerInventoryCategory * parent_cat = NULL; @@ -1180,10 +1172,9 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L if (parent_cat) { in_inbox = (LLFolderType::FT_INBOX == parent_cat->getPreferredType()); - in_outbox = (LLFolderType::FT_OUTBOX == parent_cat->getPreferredType()); } - if (in_inbox || in_outbox) + if (in_inbox) { LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); LLInventoryPanel * inventory_panel = NULL; @@ -1193,11 +1184,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L sidepanel_inventory->openInbox(); inventory_panel = sidepanel_inventory->getInboxPanel(); } - else - { - sidepanel_inventory->openOutbox(); - inventory_panel = sidepanel_inventory->getOutboxPanel(); - } if (inventory_panel) { diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp new file mode 100644 index 0000000000..225bb059c9 --- /dev/null +++ b/indra/newview/llmarketplacefunctions.cpp @@ -0,0 +1,372 @@ +/** + * @file llmarketplacefunctions.cpp + * @brief Implementation of assorted functions related to the marketplace + * + * $LicenseInfo:firstyear=2001&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 "llmarketplacefunctions.h" + +#include "llagent.h" +#include "llhttpclient.h" +#include "lltrans.h" +#include "llviewermedia.h" +#include "llviewernetwork.h" + + +// +// Helpers +// + +static std::string getMarketplaceDomain() +{ + std::string domain = "secondlife.com"; + + if (!LLGridManager::getInstance()->isInProductionGrid()) + { + const std::string& grid_label = LLGridManager::getInstance()->getGridLabel(); + const std::string& grid_label_lower = utf8str_tolower(grid_label); + + if (grid_label_lower == "damballah") + { + domain = "secondlife-staging.com"; + } + else + { + domain = llformat("%s.lindenlab.com", grid_label_lower.c_str()); + } + } + + return domain; +} + +static std::string getMarketplaceURL(const std::string& urlStringName) +{ + LLStringUtil::format_map_t domain_arg; + domain_arg["[MARKETPLACE_DOMAIN_NAME]"] = getMarketplaceDomain(); + + std::string marketplace_url = LLTrans::getString(urlStringName, domain_arg); + + return marketplace_url; +} + +LLStringUtil::format_map_t getMarketplaceStringSubstitutions() +{ + std::string marketplace_url = getMarketplaceURL("MarketplaceURL"); + std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore"); + std::string marketplace_url_dashboard = getMarketplaceURL("MarketplaceURL_Dashboard"); + std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore"); + + LLStringUtil::format_map_t agent_map; + agent_map["[AGENT_ID]"] = gAgent.getID().getString(); + + LLStringUtil::format(marketplace_url_dashboard, agent_map); + + LLStringUtil::format_map_t marketplace_sub_map; + marketplace_sub_map["[MARKETPLACE_URL]"] = marketplace_url; + marketplace_sub_map["[MARKETPLACE_CREATE_STORE_URL]"] = marketplace_url_create; + marketplace_sub_map["[MARKETPLACE_LEARN_MORE_URL]"] = marketplace_url_info; + marketplace_sub_map["[MARKETPLACE_DASHBOARD_URL]"] = marketplace_url_dashboard; + + return marketplace_sub_map; +} + +namespace LLMarketplaceImport +{ + // Basic interface for this namespace + + bool inProgress(); + bool resultPending(); + U32 getResultStatus(); + const LLSD& getResults(); + + void establishMarketplaceSessionCookie(); + void pollStatus(); + void triggerImport(); + + // Internal state variables + + static std::string sMarketplaceCookie = ""; + static bool sImportInProgress = false; + static bool sImportPostPending = false; + static bool sImportGetPending = false; + static U32 sImportResultStatus = 0; + static LLSD sImportResults = LLSD::emptyMap(); + + + // Responders + + class LLImportPostResponder : public LLHTTPClient::Responder + { + public: + LLImportPostResponder() : LLCurl::Responder() {} + + void completed(U32 status, const std::string& reason, const LLSD& content) + { + sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); + sImportPostPending = false; + sImportResultStatus = status; + } + }; + + class LLImportGetResponder : public LLHTTPClient::Responder + { + public: + LLImportGetResponder() : LLCurl::Responder() {} + + void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + sMarketplaceCookie = content["set-cookie"].asString(); + } + + void completed(U32 status, const std::string& reason, const LLSD& content) + { + sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); + sImportGetPending = false; + sImportResultStatus = status; + sImportResults = content; + } + }; + + // Coroutine testing +/* + std::string gTimeDelayDebugFunc = ""; + + void timeDelay(LLCoros::self& self, LLPanelMarketplaceOutbox* outboxPanel) + { + waitForEventOn(self, "mainloop"); + + LLTimer delayTimer; + delayTimer.reset(); + delayTimer.setTimerExpirySec(5.0f); + + while (!delayTimer.hasExpired()) + { + waitForEventOn(self, "mainloop"); + } + + outboxPanel->onImportPostComplete(MarketplaceErrorCodes::IMPORT_DONE, LLSD::emptyMap()); + + gTimeDelayDebugFunc = ""; + } + + std::string gImportPollingFunc = ""; + + void importPoll(LLCoros::self& self, LLPanelMarketplaceOutbox* outboxPanel) + { + waitForEventOn(self, "mainloop"); + + while (outboxPanel->isImportInProgress()) + { + LLTimer delayTimer; + delayTimer.reset(); + delayTimer.setTimerExpirySec(5.0f); + + while (!delayTimer.hasExpired()) + { + waitForEventOn(self, "mainloop"); + } + + //outboxPanel-> + } + + gImportPollingFunc = ""; + } + +*/ + + // Basic API + + bool inProgress() + { + return sImportInProgress; + } + + bool resultPending() + { + return (sImportPostPending || sImportGetPending); + } + + U32 getResultStatus() + { + return sImportResultStatus; + } + + const LLSD& getResults() + { + return sImportResults; + } + + static std::string getInventoryImportURL() + { + std::string url = getMarketplaceURL("MarketplaceURL"); + + url += "api/1/"; + url += gAgent.getID().getString(); + url += "/inventory/import/"; + + return url; + } + + void establishMarketplaceSessionCookie() + { + sImportInProgress = true; + sImportGetPending = true; + + std::string url = getInventoryImportURL(); + + LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders()); + } + + void pollStatus() + { + sImportGetPending = true; + + std::string url = getInventoryImportURL(); + + // Make the headers for the post + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sMarketplaceCookie; + headers["Content-Type"] = "application/xml"; + headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + + LLHTTPClient::get(url, new LLImportGetResponder(), headers); + } + + void triggerImport() + { + sImportInProgress = true; + sImportPostPending = true; + sImportResultStatus = MarketplaceErrorCodes::IMPORT_PROCESSING; + sImportResults = LLSD::emptyMap(); + + std::string url = getInventoryImportURL(); + + // Make the headers for the post + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Connection"] = "Keep-Alive"; + headers["Cookie"] = sMarketplaceCookie; + headers["Content-Type"] = "application/xml"; + headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + + LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers); + + // Set a timer (for testing only) + //gTimeDelayDebugFunc = LLCoros::instance().launch("LLPanelMarketplaceOutbox timeDelay", boost::bind(&timeDelay, _1, this)); + } +} + + +// +// Interface class +// + + +//static +void LLMarketplaceInventoryImporter::update() +{ + if (instanceExists()) + { + LLMarketplaceInventoryImporter::instance().updateImport(); + } +} + +LLMarketplaceInventoryImporter::LLMarketplaceInventoryImporter() + : mImportInProgress(false) + , mInitialized(false) + , mStatusChangedSignal(NULL) + , mStatusReportSignal(NULL) +{ +} + +void LLMarketplaceInventoryImporter::initialize() +{ + if (!mInitialized) + { + LLMarketplaceImport::establishMarketplaceSessionCookie(); + } +} + +boost::signals2::connection LLMarketplaceInventoryImporter::setStatusChangedCallback(const status_changed_signal_t::slot_type& cb) +{ + if (mStatusChangedSignal == NULL) + { + mStatusChangedSignal = new status_changed_signal_t(); + } + + return mStatusChangedSignal->connect(cb); +} + +boost::signals2::connection LLMarketplaceInventoryImporter::setStatusReportCallback(const status_report_signal_t::slot_type& cb) +{ + if (mStatusReportSignal == NULL) + { + mStatusReportSignal = new status_report_signal_t(); + } + + return mStatusReportSignal->connect(cb); +} + +bool LLMarketplaceInventoryImporter::triggerImport() +{ + LLMarketplaceImport::triggerImport(); + + return LLMarketplaceImport::inProgress(); +} + +void LLMarketplaceInventoryImporter::updateImport() +{ + const bool in_progress = LLMarketplaceImport::inProgress(); + + if (in_progress && !LLMarketplaceImport::resultPending()) + { + LLMarketplaceImport::pollStatus(); + } + + if (mImportInProgress != in_progress) + { + mImportInProgress = in_progress; + + if (mStatusChangedSignal) + { + (*mStatusChangedSignal)(mImportInProgress); + } + + // If we are no longer in progress, report results + if (!mImportInProgress && mStatusReportSignal) + { + if (mInitialized) + { + (*mStatusReportSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + } + else + { + mInitialized = true; + } + } + } +} + diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h new file mode 100644 index 0000000000..f501f1ee8b --- /dev/null +++ b/indra/newview/llmarketplacefunctions.h @@ -0,0 +1,88 @@ +/** + * @file llmarketplacefunctions.h + * @brief Miscellaneous marketplace-related functions and classes + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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_LLMARKETPLACEFUNCTIONS_H +#define LL_LLMARKETPLACEFUNCTIONS_H + + +#include <llsd.h> +#include <boost/function.hpp> +#include <boost/signals2.hpp> + +#include "llsingleton.h" +#include "llstring.h" + + +LLStringUtil::format_map_t getMarketplaceStringSubstitutions(); + + +namespace MarketplaceErrorCodes +{ + enum eCode + { + IMPORT_DONE = 200, + IMPORT_PROCESSING = 202, + IMPORT_DONE_WITH_ERRORS = 409, + IMPORT_JOB_FAILED = 410, + }; +} + + +class LLMarketplaceInventoryImporter + : public LLSingleton<LLMarketplaceInventoryImporter> +{ +public: + static void update(); + + LLMarketplaceInventoryImporter(); + + void initialize(); + + typedef boost::signals2::signal<void (bool)> status_changed_signal_t; + typedef boost::signals2::signal<void (U32, const LLSD&)> status_report_signal_t; + + boost::signals2::connection setStatusChangedCallback(const status_changed_signal_t::slot_type& cb); + boost::signals2::connection setStatusReportCallback(const status_report_signal_t::slot_type& cb); + + bool triggerImport(); + bool isImportInProgress() const { return mImportInProgress; } + +protected: + void updateImport(); + +private: + bool mImportInProgress; + bool mInitialized; + + status_changed_signal_t * mStatusChangedSignal; + status_report_signal_t * mStatusReportSignal; +}; + + + +#endif // LL_LLMARKETPLACEFUNCTIONS_H + diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 74fa5d350a..7650fe9229 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -133,10 +133,15 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : navigateHome(); } - // FIXME: How do we create a bevel now? -// LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); -// mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); -// addChild( mBorder ); + LLWindowShade::Params params; + params.name = "notification_shade"; + params.rect = getLocalRect(); + params.follows.flags = FOLLOWS_ALL; + params.modal = true; + + mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); + + addChild(mWindowShade); } LLMediaCtrl::~LLMediaCtrl() @@ -1092,39 +1097,28 @@ void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) void LLMediaCtrl::showNotification(LLNotificationPtr notify) { - delete mWindowShade; + LLWindowShade* shade = getChild<LLWindowShade>("notification_shade"); - LLWindowShade::Params params; - params.name = "notification_shade"; - params.rect = getLocalRect(); - params.follows.flags = FOLLOWS_ALL; - params.notification = notify; - params.modal = true; - //HACK: don't hardcode this if (notify->getIcon() == "Popup_Caution") { - params.bg_image.name = "Yellow_Gradient"; - params.text_color = LLColor4::black; + shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient")); + shade->setTextColor(LLColor4::black); + shade->setCanClose(true); } - else - //HACK: another one since XUI doesn't support what we need right now - if (notify->getName() == "AuthRequest") + else if (notify->getName() == "AuthRequest") { - params.bg_image.name = "Yellow_Gradient"; - params.text_color = LLColor4::black; - params.can_close = false; + shade->setBackgroundImage(LLUI::getUIImage("Yellow_Gradient")); + shade->setTextColor(LLColor4::black); + shade->setCanClose(false); } else { //HACK: make this a property of the notification itself, "cancellable" - params.can_close = false; - params.text_color.control = "LabelTextColor"; + shade->setCanClose(false); + shade->setTextColor(LLUIColorTable::instance().getColor("LabelTextColor")); } - mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); - - addChild(mWindowShade); - mWindowShade->show(); + mWindowShade->show(notify); } void LLMediaCtrl::hideNotification() diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 183063f1db..eec0965384 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -48,6 +48,7 @@ #include "llrootview.h" #include "llviewerchat.h" #include "llnearbychat.h" +#include "lltranslate.h" #include "llresizehandle.h" @@ -116,6 +117,12 @@ BOOL LLNearbyChatBar::postBuild() return TRUE; } +// virtual +void LLNearbyChatBar::onOpen(const LLSD& key) +{ + enableTranslationCheckbox(LLTranslate::isTranslationConfigured()); +} + bool LLNearbyChatBar::applyRectControl() { bool rect_controlled = LLFloater::applyRectControl(); @@ -159,6 +166,11 @@ void LLNearbyChatBar::showHistory() } } +void LLNearbyChatBar::enableTranslationCheckbox(BOOL enable) +{ + getChild<LLUICtrl>("translate_chat_checkbox")->setEnabled(enable); +} + void LLNearbyChatBar::draw() { displaySpeakingIndicator(); diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h index c2f57dc4ca..baf12a06ea 100644 --- a/indra/newview/llnearbychatbar.h +++ b/indra/newview/llnearbychatbar.h @@ -43,6 +43,7 @@ public: ~LLNearbyChatBar() {} virtual BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); static LLNearbyChatBar* getInstance(); @@ -60,6 +61,7 @@ public: static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate); void showHistory(); + void enableTranslationCheckbox(BOOL enable); /*virtual*/void setMinimized(BOOL b); protected: diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h index 28a69f2373..23dbb6b047 100644 --- a/indra/newview/llnotificationhandler.h +++ b/indra/newview/llnotificationhandler.h @@ -283,9 +283,17 @@ class LLBrowserNotification : public LLSingleton<LLBrowserNotification> { public: virtual bool processNotification(const LLSD& notify); +}; +/** + * Handler for outbox notifications + */ +class LLOutboxNotification : public LLSingleton<LLOutboxNotification> +{ +public: + virtual bool processNotification(const LLSD& notify); }; - + class LLHandlerUtil { public: diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp index 6988227128..6105eff8ea 100644 --- a/indra/newview/llnotificationmanager.cpp +++ b/indra/newview/llnotificationmanager.cpp @@ -62,6 +62,7 @@ void LLNotificationManager::init() LLNotificationChannel::buildChannel("Offer", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "offer")); LLNotificationChannel::buildChannel("Hints", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "hint")); LLNotificationChannel::buildChannel("Browser", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "browser")); + LLNotificationChannel::buildChannel("Outbox", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "outbox")); LLNotifications::instance().getChannel("Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); LLNotifications::instance().getChannel("NotificationTips")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); @@ -72,6 +73,7 @@ void LLNotificationManager::init() LLNotifications::instance().getChannel("Offer")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); LLNotifications::instance().getChannel("Hints")->connectChanged(boost::bind(&LLHintHandler::processNotification, LLHintHandler::getInstance(), _1)); LLNotifications::instance().getChannel("Browser")->connectChanged(boost::bind(&LLBrowserNotification::processNotification, LLBrowserNotification::getInstance(), _1)); + LLNotifications::instance().getChannel("Outbox")->connectChanged(boost::bind(&LLOutboxNotification::processNotification, LLOutboxNotification::getInstance(), _1)); mNotifyHandlers["notify"] = boost::shared_ptr<LLEventHandler>(new LLScriptHandler(NT_NOTIFY, LLSD())); mNotifyHandlers["notifytip"] = boost::shared_ptr<LLEventHandler>(new LLTipHandler(NT_NOTIFY, LLSD())); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 9944b51902..374afb90be 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -28,6 +28,7 @@ #include "llpanelmaininventory.h" #include "llagent.h" +#include "llagentcamera.h" #include "llavataractions.h" #include "lldndbutton.h" #include "lleconomy.h" @@ -294,7 +295,13 @@ void LLPanelMainInventory::closeAllFolders() void LLPanelMainInventory::newWindow() { - LLFloaterInventory::showAgentInventory(); + static S32 instance_num = 0; + instance_num = (instance_num + 1) % S32_MAX; + + if (!gAgentCamera.cameraMouselook()) + { + LLFloaterReg::showTypedInstance<LLFloaterSidePanelContainer>("inventory", LLSD(instance_num)); + } } void LLPanelMainInventory::doCreate(const LLSD& userdata) @@ -586,7 +593,7 @@ void LLPanelMainInventory::onFocusReceived() return; } - sidepanel_inventory->clearSelections(false, true, true); + sidepanel_inventory->clearSelections(false, true); } void LLPanelMainInventory::setFilterTextFromFilter() diff --git a/indra/newview/llpanelmarketplaceinbox.cpp b/indra/newview/llpanelmarketplaceinbox.cpp index 7cb4bbf891..a5e964f563 100644 --- a/indra/newview/llpanelmarketplaceinbox.cpp +++ b/indra/newview/llpanelmarketplaceinbox.cpp @@ -109,7 +109,7 @@ void LLPanelMarketplaceInbox::onFocusReceived() LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { - sidepanel_inventory->clearSelections(true, false, true); + sidepanel_inventory->clearSelections(true, false); } gSavedPerAccountSettings.setU32("LastInventoryInboxActivity", time_corrected()); diff --git a/indra/newview/llpanelmarketplaceoutbox.cpp b/indra/newview/llpanelmarketplaceoutbox.cpp index 12960fd0d6..6c2363eb7f 100644 --- a/indra/newview/llpanelmarketplaceoutbox.cpp +++ b/indra/newview/llpanelmarketplaceoutbox.cpp @@ -36,6 +36,7 @@ #include "llfloatersidepanelcontainer.h" #include "llinventorypanel.h" #include "llloadingindicator.h" +#include "llmarketplacefunctions.h" #include "llnotificationsutil.h" #include "llpanelmarketplaceinbox.h" #include "llsdutil.h" @@ -47,6 +48,11 @@ #include "llfolderview.h" #include "llinventoryfunctions.h" + +// Turn this on to get a bunch of console output for marketplace API calls, headers and status +#define DEBUG_MARKETPLACE_HTTP_API 0 + + static LLRegisterPanelClassWrapper<LLPanelMarketplaceOutbox> t_panel_marketplace_outbox("panel_marketplace_outbox"); const LLPanelMarketplaceOutbox::Params& LLPanelMarketplaceOutbox::getDefaultParams() @@ -58,9 +64,9 @@ const LLPanelMarketplaceOutbox::Params& LLPanelMarketplaceOutbox::getDefaultPara LLPanelMarketplaceOutbox::LLPanelMarketplaceOutbox(const Params& p) : LLPanel(p) , mInventoryPanel(NULL) - , mSyncButton(NULL) - , mSyncIndicator(NULL) - , mSyncInProgress(false) + , mImportButton(NULL) + , mImportIndicator(NULL) + , mOutboxButton(NULL) { } @@ -78,13 +84,17 @@ BOOL LLPanelMarketplaceOutbox::postBuild() return TRUE; } +// DO WE NEED THIS FILE AT ALL? + void LLPanelMarketplaceOutbox::handleLoginComplete() { - mSyncButton = getChild<LLButton>("outbox_sync_btn"); - mSyncButton->setCommitCallback(boost::bind(&LLPanelMarketplaceOutbox::onSyncButtonClicked, this)); - mSyncButton->setEnabled(!isOutboxEmpty()); + mImportButton = getChild<LLButton>("outbox_import_btn"); + mImportButton->setCommitCallback(boost::bind(&LLPanelMarketplaceOutbox::onImportButtonClicked, this)); + mImportButton->setEnabled(!isOutboxEmpty()); + + mImportIndicator = getChild<LLLoadingIndicator>("outbox_import_indicator"); - mSyncIndicator = getChild<LLLoadingIndicator>("outbox_sync_indicator"); + mOutboxButton = getChild<LLButton>("outbox_btn"); } void LLPanelMarketplaceOutbox::onFocusReceived() @@ -92,7 +102,7 @@ void LLPanelMarketplaceOutbox::onFocusReceived() LLSidepanelInventory * sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); if (sidepanel_inventory) { - sidepanel_inventory->clearSelections(true, true, false); + sidepanel_inventory->clearSelections(true, true); } } @@ -134,9 +144,44 @@ LLInventoryPanel * LLPanelMarketplaceOutbox::setupInventoryPanel() // Hide the placeholder text outbox_inventory_placeholder->setVisible(FALSE); + // Set up marketplace importer + LLMarketplaceInventoryImporter::getInstance()->initialize(); + LLMarketplaceInventoryImporter::getInstance()->setStatusChangedCallback(boost::bind(&LLPanelMarketplaceOutbox::importStatusChanged, this, _1)); + LLMarketplaceInventoryImporter::getInstance()->setStatusReportCallback(boost::bind(&LLPanelMarketplaceOutbox::importReportResults, this, _1, _2)); + + updateImportButtonStatus(); + return mInventoryPanel; } +void LLPanelMarketplaceOutbox::importReportResults(U32 status, const LLSD& content) +{ + if (status == MarketplaceErrorCodes::IMPORT_DONE) + { + LLNotificationsUtil::add("OutboxImportComplete", LLSD::emptyMap(), LLSD::emptyMap()); + } + else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) + { + LLNotificationsUtil::add("OutboxImportHadErrors", LLSD::emptyMap(), LLSD::emptyMap()); + } + else + { + char status_string[16]; + sprintf(status_string, "%d", status); + + LLSD subs; + subs["ERROR_CODE"] = status_string; + + //llassert(status == MarketplaceErrorCodes::IMPORT_JOB_FAILED); + LLNotificationsUtil::add("OutboxImportFailed", LLSD::emptyMap(), LLSD::emptyMap()); + } +} + +void LLPanelMarketplaceOutbox::importStatusChanged(bool inProgress) +{ + updateImportButtonStatus(); +} + BOOL LLPanelMarketplaceOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, @@ -163,159 +208,23 @@ bool LLPanelMarketplaceOutbox::isOutboxEmpty() const return (getTotalItemCount() == 0); } -bool LLPanelMarketplaceOutbox::isSyncInProgress() const -{ - return mSyncInProgress; -} - - -std::string gTimeDelayDebugFunc = ""; - -void timeDelay(LLCoros::self& self, LLPanelMarketplaceOutbox* outboxPanel) -{ - waitForEventOn(self, "mainloop"); - - LLTimer delayTimer; - delayTimer.reset(); - delayTimer.setTimerExpirySec(5.0f); - - while (!delayTimer.hasExpired()) - { - waitForEventOn(self, "mainloop"); - } - - outboxPanel->onSyncComplete(true, LLSD::emptyMap()); - - gTimeDelayDebugFunc = ""; -} - - -class LLInventorySyncResponder : public LLHTTPClient::Responder -{ -public: - LLInventorySyncResponder(LLPanelMarketplaceOutbox * outboxPanel) - : LLCurl::Responder() - , mOutboxPanel(outboxPanel) - { - } - - void completed(U32 status, const std::string& reason, const LLSD& content) - { - llinfos << "inventory_import complete status: " << status << ", reason: " << reason << llendl; - - if (isGoodStatus(status)) - { - // Complete success - llinfos << "success" << llendl; - } - else - { - llwarns << "failed" << llendl; - } - - mOutboxPanel->onSyncComplete(isGoodStatus(status), content); - } - -private: - LLPanelMarketplaceOutbox * mOutboxPanel; -}; - -void LLPanelMarketplaceOutbox::onSyncButtonClicked() -{ - // Get the sync animation going - mSyncInProgress = true; - updateSyncButtonStatus(); - - // Make the url for the inventory import request - std::string url = "https://marketplace.secondlife.com/"; - - if (!LLGridManager::getInstance()->isInProductionGrid()) - { - std::string gridLabel = LLGridManager::getInstance()->getGridLabel(); - url = llformat("https://marketplace.%s.lindenlab.com/", utf8str_tolower(gridLabel).c_str()); - - // TEMP for Jim's pdp - //url = "http://pdp24.lindenlab.com:3000/"; - } - - url += "api/1/users/"; - url += gAgent.getID().getString(); - url += "/inventory_import"; - - llinfos << "http get: " << url << llendl; - LLHTTPClient::get(url, new LLInventorySyncResponder(this), LLViewerMedia::getHeaders()); - - // Set a timer (for testing only) - //gTimeDelayDebugFunc = LLCoros::instance().launch("LLPanelMarketplaceOutbox timeDelay", boost::bind(&timeDelay, _1, this)); -} - -void LLPanelMarketplaceOutbox::onSyncComplete(bool goodStatus, const LLSD& content) +void LLPanelMarketplaceOutbox::updateImportButtonStatus() { - mSyncInProgress = false; - updateSyncButtonStatus(); - - const LLSD& errors_list = content["errors"]; - - if (goodStatus && (errors_list.size() == 0)) + if (LLMarketplaceInventoryImporter::instance().isImportInProgress()) { - LLNotificationsUtil::add("OutboxUploadComplete", LLSD::emptyMap(), LLSD::emptyMap()); - } - else - { - LLNotificationsUtil::add("OutboxUploadHadErrors", LLSD::emptyMap(), LLSD::emptyMap()); - } - - llinfos << "Marketplace upload llsd:" << llendl; - llinfos << ll_pretty_print_sd(content) << llendl; - llinfos << llendl; + mImportButton->setVisible(false); - const LLSD& imported_list = content["imported"]; - LLSD::array_const_iterator it = imported_list.beginArray(); - for ( ; it != imported_list.endArray(); ++it) - { - LLUUID imported_folder = (*it).asUUID(); - llinfos << "Successfully uploaded folder " << imported_folder.asString() << " to marketplace." << llendl; - } - - for (it = errors_list.beginArray(); it != errors_list.endArray(); ++it) - { - const LLSD& item_error_map = (*it); - - LLUUID error_folder = item_error_map["folder_id"].asUUID(); - const std::string& error_string = item_error_map["identifier"].asString(); - LLUUID error_item = item_error_map["item_id"].asUUID(); - const std::string& error_item_name = item_error_map["item_name"].asString(); - const std::string& error_message = item_error_map["message"].asString(); - - llinfos << "Error item " << error_folder.asString() << ", " << error_string << ", " - << error_item.asString() << ", " << error_item_name << ", " << error_message << llendl; - - LLFolderViewFolder * item_folder = mInventoryPanel->getRootFolder()->getFolderByID(error_folder); - LLOutboxFolderViewFolder * outbox_item_folder = dynamic_cast<LLOutboxFolderViewFolder *>(item_folder); - - llassert(outbox_item_folder); - - outbox_item_folder->setErrorString(error_string); - } -} - -void LLPanelMarketplaceOutbox::updateSyncButtonStatus() -{ - if (isSyncInProgress()) - { - mSyncButton->setVisible(false); - - mSyncIndicator->setVisible(true); - mSyncIndicator->reset(); - mSyncIndicator->start(); + mImportIndicator->setVisible(true); + mImportIndicator->reset(); + mImportIndicator->start(); } else { - mSyncIndicator->stop(); - mSyncIndicator->setVisible(false); + mImportIndicator->stop(); + mImportIndicator->setVisible(false); - mSyncButton->setVisible(true); - mSyncButton->setEnabled(!isOutboxEmpty()); + mImportButton->setVisible(true); + mImportButton->setEnabled(!isOutboxEmpty()); } } @@ -330,12 +239,21 @@ U32 LLPanelMarketplaceOutbox::getTotalItemCount() const if (outbox_folder) { item_count += outbox_folder->getFoldersCount(); + item_count += outbox_folder->getItemsCount(); } } return item_count; } +void LLPanelMarketplaceOutbox::onImportButtonClicked() +{ + LLMarketplaceInventoryImporter::instance().triggerImport(); + + // Get the import animation going + updateImportButtonStatus(); +} + void LLPanelMarketplaceOutbox::draw() { const U32 item_count = getTotalItemCount(); @@ -347,16 +265,11 @@ void LLPanelMarketplaceOutbox::draw() LLStringUtil::format_map_t args; args["[NUM]"] = item_count_str; - getChild<LLButton>("outbox_btn")->setLabel(getString("OutboxLabelWithArg", args)); + mOutboxButton->setLabel(getString("OutboxLabelWithArg", args)); } else { - getChild<LLButton>("outbox_btn")->setLabel(getString("OutboxLabelNoArg")); - } - - if (!isSyncInProgress()) - { - mSyncButton->setEnabled(not_empty); + mOutboxButton->setLabel(getString("OutboxLabelNoArg")); } LLPanel::draw(); diff --git a/indra/newview/llpanelmarketplaceoutbox.h b/indra/newview/llpanelmarketplaceoutbox.h index c6b4a5abe2..6f038118b3 100644 --- a/indra/newview/llpanelmarketplaceoutbox.h +++ b/indra/newview/llpanelmarketplaceoutbox.h @@ -59,9 +59,6 @@ public: U32 getTotalItemCount() const; bool isOutboxEmpty() const; - bool isSyncInProgress() const; - - void onSyncComplete(bool goodStatus, const LLSD& content); /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -70,19 +67,23 @@ public: std::string& tooltip_msg); protected: - void onSyncButtonClicked(); - void updateSyncButtonStatus(); + void onImportButtonClicked(); + void updateImportButtonStatus(); void handleLoginComplete(); void onFocusReceived(); void onSelectionChange(); - + + void importReportResults(U32 status, const LLSD& content); + void importStatusChanged(bool inProgress); + private: LLInventoryPanel * mInventoryPanel; - LLButton * mSyncButton; - LLLoadingIndicator * mSyncIndicator; - bool mSyncInProgress; + LLButton * mImportButton; + LLLoadingIndicator * mImportIndicator; + + LLButton * mOutboxButton; }; diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 933b40ec79..39c0628cbe 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -1351,7 +1351,6 @@ void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify) LLWindowShade::Params params; params.rect = mMediaRegion->getLocalRect(); params.follows.flags = FOLLOWS_ALL; - params.notification = notify; //HACK: don't hardcode this if (notify->getIcon() == "Popup_Caution") @@ -1369,7 +1368,7 @@ void LLPanelPrimMediaControls::showNotification(LLNotificationPtr notify) mWindowShade = LLUICtrlFactory::create<LLWindowShade>(params); mMediaRegion->addChild(mWindowShade); - mWindowShade->show(); + mWindowShade->show(notify); } void LLPanelPrimMediaControls::hideNotification() diff --git a/indra/newview/llsidepanelinventory.cpp b/indra/newview/llsidepanelinventory.cpp index 9d069c3996..5cda381d10 100644 --- a/indra/newview/llsidepanelinventory.cpp +++ b/indra/newview/llsidepanelinventory.cpp @@ -47,7 +47,6 @@ #include "lloutfitobserver.h" #include "llpanelmaininventory.h" #include "llpanelmarketplaceinbox.h" -#include "llpanelmarketplaceoutbox.h" #include "llselectmgr.h" #include "llsidepaneliteminfo.h" #include "llsidepaneltaskinfo.h" @@ -68,35 +67,24 @@ static LLRegisterPanelClassWrapper<LLSidepanelInventory> t_inventory("sidepanel_ // No longer want the inbox panel to auto-expand since it creates issues with the "new" tag time stamp #define AUTO_EXPAND_INBOX 0 -// Temporarily disabling the outbox until we straighten out the API -#define ENABLE_MERCHANT_OUTBOX_PANEL 0 // keep in sync with ENABLE_INVENTORY_DISPLAY_OUTBOX, ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU - static const char * const INBOX_BUTTON_NAME = "inbox_btn"; -static const char * const OUTBOX_BUTTON_NAME = "outbox_btn"; - static const char * const INBOX_LAYOUT_PANEL_NAME = "inbox_layout_panel"; -static const char * const OUTBOX_LAYOUT_PANEL_NAME = "outbox_layout_panel"; - -static const char * const INBOX_OUTBOX_LAYOUT_PANEL_NAME = "inbox_outbox_layout_panel"; static const char * const MAIN_INVENTORY_LAYOUT_PANEL_NAME = "main_inventory_layout_panel"; static const char * const INBOX_INVENTORY_PANEL = "inventory_inbox"; -static const char * const OUTBOX_INVENTORY_PANEL = "inventory_outbox"; -static const char * const INBOX_OUTBOX_LAYOUT_STACK_NAME = "inbox_outbox_layout_stack"; static const char * const INVENTORY_LAYOUT_STACK_NAME = "inventory_layout_stack"; static const char * const MARKETPLACE_INBOX_PANEL = "marketplace_inbox"; -static const char * const MARKETPLACE_OUTBOX_PANEL = "marketplace_outbox"; // // Helpers // -class LLInboxOutboxAddedObserver : public LLInventoryCategoryAddedObserver +class LLInboxAddedObserver : public LLInventoryCategoryAddedObserver { public: - LLInboxOutboxAddedObserver(LLSidepanelInventory * sidepanelInventory) + LLInboxAddedObserver(LLSidepanelInventory * sidepanelInventory) : LLInventoryCategoryAddedObserver() , mSidepanelInventory(sidepanelInventory) { @@ -116,10 +104,6 @@ public: mSidepanelInventory->enableInbox(true); mSidepanelInventory->observeInboxModifications(added_category->getUUID()); break; - case LLFolderType::FT_OUTBOX: - mSidepanelInventory->enableOutbox(true); - mSidepanelInventory->observeOutboxModifications(added_category->getUUID()); - break; default: break; } @@ -138,12 +122,10 @@ LLSidepanelInventory::LLSidepanelInventory() : LLPanel() , mItemPanel(NULL) , mInventoryPanelInbox(NULL) - , mInventoryPanelOutbox(NULL) , mPanelMainInventory(NULL) , mInboxEnabled(false) - , mOutboxEnabled(false) , mCategoriesObserver(NULL) - , mInboxOutboxAddedObserver(NULL) + , mInboxAddedObserver(NULL) { //buildFromFile( "panel_inventory.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() } @@ -156,11 +138,11 @@ LLSidepanelInventory::~LLSidepanelInventory() } delete mCategoriesObserver; - if (mInboxOutboxAddedObserver && gInventory.containsObserver(mInboxOutboxAddedObserver)) + if (mInboxAddedObserver && gInventory.containsObserver(mInboxAddedObserver)) { - gInventory.removeObserver(mInboxOutboxAddedObserver); + gInventory.removeObserver(mInboxAddedObserver); } - delete mInboxOutboxAddedObserver; + delete mInboxAddedObserver; } void handleInventoryDisplayInboxChanged() @@ -172,15 +154,6 @@ void handleInventoryDisplayInboxChanged() } } -void handleInventoryDisplayOutboxChanged() -{ - LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory"); - if (sidepanel_inventory) - { - sidepanel_inventory->enableOutbox(gSavedSettings.getBOOL("InventoryDisplayOutbox")); - } -} - BOOL LLSidepanelInventory::postBuild() { // UI elements from inventory panel @@ -242,43 +215,31 @@ BOOL LLSidepanelInventory::postBuild() } } - // Marketplace inbox/outbox setup + // Received items inbox setup { LLLayoutStack* inv_stack = getChild<LLLayoutStack>(INVENTORY_LAYOUT_STACK_NAME); // Disable user_resize on main inventory panel by default inv_stack->setPanelUserResize(MAIN_INVENTORY_LAYOUT_PANEL_NAME, false); - inv_stack->setPanelUserResize(INBOX_OUTBOX_LAYOUT_PANEL_NAME, false); - - // Collapse marketplace panel by default - inv_stack->collapsePanel(getChild<LLLayoutPanel>(INBOX_OUTBOX_LAYOUT_PANEL_NAME), true); - - LLLayoutStack* inout_stack = getChild<LLLayoutStack>(INBOX_OUTBOX_LAYOUT_STACK_NAME); + inv_stack->setPanelUserResize(INBOX_LAYOUT_PANEL_NAME, false); - // Collapse both inbox and outbox panels - inout_stack->collapsePanel(getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME), true); - inout_stack->collapsePanel(getChild<LLLayoutPanel>(OUTBOX_LAYOUT_PANEL_NAME), true); + // Collapse inbox panel + inv_stack->collapsePanel(getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME), true); // Set up button states and callbacks LLButton * inbox_button = getChild<LLButton>(INBOX_BUTTON_NAME); - LLButton * outbox_button = getChild<LLButton>(OUTBOX_BUTTON_NAME); inbox_button->setToggleState(false); - outbox_button->setToggleState(false); - inbox_button->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleInboxBtn, this)); - outbox_button->setCommitCallback(boost::bind(&LLSidepanelInventory::onToggleOutboxBtn, this)); - // Set the inbox and outbox visible based on debug settings (final setting comes from http request below) + // Set the inbox visible based on debug settings (final setting comes from http request below) enableInbox(gSavedSettings.getBOOL("InventoryDisplayInbox")); - enableOutbox(gSavedSettings.getBOOL("InventoryDisplayOutbox")); - // Trigger callback for after login so we can setup to track inbox and outbox changes after initial inventory load - LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInboxOutbox, this)); + // Trigger callback for after login so we can setup to track inbox changes after initial inventory load + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLSidepanelInventory::updateInbox, this)); } gSavedSettings.getControl("InventoryDisplayInbox")->getCommitSignal()->connect(boost::bind(&handleInventoryDisplayInboxChanged)); - gSavedSettings.getControl("InventoryDisplayOutbox")->getCommitSignal()->connect(boost::bind(&handleInventoryDisplayOutboxChanged)); // Update the verbs buttons state. updateVerbs(); @@ -286,63 +247,50 @@ BOOL LLSidepanelInventory::postBuild() return TRUE; } -void LLSidepanelInventory::updateInboxOutbox() +void LLSidepanelInventory::updateInbox() { // - // Track inbox and outbox folder changes + // Track inbox folder changes // const bool do_not_create_folder = false; const bool do_not_find_in_library = false; const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, do_not_create_folder, do_not_find_in_library); - const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, do_not_create_folder, do_not_find_in_library); - // Set up observer to listen for creation of inbox and outbox if at least one of them doesn't exist - if (inbox_id.isNull() || outbox_id.isNull()) + // Set up observer to listen for creation of inbox if at least one of them doesn't exist + if (inbox_id.isNull()) { - observeInboxOutboxCreation(); + observeInboxCreation(); } - // Set up observer for inbox changes, if we have an inbox already - if (!inbox_id.isNull()) + else { // Enable the display of the inbox if it exists enableInbox(true); observeInboxModifications(inbox_id); } - -#if ENABLE_MERCHANT_OUTBOX_PANEL - // Set up observer for outbox changes, if we have an outbox already - if (!outbox_id.isNull()) - { - // Enable the display of the outbox if it exists - enableOutbox(true); - - observeOutboxModifications(outbox_id); - } -#endif } -void LLSidepanelInventory::observeInboxOutboxCreation() +void LLSidepanelInventory::observeInboxCreation() { // - // Set up observer to track inbox and outbox folder creation + // Set up observer to track inbox folder creation // - if (mInboxOutboxAddedObserver == NULL) + if (mInboxAddedObserver == NULL) { - mInboxOutboxAddedObserver = new LLInboxOutboxAddedObserver(this); + mInboxAddedObserver = new LLInboxAddedObserver(this); - gInventory.addObserver(mInboxOutboxAddedObserver); + gInventory.addObserver(mInboxAddedObserver); } } void LLSidepanelInventory::observeInboxModifications(const LLUUID& inboxID) { // - // Track inbox and outbox folder changes + // Track inbox folder changes // if (inboxID.isNull()) @@ -373,81 +321,12 @@ void LLSidepanelInventory::observeInboxModifications(const LLUUID& inboxID) mInventoryPanelInbox = inbox->setupInventoryPanel(); } - -void LLSidepanelInventory::observeOutboxModifications(const LLUUID& outboxID) -{ - // - // Track outbox folder changes - // - - if (outboxID.isNull()) - { - llwarns << "Attempting to track modifications to non-existant outbox" << llendl; - return; - } - - if (mCategoriesObserver == NULL) - { - mCategoriesObserver = new LLInventoryCategoriesObserver(); - gInventory.addObserver(mCategoriesObserver); - } - - mCategoriesObserver->addCategory(outboxID, boost::bind(&LLSidepanelInventory::onOutboxChanged, this, outboxID)); - - // - // Set up the outbox inventory view - // - - LLPanelMarketplaceOutbox * outbox = getChild<LLPanelMarketplaceOutbox>(MARKETPLACE_OUTBOX_PANEL); - mInventoryPanelOutbox = outbox->setupInventoryPanel(); -} - void LLSidepanelInventory::enableInbox(bool enabled) { mInboxEnabled = enabled; LLLayoutPanel * inbox_layout_panel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME); inbox_layout_panel->setVisible(enabled); - - if (mInboxEnabled) - { - LLLayoutPanel * inout_layout_panel = getChild<LLLayoutPanel>(INBOX_OUTBOX_LAYOUT_PANEL_NAME); - - inout_layout_panel->setVisible(TRUE); - - if (mOutboxEnabled) - { - S32 inbox_min_dim = inbox_layout_panel->getMinDim(); - S32 outbox_min_dim = getChild<LLLayoutPanel>(OUTBOX_LAYOUT_PANEL_NAME)->getMinDim(); - - inout_layout_panel->setMinDim(inbox_min_dim + outbox_min_dim); - } - } -} - -void LLSidepanelInventory::enableOutbox(bool enabled) -{ - mOutboxEnabled = enabled; - - LLLayoutPanel * outbox_layout_panel = getChild<LLLayoutPanel>(OUTBOX_LAYOUT_PANEL_NAME); - outbox_layout_panel->setVisible(enabled); - - if (mOutboxEnabled) - { - LLLayoutPanel * inout_layout_panel = getChild<LLLayoutPanel>(INBOX_OUTBOX_LAYOUT_PANEL_NAME); - - inout_layout_panel->setVisible(TRUE); - - if (mInboxEnabled) - { - S32 inbox_min_dim = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME)->getMinDim(); - S32 outbox_min_dim = outbox_layout_panel->getMinDim(); - - inout_layout_panel->setMinDim(inbox_min_dim + outbox_min_dim); - } - - updateOutboxUserStatus(); - } } void LLSidepanelInventory::openInbox() @@ -459,31 +338,13 @@ void LLSidepanelInventory::openInbox() } } -void LLSidepanelInventory::openOutbox() -{ - if (mOutboxEnabled) - { - getChild<LLButton>(OUTBOX_BUTTON_NAME)->setToggleState(true); - onToggleOutboxBtn(); - } -} - void LLSidepanelInventory::onInboxChanged(const LLUUID& inbox_id) { // Trigger a load of the entire inbox so we always know the contents and their creation dates for sorting LLInventoryModelBackgroundFetch::instance().start(inbox_id); #if AUTO_EXPAND_INBOX - // If the outbox is expanded, don't auto-expand the inbox - if (mOutboxEnabled) - { - if (getChild<LLButton>(OUTBOX_BUTTON_NAME)->getToggleState()) - { - return; - } - } - - // Expand the inbox since we have fresh items and the outbox is not expanded + // Expand the inbox since we have fresh items if (mInboxEnabled) { getChild<LLButton>(INBOX_BUTTON_NAME)->setToggleState(true); @@ -492,68 +353,19 @@ void LLSidepanelInventory::onInboxChanged(const LLUUID& inbox_id) #endif } -void LLSidepanelInventory::onOutboxChanged(const LLUUID& outbox_id) -{ - // Expand the outbox since we have new items in it - if (mOutboxEnabled) - { - getChild<LLButton>(OUTBOX_BUTTON_NAME)->setToggleState(true); - onToggleOutboxBtn(); - } -} - -bool LLSidepanelInventory::manageInboxOutboxPanels(LLButton * pressedButton, LLLayoutPanel * pressedPanel, - LLButton * otherButton, LLLayoutPanel * otherPanel) -{ - bool expand = pressedButton->getToggleState(); - bool otherExpanded = otherButton->getToggleState(); - - LLLayoutStack* inv_stack = getChild<LLLayoutStack>(INVENTORY_LAYOUT_STACK_NAME); - LLLayoutStack* inout_stack = getChild<LLLayoutStack>(INBOX_OUTBOX_LAYOUT_STACK_NAME); - LLLayoutPanel* inout_panel = getChild<LLLayoutPanel>(INBOX_OUTBOX_LAYOUT_PANEL_NAME); - - // Enable user_resize on main inventory panel only when a marketplace box is expanded - inv_stack->setPanelUserResize(MAIN_INVENTORY_LAYOUT_PANEL_NAME, expand); - inv_stack->collapsePanel(inout_panel, !expand); - - // Collapse other marketplace panel if it is expanded - if (expand && otherExpanded) - { - // Reshape pressedPanel to the otherPanel's height so we preserve the marketplace panel size - pressedPanel->reshape(pressedPanel->getRect().getWidth(), otherPanel->getRect().getHeight()); - - inout_stack->collapsePanel(otherPanel, true); - otherButton->setToggleState(false); - } - else - { - // NOTE: This is an attempt to reshape the inventory panel to the proper size but it doesn't seem to propagate - // properly to the child panels. - - S32 new_height = inout_panel->getRect().getHeight(); - - if (otherPanel->getVisible()) - { - new_height -= otherPanel->getMinDim(); - } - - pressedPanel->reshape(pressedPanel->getRect().getWidth(), new_height); - } - - // Expand/collapse the indicated panel - inout_stack->collapsePanel(pressedPanel, !expand); - - return expand; -} - void LLSidepanelInventory::onToggleInboxBtn() { LLButton* inboxButton = getChild<LLButton>(INBOX_BUTTON_NAME); LLLayoutPanel* inboxPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME); - LLButton* outboxButton = getChild<LLButton>(OUTBOX_BUTTON_NAME); - LLLayoutPanel* outboxPanel = getChild<LLLayoutPanel>(OUTBOX_LAYOUT_PANEL_NAME); - - const bool inbox_expanded = manageInboxOutboxPanels(inboxButton, inboxPanel, outboxButton, outboxPanel); + LLLayoutStack* inv_stack = getChild<LLLayoutStack>(INVENTORY_LAYOUT_STACK_NAME); + + const bool inbox_expanded = inboxButton->getToggleState(); + + // Enable user_resize on main inventory panel only when inbox is expanded + inv_stack->setPanelUserResize(MAIN_INVENTORY_LAYOUT_PANEL_NAME, inbox_expanded); + + // Expand/collapse the indicated panel + inv_stack->collapsePanel(inboxPanel, !inbox_expanded); if (inbox_expanded && inboxPanel->isInVisibleChain()) { @@ -561,16 +373,6 @@ void LLSidepanelInventory::onToggleInboxBtn() } } -void LLSidepanelInventory::onToggleOutboxBtn() -{ - LLButton* inboxButton = getChild<LLButton>(INBOX_BUTTON_NAME); - LLLayoutPanel* inboxPanel = getChild<LLLayoutPanel>(INBOX_LAYOUT_PANEL_NAME); - LLButton* outboxButton = getChild<LLButton>(OUTBOX_BUTTON_NAME); - LLLayoutPanel* outboxPanel = getChild<LLLayoutPanel>(OUTBOX_LAYOUT_PANEL_NAME); - - manageInboxOutboxPanels(outboxButton, outboxPanel, inboxButton, inboxPanel); -} - void LLSidepanelInventory::onOpen(const LLSD& key) { LLFirstUse::newInventory(false); @@ -740,77 +542,6 @@ void LLSidepanelInventory::showInventoryPanel() updateVerbs(); } -void LLSidepanelInventory::updateOutboxUserStatus() -{ - const bool isMerchant = (gSavedSettings.getString("InventoryMarketplaceUserStatus") == "merchant"); - const bool hasOutbox = !gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false).isNull(); - - LLView * outbox_placeholder = getChild<LLView>("outbox_inventory_placeholder_panel"); - LLView * outbox_placeholder_parent = outbox_placeholder->getParent(); - - LLTextBox * outbox_title_box = outbox_placeholder->getChild<LLTextBox>("outbox_inventory_placeholder_title"); - LLTextBox * outbox_text_box = outbox_placeholder->getChild<LLTextBox>("outbox_inventory_placeholder_text"); - - std::string outbox_text; - std::string outbox_title; - std::string outbox_tooltip; - - if (isMerchant) - { - if (hasOutbox) - { - outbox_text = LLTrans::getString("InventoryOutboxNoItems"); - outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip"); - } - else - { - outbox_text = LLTrans::getString("InventoryOutboxCreationError"); - outbox_title = LLTrans::getString("InventoryOutboxCreationErrorTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxCreationErrorTooltip"); - } - } - else - { - // - // The string to become a merchant contains 3 URL's which need the domain name patched in. - // - - std::string domain = "secondlife.com"; - - if (!LLGridManager::getInstance()->isInProductionGrid()) - { - std::string gridLabel = LLGridManager::getInstance()->getGridLabel(); - domain = llformat("%s.lindenlab.com", utf8str_tolower(gridLabel).c_str()); - } - - LLStringUtil::format_map_t domain_arg; - domain_arg["[DOMAIN_NAME]"] = domain; - - std::string marketplace_url = LLTrans::getString("MarketplaceURL", domain_arg); - std::string marketplace_url_create = LLTrans::getString("MarketplaceURL_CreateStore", domain_arg); - std::string marketplace_url_info = LLTrans::getString("MarketplaceURL_LearnMore", domain_arg); - - LLStringUtil::format_map_t args1, args2, args3; - args1["[MARKETPLACE_URL]"] = marketplace_url; - args2["[LEARN_MORE_URL]"] = marketplace_url_info; - args3["[CREATE_STORE_URL]"] = marketplace_url_create; - - // NOTE: This is dumb, ridiculous and very finicky. The order of these is very important - // to have these three string substitutions work properly. - outbox_text = LLTrans::getString("InventoryOutboxNotMerchant", args1); - LLStringUtil::format(outbox_text, args2); - LLStringUtil::format(outbox_text, args3); - - outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); - } - - outbox_text_box->setValue(outbox_text); - outbox_title_box->setValue(outbox_title); - outbox_placeholder_parent->setToolTip(outbox_tooltip); -} - void LLSidepanelInventory::updateVerbs() { mInfoBtn->setEnabled(FALSE); @@ -926,13 +657,6 @@ U32 LLSidepanelInventory::getSelectedCount() { selection_list = mInventoryPanelInbox->getRootFolder()->getSelectionList(); - count += selection_list.size(); - } - - if ((count == 0) && mOutboxEnabled && (mInventoryPanelOutbox != NULL)) - { - selection_list = mInventoryPanelOutbox->getRootFolder()->getSelectionList(); - count += selection_list.size(); } @@ -957,7 +681,7 @@ BOOL LLSidepanelInventory::isMainInventoryPanelActive() const return mInventoryPanel->getVisible(); } -void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox, bool clearOutbox) +void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox) { if (clearMain) { @@ -974,15 +698,10 @@ void LLSidepanelInventory::clearSelections(bool clearMain, bool clearInbox, bool mInventoryPanelInbox->clearSelection(); } - if (clearOutbox && mOutboxEnabled && (mInventoryPanelOutbox != NULL)) - { - mInventoryPanelOutbox->clearSelection(); - } - updateVerbs(); } -std::set<LLUUID> LLSidepanelInventory::getInboxOrOutboxSelectionList() +std::set<LLUUID> LLSidepanelInventory::getInboxSelectionList() { std::set<LLUUID> inventory_selected_uuids; @@ -991,10 +710,5 @@ std::set<LLUUID> LLSidepanelInventory::getInboxOrOutboxSelectionList() inventory_selected_uuids = mInventoryPanelInbox->getRootFolder()->getSelectionList(); } - if (inventory_selected_uuids.empty() && mOutboxEnabled && (mInventoryPanelOutbox != NULL)) - { - inventory_selected_uuids = mInventoryPanelOutbox->getRootFolder()->getSelectionList(); - } - return inventory_selected_uuids; } diff --git a/indra/newview/llsidepanelinventory.h b/indra/newview/llsidepanelinventory.h index 2c6f807013..a33607f50d 100644 --- a/indra/newview/llsidepanelinventory.h +++ b/indra/newview/llsidepanelinventory.h @@ -31,7 +31,7 @@ class LLButton; class LLFolderViewItem; -class LLInboxOutboxAddedObserver; +class LLInboxAddedObserver; class LLInventoryCategoriesObserver; class LLInventoryItem; class LLInventoryPanel; @@ -47,25 +47,23 @@ public: virtual ~LLSidepanelInventory(); private: - void updateInboxOutbox(); + void updateInbox(); public: - void observeInboxOutboxCreation(); + void observeInboxCreation(); void observeInboxModifications(const LLUUID& inboxID); - void observeOutboxModifications(const LLUUID& outboxID); /*virtual*/ BOOL postBuild(); /*virtual*/ void onOpen(const LLSD& key); LLInventoryPanel* getActivePanel(); // Returns an active inventory panel, if any. LLInventoryPanel* getInboxPanel() const { return mInventoryPanelInbox; } - LLInventoryPanel* getOutboxPanel() const { return mInventoryPanelOutbox; } LLPanelMainInventory* getMainInventoryPanel() const { return mPanelMainInventory; } BOOL isMainInventoryPanelActive() const; - void clearSelections(bool clearMain, bool clearInbox, bool clearOutbox); - std::set<LLUUID> getInboxOrOutboxSelectionList(); + void clearSelections(bool clearMain, bool clearInbox); + std::set<LLUUID> getInboxSelectionList(); void showItemInfoPanel(); void showTaskInfoPanel(); @@ -75,18 +73,13 @@ public: bool canShare(); void onToggleInboxBtn(); - void onToggleOutboxBtn(); void enableInbox(bool enabled); - void enableOutbox(bool enabled); void openInbox(); - void openOutbox(); bool isInboxEnabled() const { return mInboxEnabled; } - bool isOutboxEnabled() const { return mOutboxEnabled; } - void updateOutboxUserStatus(); void updateVerbs(); protected: @@ -100,9 +93,6 @@ protected: bool canWearSelected(); // check whether selected items can be worn void onInboxChanged(const LLUUID& inbox_id); - void onOutboxChanged(const LLUUID& outbox_id); - - bool manageInboxOutboxPanels(LLButton * pressedButton, LLLayoutPanel * pressedPanel, LLButton * otherButton, LLLayoutPanel * otherPanel); // // UI Elements @@ -110,7 +100,6 @@ protected: private: LLPanel* mInventoryPanel; // Main inventory view LLInventoryPanel* mInventoryPanelInbox; - LLInventoryPanel* mInventoryPanelOutbox; LLSidepanelItemInfo* mItemPanel; // Individual item view LLSidepanelTaskInfo* mTaskPanel; // Individual in-world object view LLPanelMainInventory* mPanelMainInventory; @@ -135,10 +124,9 @@ private: LLButton* mShopBtn; bool mInboxEnabled; - bool mOutboxEnabled; - LLInventoryCategoriesObserver* mCategoriesObserver; - LLInboxOutboxAddedObserver* mInboxOutboxAddedObserver; + LLInventoryCategoriesObserver* mCategoriesObserver; + LLInboxAddedObserver* mInboxAddedObserver; }; #endif //LL_LLSIDEPANELINVENTORY_H diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 92f007a251..273d23d1a0 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -86,6 +86,8 @@ public: EAcceptance getLastAccept() { return mLastAccept; } boost::signals2::connection setEndDragCallback( const enddrag_signal_t::slot_type& cb ) { return mEndDragSignal.connect(cb); } + + uuid_vec_t::size_type getCargoIDsCount() const { return mCargoIDs.size(); } protected: enum EDropTarget diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 7eb54271f4..c1cc9c7bc4 100755 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -95,6 +95,12 @@ bool LLGoogleTranslationHandler::parseResponse( return parseTranslation(root, translation, detected_lang); } +// virtual +bool LLGoogleTranslationHandler::isConfigured() const +{ + return !getAPIKey().empty(); +} + // static void LLGoogleTranslationHandler::parseErrorResponse( const Json::Value& root, @@ -218,6 +224,12 @@ bool LLBingTranslationHandler::parseResponse( return true; } +// virtual +bool LLBingTranslationHandler::isConfigured() const +{ + return !getAPIKey().empty(); +} + // static std::string LLBingTranslationHandler::getAPIKey() { @@ -332,6 +344,12 @@ std::string LLTranslate::getTranslateLanguage() } // static +bool LLTranslate::isTranslationConfigured() +{ + return getPreferredHandler().isConfigured(); +} + +// static const LLTranslationAPIHandler& LLTranslate::getPreferredHandler() { EService service = SERVICE_BING; diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index c2330daa81..424bc14587 100755 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -89,6 +89,11 @@ public: std::string& detected_lang, std::string& err_msg) const = 0; + /** + * @return if the handler is configured to function properly + */ + virtual bool isConfigured() const = 0; + virtual ~LLTranslationAPIHandler() {} protected: @@ -115,6 +120,7 @@ public: std::string& translation, std::string& detected_lang, std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; private: static void parseErrorResponse( @@ -148,6 +154,7 @@ public: std::string& translation, std::string& detected_lang, std::string& err_msg) const; + /*virtual*/ bool isConfigured() const; private: static std::string getAPIKey(); }; @@ -275,8 +282,17 @@ public : * @param key Key to verify. */ static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key); + + /** + * @return translation target language + */ static std::string getTranslateLanguage(); + /** + * @return true if translation is configured properly. + */ + static bool isTranslationConfigured(); + private: static const LLTranslationAPIHandler& getPreferredHandler(); static const LLTranslationAPIHandler& getHandler(EService service); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 8406f639df..01650881f9 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -83,6 +83,7 @@ #include "llfloaternotificationsconsole.h" #include "llfloaterobjectweights.h" #include "llfloateropenobject.h" +#include "llfloateroutbox.h" #include "llfloaterpay.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -238,6 +239,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("object_weights", "floater_object_weights.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterObjectWeights>); LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOpenObject>); + LLFloaterReg::add("outbox", "floater_merchant_outbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterOutbox>); LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); LLFloaterPayUtil::registerFloater(); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 42dabdec0d..046360e9e9 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -26,46 +26,48 @@ #include "llviewerprecompiledheaders.h" +#include "llviewermedia.h" + #include "llagent.h" #include "llagentcamera.h" -#include "llviewermedia.h" -#include "llviewermediafocus.h" -#include "llmimetypes.h" +#include "llappviewer.h" +#include "llaudioengine.h" // for gAudiop +#include "llcallbacklist.h" +#include "lldir.h" +#include "lldiriterator.h" +#include "llevent.h" // LLSimpleListener +#include "llfilepicker.h" +#include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. +#include "llfocusmgr.h" +#include "llkeyboard.h" +#include "lllogininstance.h" +#include "llmarketplacefunctions.h" #include "llmediaentry.h" +#include "llmimetypes.h" +#include "llmutelist.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llpanelprofile.h" +#include "llparcel.h" +#include "llpluginclassmedia.h" +#include "llplugincookiestore.h" +#include "llurldispatcher.h" +#include "lluuid.h" #include "llversioninfo.h" +#include "llviewermediafocus.h" #include "llviewercontrol.h" -#include "llviewertexture.h" +#include "llviewernetwork.h" #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewertexture.h" #include "llviewertexturelist.h" -#include "llvovolume.h" -#include "llpluginclassmedia.h" -#include "llplugincookiestore.h" #include "llviewerwindow.h" -#include "llfocusmgr.h" -#include "llcallbacklist.h" -#include "llparcel.h" -#include "llaudioengine.h" // for gAudiop -#include "llurldispatcher.h" #include "llvoavatar.h" #include "llvoavatarself.h" -#include "llviewerregion.h" +#include "llvovolume.h" #include "llwebprofile.h" #include "llwebsharing.h" // For LLWebSharing::setOpenIDCookie(), *TODO: find a better way to do this! -#include "llfilepicker.h" -#include "llnotifications.h" -#include "lldir.h" -#include "lldiriterator.h" -#include "llevent.h" // LLSimpleListener -#include "llnotificationsutil.h" -#include "lluuid.h" -#include "llkeyboard.h" -#include "llmutelist.h" -#include "llpanelprofile.h" -#include "llappviewer.h" -#include "lllogininstance.h" -//#include "llfirstuse.h" -#include "llviewernetwork.h" #include "llwindow.h" #include "llvieweraudio.h" @@ -1398,75 +1400,11 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom } -// This is defined in two files but I don't want to create a dependence between this and llsidepanelinventory -// just to be able to temporarily disable the outbox. -#define ENABLE_INVENTORY_DISPLAY_OUTBOX 0 // keep in sync with ENABLE_MERCHANT_OUTBOX_PANEL, ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU - -class LLInventoryUserStatusResponder : public LLHTTPClient::Responder -{ -public: - LLInventoryUserStatusResponder() - : LLCurl::Responder() - { - } - - void completed(U32 status, const std::string& reason, const LLSD& content) - { - if (isGoodStatus(status)) - { - std::string merchantStatus = content[gAgent.getID().getString()].asString(); - llinfos << "Marketplace merchant status: " << merchantStatus << llendl; - - // Save the merchant status before turning on the display - gSavedSettings.setString("InventoryMarketplaceUserStatus", merchantStatus); - - // Complete success - gSavedSettings.setBOOL("InventoryDisplayInbox", true); - -#if ENABLE_INVENTORY_DISPLAY_OUTBOX - gSavedSettings.setBOOL("InventoryDisplayOutbox", true); -#endif - } - else if (status == 401) - { - // API is available for use but OpenID authorization failed - gSavedSettings.setBOOL("InventoryDisplayInbox", true); - } - else - { - // API in unavailable - llinfos << "Marketplace API is unavailable -- Inbox may be disabled, status = " << status << ", reason = " << reason << llendl; - } - } -}; - - -void doOnetimeEarlyHTTPRequests() -{ - std::string url = "https://marketplace.secondlife.com/"; - - if (!LLGridManager::getInstance()->isInProductionGrid()) - { - std::string gridLabel = LLGridManager::getInstance()->getGridLabel(); - url = llformat("https://marketplace.%s.lindenlab.com/", utf8str_tolower(gridLabel).c_str()); - - // TEMP for Jim's pdp - //url = "http://pdp24.lindenlab.com:3000/"; - } - - url += "api/1/users/"; - url += gAgent.getID().getString(); - url += "/user_status"; - - llinfos << "http get: " << url << llendl; - LLHTTPClient::get(url, new LLInventoryUserStatusResponder(), LLViewerMedia::getHeaders()); -} - - LLSD LLViewerMedia::getHeaders() { LLSD headers = LLSD::emptyMap(); headers["Accept"] = "*/*"; + headers["Content-Type"] = "application/xml"; headers["Cookie"] = sOpenIDCookie; headers["User-Agent"] = getCurrentUserAgent(); @@ -1521,9 +1459,6 @@ void LLViewerMedia::setOpenIDCookie() LLHTTPClient::get(profile_url, new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), headers); - - // FUI: No longer perform the user_status query - //doOnetimeEarlyHTTPRequests(); } } @@ -1966,7 +1901,7 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } } - LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; + LL_WARNS_ONCE("Plugin") << "plugin intialization failed for mime type: " << media_type << LL_ENDL; LLSD args; args["MIME_TYPE"] = media_type; LLNotificationsUtil::add("NoPlugin", args); diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 8702ebde2a..e4a8622a4b 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -137,6 +137,7 @@ with the same filename but different name <texture name="Command_MiniCart_Icon" file_name="toolbar_icons/mini_cart.png" preload="true" /> <texture name="Command_MiniMap_Icon" file_name="toolbar_icons/mini_map.png" preload="true" /> <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> + <texture name="Command_Outbox_Icon" file_name="toolbar_icons/outbox.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> @@ -386,22 +387,9 @@ with the same filename but different name <texture name="OptionsMenu_Off" file_name="icons/OptionsMenu_Off.png" preload="false" /> <texture name="OptionsMenu_Press" file_name="icons/OptionsMenu_Press.png" preload="false" /> - <texture name="OutboxPush_Disabled" file_name="icons/OutboxPush_Disabled.png" preload="true" /> - <texture name="OutboxPush_Off" file_name="icons/OutboxPush_Off.png" preload="true" /> - <texture name="OutboxPush_On" file_name="icons/OutboxPush_On.png" preload="true" /> - <texture name="OutboxPush_On_Over" file_name="icons/OutboxPush_On_Over.png" preload="true" /> - <texture name="OutboxPush_Over" file_name="icons/OutboxPush_Over.png" preload="true" /> - <texture name="OutboxPush_Press" file_name="icons/OutboxPush_Press.png" preload="true" /> - <texture name="OutboxPush_Progress_1" file_name="icons/OutboxPush_Progress_1.png" preload="true" /> - <texture name="OutboxPush_Progress_2" file_name="icons/OutboxPush_Progress_2.png" preload="true" /> - <texture name="OutboxPush_Progress_3" file_name="icons/OutboxPush_Progress_3.png" preload="true" /> - <texture name="OutboxPush_Progress_4" file_name="icons/OutboxPush_Progress_4.png" preload="true" /> - <texture name="OutboxPush_Progress_5" file_name="icons/OutboxPush_Progress_5.png" preload="true" /> - <texture name="OutboxPush_Progress_6" file_name="icons/OutboxPush_Progress_6.png" preload="true" /> - <texture name="OutboxPush_Selected" file_name="icons/OutboxPush_Selected.png" preload="true" /> - <texture name="OutboxPush_Selected_Disabled" file_name="icons/OutboxPush_Selected_Disabled.png" preload="true" /> - <texture name="OutboxPush_Selected_Over" file_name="icons/OutboxPush_Selected_Over.png" preload="true" /> - <texture name="OutboxPush_Selected_Press" file_name="icons/OutboxPush_Selected_Press.png" preload="true" /> + <texture name="OutboxStatus_Success" file_name="green_checkmark.png" preload="false" /> + <texture name="OutboxStatus_Warning" file_name="icons/pop_up_caution.png" preload="false" /> + <texture name="OutboxStatus_Error" file_name="red_x.png" preload="false" /> <texture name="PanOrbit_Off" file_name="bottomtray/PanOrbit_Off.png" preload="false" /> diff --git a/indra/newview/skins/default/textures/toolbar_icons/outbox.png b/indra/newview/skins/default/textures/toolbar_icons/outbox.png Binary files differnew file mode 100644 index 0000000000..0f3db1c47c --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/outbox.png diff --git a/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml new file mode 100644 index 0000000000..0368601bf4 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_merchant_outbox.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<floater + open_positioning="cascading" + can_close="true" + can_resize="true" + height="440" + help_topic="floater_merchant_outbox" + min_width="300" + min_height="200" + name="floater_merchant_outbox" + save_rect="true" + save_visibility="true" + reuse_instance="true" + title="MERCHANT OUTBOX" + width="333" > + <string name="OutboxFolderCount0">0 folders</string> + <string name="OutboxFolderCount1">1 folder</string> + <string name="OutboxFolderCountN">[NUM] folders</string> + <panel + follows="all" + layout="topleft" + left="0" + top="0" + label="" + height="440" + width="333"> + <panel + follows="all" + left="10" + bottom="400" + width="313" + top="0" + bg_opaque_color="InventoryBackgroundColor" + > + <panel + name="outbox_inventory_placeholder_panel" + follows="all" + layout="topleft" + top="0" + left="0" + width="308" + height="400" + bg_opaque_color="InventoryBackgroundColor" + > + <text + name="outbox_inventory_placeholder_title" + type="string" + follows="top|left|right" + layout="topleft" + top="10" + left="0" + width="308" + height="25" + wrap="true" + halign="center" + font="SansSerifBold"> + Loading... + </text> + <text + name="outbox_inventory_placeholder_text" + type="string" + follows="top|left|right" + layout="topleft" + top="35" + left="0" + width="308" + height="130" + wrap="true" + halign="left" /> + </panel> + </panel> + <panel + follows="bottom|left|right" + left="10" + bottom="435" + width="313" + top="405" + bg_opaque_color="InventoryBackgroundColor" + > + <text + name="outbox_folder_count" + type="string" + follows="all" + layout="topleft" + top="7" + left="5" + width="100" + height="20" + wrap="true" + halign="left" + valign="baseline" + font="SansSerif" /> + <button + label="Send to Marketplace" + tool_tip="Push to my Marketplace Storefront" + is_toggle="false" + name="outbox_import_btn" + follows="bottom|right" + tab_stop="false" + halign="center" + top="3" + left="110" + height="25" + width="200" + enabled="false" /> + </panel> + <layout_stack name="import_progress_indicator" orientation="vertical" left="0" height="440" top="0" width="333" follows="all" visible="false"> + <layout_panel /> + <layout_panel height="45" auto_resize="false"> + <layout_stack orientation="horizontal" left="0" height="45" top="0" width="333" follows="all"> + <layout_panel width="0" /> + <layout_panel width="45" auto_resize="false"> + <loading_indicator + height="45" + layout="topleft" + left="0" + top="0" + width="45" + /> + </layout_panel> + <layout_panel width="0" /> + </layout_stack> + </layout_panel> + <layout_panel /> + </layout_stack> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_toybox.xml b/indra/newview/skins/default/xui/en/floater_toybox.xml index 493d44a9cf..72e6187a14 100644 --- a/indra/newview/skins/default/xui/en/floater_toybox.xml +++ b/indra/newview/skins/default/xui/en/floater_toybox.xml @@ -5,7 +5,7 @@ can_minimize="false" can_resize="false" default_tab_group="1" - height="330" + height="375" help_topic="toybox" layout="topleft" legacy_header_height="18" @@ -46,7 +46,7 @@ Buttons will appear as shown or as icon-only depending on each toolbar's settings. </text> <toolbar - bottom="265" + bottom="310" button_display_mode="icons_with_text" follows="all" left="20" @@ -82,11 +82,11 @@ <panel bevel_style="none" border="true" - bottom="266" + bottom="311" follows="left|bottom|right" left="20" right="-20" - top="266" /> + top="311" /> <button follows="left|bottom|right" height="23" @@ -95,7 +95,7 @@ layout="topleft" left="185" name="btn_clear_all" - top="285" + top="330" width="130"> <button.commit_callback function="Toybox.ClearAll" /> </button> @@ -107,7 +107,7 @@ layout="topleft" left="335" name="btn_restore_defaults" - top="285" + top="330" width="130"> <button.commit_callback function="Toybox.RestoreDefaults" /> </button> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 1834be2d48..3c98f8e892 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -164,12 +164,19 @@ <menu_item_separator/> <menu_item_call - label="Buy L$" + label="Buy L$..." name="Buy and Sell L$"> <menu_item_call.on_click function="BuyCurrency" /> </menu_item_call> <menu_item_call + label="Merchant Outbox..." + name="MerchantOutbox"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="outbox" /> + </menu_item_call> + <menu_item_call label="Account dashboard..." name="Manage My Account"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 0ba4b84abe..39cc1c2cb2 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -212,23 +212,44 @@ Save changes to current clothing/body part? </notification> <notification - icon="alertmodal.tga" - name="OutboxUploadComplete" - type="alertmodal"> -Marketplace upload complete. + icon="OutboxStatus_Success" + name="OutboxImportComplete" + type="outbox"> +Success + +All folders were successfully sent to the Marketplace. + <usetemplate name="okbutton" - yestext="Hooray!"/> + yestext="OK"/> </notification> <notification - icon="alertmodal.tga" - name="OutboxUploadHadErrors" - type="alertmodal"> -Marketplace upload completed with errors! Please correct the problems in your outbox and retry. Thanks. + icon="OutboxStatus_Warning" + name="OutboxImportHadErrors" + type="outbox"> +Some folders did not transfer + +Errors occurred when some folders were sent to the Marketplace. Those folders are still in your Merchant Outbox. See the error log for more information. + <usetemplate name="okbutton" - yestext="Boo!"/> + yestext="OK"/> + </notification> + + <notification + icon="OutboxStatus_Error" + name="OutboxImportFailed" + type="outbox"> +Transfer failed + +No folders were sent to the Marketplace because of a system or network error. Try again later. + +Error [ERROR_CODE] + + <usetemplate + name="okbutton" + yestext="OK"/> </notification> diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml index e6c5110999..3007be7d5e 100644 --- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel - background_visible="true" default_tab_group="1" follows="all" height="423" @@ -51,10 +50,6 @@ top="18" width="303" /> <tab_container - bg_alpha_color="DkGray" - bg_opaque_color="DkGray" - background_visible="true" - background_opaque="true" follows="all" halign="center" height="339" @@ -71,7 +66,6 @@ bg_opaque_color="DkGray2" bg_alpha_color="DkGray2" background_visible="true" - background_opaque="true" border="false" bevel_style="none" follows="all" @@ -90,7 +84,6 @@ bg_opaque_color="DkGray2" bg_alpha_color="DkGray2" background_visible="true" - background_opaque="true" border="false" bevel_style="none" follows="all" diff --git a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml index 66117615e4..a3d39e55af 100644 --- a/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml +++ b/indra/newview/skins/default/xui/en/panel_outbox_inventory.xml @@ -8,7 +8,6 @@ bg_opaque_color="DkGray2" bg_alpha_color="DkGray2" background_visible="true" - background_opaque="true" border="false" bevel_style="none" show_item_link_overlays="true" diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml index b52784d6bc..a26eb23a5d 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> <panel - background_visible="true" follows="all" height="570" label="Things" @@ -30,7 +29,7 @@ width="330"> <layout_panel name="main_inventory_layout_panel" - layout="topleft" + layout="topleft" min_dim="150" width="330" follows="bottom|left|right" @@ -48,41 +47,18 @@ height="300" width="330" /> </layout_panel> - <layout_panel - width="330" - layout="topleft" - auto_resize="true" - user_resize="false" - follows="bottom|left|right" - name="inbox_outbox_layout_panel" - visible="false" - min_dim="35" - max_dim="235" - expanded_min_dim="125" - height="235"> - <layout_stack - follows="left|right|top|bottom" - layout="topleft" - left="0" - top="0" - orientation="vertical" - name="inbox_outbox_layout_stack" - open_time_constant="0.02" - close_time_constant="0.02" - height="235" - width="330"> - <layout_panel + <layout_panel width="330" - layout="topleft" + layout="topleft" auto_resize="true" user_resize="false" follows="left|right|top" name="inbox_layout_panel" visible="false" min_dim="35" - max_dim="200" + max_dim="235" expanded_min_dim="90" - height="200"> + height="235"> <panel follows="all" layout="topleft" @@ -91,13 +67,13 @@ class="panel_marketplace_inbox" top="0" label="" - height="200" + height="235" width="330"> <string name="InboxLabelWithArg">Received items ([NUM])</string> <string name="InboxLabelNoArg">Received items</string> <button label="Received items" - font="SansSerifMedium" + font="SansSerifMedium" name="inbox_btn" height="35" width="308" @@ -129,7 +105,7 @@ <panel follows="all" left="10" - bottom="200" + bottom="235" width="308" top="35" bg_opaque_color="InventoryBackgroundColor" @@ -145,7 +121,7 @@ top="0" left="0" width="308" - height="165" + height="200" wrap="true" halign="center"> Purchases from the marketplace will be delivered here. @@ -153,139 +129,6 @@ </panel> </panel> </layout_panel> - <layout_panel - width="330" - layout="topleft" - auto_resize="true" - user_resize="false" - follows="all" - name="outbox_layout_panel" - visible="false" - min_dim="35" - max_dim="200" - expanded_min_dim="90" - height="200"> - <panel - follows="all" - layout="topleft" - left="0" - name="marketplace_outbox" - class="panel_marketplace_outbox" - top="0" - label="" - height="200" - width="330"> - <string name="OutboxLabelWithArg">Merchant outbox ([NUM])</string> - <string name="OutboxLabelNoArg">Merchant outbox</string> - <button - label="Merchant outbox" - font="SansSerifMedium" - name="outbox_btn" - height="35" - width="308" - image_unselected="MarketplaceBtn_Off" - image_selected="MarketplaceBtn_Selected" - halign="left" - handle_right_mouse="false" - follows="top|left|right" - is_toggle="true" - tab_stop="false" - pad_left="35" - top="0" - left="10" /> - <button - image_unselected="OutboxPush_Off" - image_selected="OutboxPush_Selected" - image_hover_selected="OutboxPush_Selected_Over" - image_hover_unselected="OutboxPush_Over" - image_disabled_selected="OutboxPush_Selected_Disabled" - image_disabled="OutboxPush_Disabled" - image_pressed="OutboxPush_Press" - image_pressed_selected="OutboxPush_Selected_Press" - label="" - tool_tip="Push to my Marketplace Storefront" - is_toggle="false" - name="outbox_sync_btn" - follows="top|right" - tab_stop="false" - halign="center" - top="6" - left="-50" - height="23" - width="32" - enabled="false" /> - <loading_indicator - follows="top|right" - name="outbox_sync_indicator" - top="6" - left="-50" - height="23" - width="32" - images_per_sec="1.15" - tab_stop="false" - visible="false"> - <images> - <image name="OutboxPush_Progress_1"/> - <image name="OutboxPush_Progress_2"/> - <image name="OutboxPush_Progress_3"/> - <image name="OutboxPush_Progress_4"/> - <image name="OutboxPush_Progress_5"/> - <image name="OutboxPush_Progress_6"/> - </images> - </loading_indicator> - <panel - follows="all" - left="10" - bottom="200" - width="308" - top="35" - bg_opaque_color="InventoryBackgroundColor" - background_visible="true" - background_opaque="true" - > - <panel - name="outbox_inventory_placeholder_panel" - follows="all" - layout="topleft" - top="0" - left="0" - width="308" - height="165" - bg_opaque_color="InventoryBackgroundColor" - background_visible="true" - background_opaque="true" - > - <text - name="outbox_inventory_placeholder_title" - type="string" - follows="all" - layout="topleft" - top="10" - left="0" - width="308" - height="25" - wrap="true" - halign="center" - font="SansSerifBold"> - Loading... - </text> - <text - name="outbox_inventory_placeholder_text" - type="string" - follows="all" - layout="topleft" - top="35" - left="0" - width="308" - height="130" - wrap="true" - halign="left" /> - </panel> - </panel> - </panel> - </layout_panel> - </layout_stack> - </layout_panel> </layout_stack> <panel follows="bottom|left|right" @@ -406,8 +249,7 @@ </layout_stack> </panel> </panel> - -<panel + <panel follows="all" layout="topleft" left="0" @@ -420,8 +262,7 @@ visible="false" width="330"> </panel> - -<panel + <panel follows="all" layout="topleft" left="0" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index c25d1f57d6..0d9a7e5c41 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -165,8 +165,10 @@ Please try logging in again in a minute.</string> <string name="TooltipMustSingleDrop">Only a single item can be dragged here</string> <string name="TooltipPrice" value="L$[AMOUNT]: "/> <string name="TooltipOutboxNoTransfer">One or more of these objects cannot be sold or transferred to another user.</string> + <string name="TooltipOutboxNotInInventory">You can only transfer objects in your inventory to your merchant outbox.</string> <string name="TooltipOutboxWorn">You are wearing one or more of these objects. Remove them from your avatar and try moving them again.</string> <string name="TooltipOutboxFolderLevels">This folder has too many levels of subfolders. Rearrange the interior folders to a maximum of 4 levels deep (Root Folder contains A contains B contains C).</string> + <string name="TooltipOutboxTooManyFolders">This folder has too many subfolders. Reorganize the interior to a maximum of 20 folders.</string> <string name="TooltipOutboxTooManyObjects">This folder contains more than 200 objects. Box some of the items to reduce the object count.</string> <!-- tooltips for Urls --> @@ -2029,18 +2031,29 @@ Returns a string with the requested data about the region <string name="FavoritesNoMatchingItems">Drag a landmark here to add it to your favorites.</string> <string name="InventoryNoTexture">You do not have a copy of this texture in your inventory</string> <string name="InventoryInboxNoItems">When you purchase or otherwise receive an item, it will appear here so you can drag it to a folder in your inventory, or delete it if you do not wish to keep it.</string> - <string name="MarketplaceURL">http://marketplace.[DOMAIN_NAME]</string> - <string name="MarketplaceURL_CreateStore">http://marketplace.[DOMAIN_NAME]/create_store</string> - <string name="MarketplaceURL_LearnMore">http://marketplace.[DOMAIN_NAME]/learn_more</string> + <string name="MarketplaceURL">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/</string> + <string name="MarketplaceURL_CreateStore">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/create_store</string> + <string name="MarketplaceURL_Dashboard">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/merchants/[AGENT_ID]/store/dashboard</string> + <string name="MarketplaceURL_LearnMore">https://marketplace.[MARKETPLACE_DOMAIN_NAME]/learn_more</string> <string name="InventoryOutboxCreationErrorTitle">Your Merchant Outbox is not properly configured</string> <string name="InventoryOutboxCreationErrorTooltip">Merchant Outbox configuration error</string> <string name="InventoryOutboxCreationError">Please contact Customer Service to correct the problem.</string> - <string name="InventoryOutboxNotMerchantTitle">Anyone can sell items on the Marketplace</string> + <string name="InventoryOutboxNotMerchantTitle">Anyone can sell items on the Marketplace.</string> <string name="InventoryOutboxNotMerchantTooltip">Become a merchant!</string> - <string name="InventoryOutboxNotMerchant">[[MARKETPLACE_URL] The Second Life Marketplace] offers more than one million virtual products for sale, all of them created by Residents. You, too, can sell items you create, as well as some of the items you have purchased. It’s easy and setup is free. [[LEARN_MORE_URL] Learn more] or [[CREATE_STORE_URL] create a store] on the Marketplace to get started.</string> - <string name="InventoryOutboxNoItemsTitle">A new way to send items to the Marketplace</string> + <string name="InventoryOutboxNotMerchant"> +The Second Life Marketplace offers more than one million virtual products for sale, all of them created by Residents like you. You too can create items and sell them on the Marketplace. Creating a store is easy and free of charge. + +[[MARKETPLACE_URL] Visit the Marketplace] + +[[MARKETPLACE_LEARN_MORE_URL] Learn more about creating a store] + </string> + <string name="InventoryOutboxNoItemsTitle">Your outbox is empty.</string> <string name="InventoryOutboxNoItemsTooltip">Drag and drop items here to prepare them for sale on the Marketplace</string> - <string name="InventoryOutboxNoItems">Drag items or folders that you wish to sell into this area. A copy of the item will appear, leaving your inventory unchanged, unless you have dragged a no-copy item. When you are ready to send the items to the Marketplace, click the Upload button. Once your items have been moved to your Marketplace Inventory, they will disappear from this folder.</string> + <string name="InventoryOutboxNoItems"> +Drag folders to this area. When you are ready to send them to the Marketplace for sale, click the "Send to Marketplace" button below. + +[[MARKETPLACE_DASHBOARD_URL] Go to your Merchant Dashboard] + </string> <string name="Marketplace Error None">No errors</string> <string name="Marketplace Error Not Merchant">Error: Before sending items to the Marketplace you will need to set yourself up as a merchant (free of charge).</string> @@ -3675,6 +3688,7 @@ Try enclosing path to the editor with double quotes. <string name="Command_Marketplace_Label">Marketplace</string> <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> + <string name="Command_Outbox_Label">Merchant outbox</string> <string name="Command_People_Label">People</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> @@ -3700,6 +3714,7 @@ Try enclosing path to the editor with double quotes. <string name="Command_Marketplace_Tooltip">Go shopping</string> <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> + <string name="Command_Outbox_Tooltip">Transfer items to your marketplace for sale</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> diff --git a/indra/newview/skins/default/xui/en/widgets/window_shade.xml b/indra/newview/skins/default/xui/en/widgets/window_shade.xml new file mode 100644 index 0000000000..23eb2f13fb --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/window_shade.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<window_shade shade_color="0 0 0 0.5"/> |