From 7a35a43bd43bf6ce651373bd692e0dcc30abdd96 Mon Sep 17 00:00:00 2001 From: Lirusaito Date: Tue, 6 Nov 2012 20:23:36 -0500 Subject: [PATCH] Merchant Outbox! Enter: LLFloaterOutbox, floater_merchant_outbox, LLMarketplaceFunctions, LLPanelMarketplaceOutboxInventory, and panel_outbox_inventory LLView now has childFromPoint() from v-d. LLInventoryBridge{ Sync includes with v-d. Let's ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU for ease of access and tweak it to work. Uncomment related code. Catch if we're moving objects into the outbox during pasteFromClipboard() } LLInventoryPanel: start_folder attribute for inventory_panels, this could be quite useful in the future Sync LLToolDragAndDrop with Catznip/v-d Add the outbox to the World menu, since that seems to involve most commerce. Perhaps we should add a menu entry to the outbox itself to open its floater? Fix the inventory merchant menu entries, thanks Shyotl.. Merchant Outbox Strings! --- indra/llui/llview.cpp | 33 + indra/llui/llview.h | 7 +- indra/newview/CMakeLists.txt | 6 + indra/newview/llappviewer.cpp | 4 +- indra/newview/llfloateroutbox.cpp | 591 ++++++++++++++++++ indra/newview/llfloateroutbox.h | 115 ++++ indra/newview/llinventorybridge.cpp | 135 ++-- indra/newview/llinventoryfunctions.cpp | 3 +- indra/newview/llinventorypanel.cpp | 50 +- indra/newview/llinventorypanel.h | 2 + indra/newview/llmarketplacefunctions.cpp | 484 ++++++++++++++ indra/newview/llmarketplacefunctions.h | 94 +++ .../llpanelmarketplaceoutboxinventory.cpp | 149 +++++ .../llpanelmarketplaceoutboxinventory.h | 74 +++ indra/newview/lltooldraganddrop.cpp | 16 +- indra/newview/llviewermenu.cpp | 9 + .../xui/en-us/floater_merchant_outbox.xml | 146 +++++ .../default/xui/en-us/menu_inventory.xml | 6 +- .../skins/default/xui/en-us/menu_viewer.xml | 6 + .../xui/en-us/panel_outbox_inventory.xml | 17 + .../skins/default/xui/en-us/strings.xml | 17 + 21 files changed, 1897 insertions(+), 67 deletions(-) create mode 100644 indra/newview/llfloateroutbox.cpp create mode 100644 indra/newview/llfloateroutbox.h create mode 100644 indra/newview/llmarketplacefunctions.cpp create mode 100644 indra/newview/llmarketplacefunctions.h create mode 100644 indra/newview/llpanelmarketplaceoutboxinventory.cpp create mode 100644 indra/newview/llpanelmarketplaceoutboxinventory.h create mode 100644 indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml create mode 100644 indra/newview/skins/default/xui/en-us/panel_outbox_inventory.xml diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 089be0788..ae81cce24 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -893,6 +893,39 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) } return NULL; } + +LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) +{ + if (!getVisible()) + return NULL; + + BOOST_FOREACH(LLView* viewp, mChildList) + { + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (!viewp->visibleAndContains(local_x, local_y)) + { + continue; + } + // Here we've found the first (frontmost) visible child at this level + // containing the specified point. Is the caller asking us to drill + // down and return the innermost leaf child at this point, or just the + // top-level child? + if (recur) + { + LLView* leaf(viewp->childFromPoint(local_x, local_y, recur)); + // Maybe viewp is already a leaf LLView, or maybe it has children + // but this particular (x, y) point falls between them. If the + // recursive call returns non-NULL, great, use that; else just use + // viewp. + return leaf? leaf : viewp; + } + return viewp; + + } + return 0; +} + BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent) { BOOL handled = FALSE; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index ee2ad2d3e..a742b2c56 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -394,11 +394,9 @@ public: void setShape(const LLRect& new_rect, bool by_user = false); virtual LLView* findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir, LLView::ESnapType snap_type, S32 threshold, S32 padding = 0); virtual LLView* findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding = 0); - virtual BOOL canSnapTo(const LLView* other_view); - virtual void setSnappedTo(const LLView* snap_view); - + // inherited from LLFocusableElement /* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); /* virtual */ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); @@ -478,6 +476,7 @@ public: /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); // Display mToolTipMsg if no child handles it. + /*virtual*/ const std::string& getName() const; /*virtual*/ void onMouseCaptureLost(); /*virtual*/ BOOL hasMouseCapture(); @@ -485,6 +484,8 @@ public: /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const; /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const; + virtual LLView* childFromPoint(S32 x, S32 y, bool recur=false); + template T* findChild(const std::string& name) { return getChild(name,true,false); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index bb65bee83..c731b4bdc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -225,6 +225,7 @@ set(viewer_SOURCE_FILES llfloaternotificationsconsole.cpp llfloaterobjectiminfo.cpp llfloateropenobject.cpp + llfloateroutbox.cpp llfloaterparcel.cpp llfloaterpermissionsmgr.cpp llfloaterperms.cpp @@ -305,6 +306,7 @@ set(viewer_SOURCE_FILES llmanipscale.cpp llmaniptranslate.cpp llmapresponders.cpp + llmarketplacefunctions.cpp llmarketplacenotifications.cpp llmediactrl.cpp llmediaremotectrl.cpp @@ -357,6 +359,7 @@ set(viewer_SOURCE_FILES llpanellandoptions.cpp llpanellogin.cpp llpanelmaininventory.cpp + llpanelmarketplaceoutboxinventory.cpp llpanelmediahud.cpp llpanelmorph.cpp llpanelmsgs.cpp @@ -727,6 +730,7 @@ set(viewer_HEADER_FILES llfloaternotificationsconsole.h llfloaterobjectiminfo.h llfloateropenobject.h + llfloateroutbox.h llfloaterparcel.h llfloaterpermissionsmgr.h llfloaterperms.h @@ -807,6 +811,7 @@ set(viewer_HEADER_FILES llmanipscale.h llmaniptranslate.h llmapresponders.h + llmarketplacefunctions.h llmarketplacenotifications.h llmediactrl.h llmediaremotectrl.h @@ -859,6 +864,7 @@ set(viewer_HEADER_FILES llpanellandoptions.h llpanellogin.h llpanelmaininventory.h + llpanelmarketplaceoutboxinventory.h llpanelmediahud.h llpanelmorph.h llpanelmsgs.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 72d94258d..39298f4db 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -51,7 +51,7 @@ #include "llagentwearables.h" #include "llwindow.h" #include "llviewerstats.h" -//#include "llmarketplacefunctions.h" +#include "llmarketplacefunctions.h" #include "llmarketplacenotifications.h" #include "llmd5.h" #include "llmeshrepository.h" @@ -4090,7 +4090,7 @@ void LLAppViewer::idle() LLViewerMediaFocus::getInstance()->update(); // Update marketplace - //LLMarketplaceInventoryImporter::update(); + LLMarketplaceInventoryImporter::update(); LLMarketplaceInventoryNotifications::update(); // objects and camera should be in sync, do LOD calculations now diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp new file mode 100644 index 000000000..67e6b45c9 --- /dev/null +++ b/indra/newview/llfloateroutbox.cpp @@ -0,0 +1,591 @@ +/** + * @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 "llfolderview.h" +#include "llinventorybridge.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventoryobserver.h" +#include "llinventorypanel.h" +#include "llmarketplacefunctions.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "lltextbox.h" +#include "lltexteditor.h" +//#include "lltransientfloatermgr.h" +#include "lltrans.h" +#include "llviewernetwork.h" +//#include "llwindowshade.h" + +#define USE_WINDOWSHADE_DIALOGS 0 + + +///---------------------------------------------------------------------------- +/// LLOutboxNotification class +///---------------------------------------------------------------------------- + +class LLOutboxNotification +{ +public: + bool processNotification(const LLSD& notify) + { + LLFloaterOutbox* outbox_floater = LLFloaterOutbox::getInstance(); + + outbox_floater->showNotification(notify); + + 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) + , mImportBusy(false) + , mImportButton(NULL) + , mInventoryFolderCountText(NULL) + , mInventoryImportInProgress(NULL) + , mInventoryPlaceholder(NULL) + , mInventoryText(NULL) + , mInventoryTitle(NULL) + , mOutboxId(LLUUID::null) + , mOutboxInventoryPanel(NULL) + , mOutboxItemCount(0) + , mOutboxTopLevelDropZone(NULL) +// , mWindowShade(NULL) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_merchant_outbox.xml"); + +} + +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("outbox_folder_count"); + mInventoryImportInProgress = getChild("import_progress_indicator"); + mInventoryPlaceholder = getChild("outbox_inventory_placeholder_panel"); + mInventoryText = mInventoryPlaceholder->getChild("outbox_inventory_placeholder_text"); + // For some reason, adding style doesn't work unless this is true. + mInventoryText->setParseHTML(TRUE); + + mInventoryTitle = mInventoryPlaceholder->getChild("outbox_inventory_placeholder_title"); + + mImportButton = getChild("outbox_import_btn"); + mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this)); + + mOutboxTopLevelDropZone = getChild("outbox_generic_drag_target"); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this)); + + return TRUE; +} + +void LLFloaterOutbox::onClose(bool app_quitting) +{ +/* + if (mWindowShade) + { + delete mWindowShade; + + mWindowShade = NULL; + } +*/ + setVisible(FALSE); + //destroy(); //Don't because outbox should be persistent. +} + +void LLFloaterOutbox::onOpen() +{ + // + // 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 = getChild("panel_outbox_inventory"); + + 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& importer = LLMarketplaceInventoryImporter::instance(); + + importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2)); + importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); + importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); + importer.initialize(); +} + +void LLFloaterOutbox::setStatusString(const std::string& statusString) +{ + llassert(mInventoryFolderCountText != NULL); + + mInventoryFolderCountText->setText(statusString); +} + +void LLFloaterOutbox::updateFolderCount() +{ + 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 (!mImportBusy) + { + updateFolderCountStatus(); + } +} + +void LLFloaterOutbox::updateFolderCountStatus() +{ + if (mOutboxInventoryPanel) + { + switch (mOutboxItemCount) + { + case 0: setStatusString(getString("OutboxFolderCount0")); break; + case 1: setStatusString(getString("OutboxFolderCount1")); break; + default: + { + std::string item_count_str = llformat("%d", mOutboxItemCount); + + LLStringUtil::format_map_t args; + args["[NUM]"] = item_count_str; + + setStatusString(getString("OutboxFolderCountN", args)); + break; + } + } + } + + mImportButton->setEnabled(mOutboxItemCount > 0); +} + +void LLFloaterOutbox::updateView() +{ + //updateView() is called twice the first time. + updateFolderCount(); + + 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; + + const LLSD& subs = getMarketplaceStringSubstitutions(); + + // Text styles for marketplace hyperlinks + std::string subs_link; + std::string subs_text; + + if (mOutboxId.notNull()) + { + outbox_text = LLTrans::getString("InventoryOutboxNoItems"); + subs_link = "[MARKETPLACE_DASHBOARD_URL]"; + subs_text = " " + LLTrans::getString("InventoryOutboxNoItemsSubs"); + outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle"); + outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip"); + } + else + { + outbox_text = LLTrans::getString("InventoryOutboxNotMerchant"); + subs_link = "[MARKETPLACE_CREATE_STORE_URL]"; + subs_text = " " + LLTrans::getString("InventoryOutboxNotMerchantSubs"); + outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); + outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); + } + + mInventoryText->clear(); + mInventoryText->appendColoredText(outbox_text, false, false, gColors.getColor("TextFgReadOnlyColor")); + LLStringUtil::format(subs_link, subs); + LLStyleSP subs_link_style(new LLStyle); + subs_link_style->setLinkHREF(subs_link); + subs_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + mInventoryText->appendStyledText(subs_text, false, false, subs_link_style); + mInventoryTitle->setValue(outbox_title); + mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip); + } +} + +bool isAccepted(EAcceptance accept) +{ + return (accept >= ACCEPT_YES_COPY_SINGLE); +} + +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); + + // Determine if the mouse is inside the inventory panel itself or just within the floater + bool pointInInventoryPanel = false; + bool pointInInventoryPanelChild = false; + LLFolderView * root_folder = mOutboxInventoryPanel->getRootFolder(); + if (mOutboxInventoryPanel->getVisible()) + { + S32 inv_x, inv_y; + localPointToOtherView(x, y, &inv_x, &inv_y, mOutboxInventoryPanel); + + pointInInventoryPanel = mOutboxInventoryPanel->getRect().pointInRect(inv_x, inv_y); + + LLView * inventory_panel_child_at_point = mOutboxInventoryPanel->childFromPoint(inv_x, inv_y, true); + pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder); + } + + // Pass all drag and drop for this floater to the outbox inventory control + if (!handled || !isAccepted(*accept)) + { + // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel + // (otherwise the inventory panel itself will handle the drag and drop operation, without any override) + if (!pointInInventoryPanel) + { + handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + mOutboxTopLevelDropZone->setBackgroundVisible(handled && !drop && isAccepted(*accept)); + } + else + { + mOutboxTopLevelDropZone->setBackgroundVisible(!pointInInventoryPanelChild); + } + + return handled; +} + +BOOL LLFloaterOutbox::handleHover(S32 x, S32 y, MASK mask) +{ + mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); + + return LLFloater::handleHover(x, y, mask); +} +/* +void LLFloaterOutbox::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); + + LLFloater::onMouseLeave(x, y, mask); +} +*/ +void LLFloaterOutbox::onImportButtonClicked() +{ + mOutboxInventoryPanel->clearSelection(); + + mImportBusy = 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) + { + const LLSD& subs = getMarketplaceStringSubstitutions(); + + LLNotificationsUtil::add("OutboxImportHadErrors", subs); + } + else + { + char status_string[16]; + sprintf(status_string, "%d", status); + + LLSD subs; + subs["[ERROR_CODE]"] = status_string; + + LLNotificationsUtil::add("OutboxImportFailed", subs); + } + + updateView(); +} + +void LLFloaterOutbox::importStatusChanged(bool inProgress) +{ + if (inProgress) + { + if (mImportBusy) + { + setStatusString(getString("OutboxImporting")); + } + else + { + setStatusString(getString("OutboxInitializing")); + } + + mImportBusy = true; + mImportButton->setEnabled(false); + mInventoryImportInProgress->setVisible(true); + } + else + { + mImportBusy = false; + mImportButton->setEnabled(mOutboxItemCount > 0); + mInventoryImportInProgress->setVisible(false); + } + + updateView(); +} + +void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content) +{ + if (status != MarketplaceErrorCodes::IMPORT_DONE) + { + char status_string[16]; + sprintf(status_string, "%d", status); + + LLSD subs; + subs["[ERROR_CODE]"] = status_string; + + LLNotificationsUtil::add("OutboxInitFailed", subs); + } + + updateView(); +} + +void LLFloaterOutbox::showNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (!notification) + { + llerrs << "Unable to find outbox notification!" << notify.asString() << llendl; + + return; + } + +#if USE_WINDOWSHADE_DIALOGS + + 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(params); + + addChild(mWindowShade); + mWindowShade->show(notification); + +#else //USE_WINDOWSHADE_DIALOGS +/* + LLNotificationsUI::LLEventHandler * handler = + LLNotificationsUI::LLNotificationManager::instance().getHandlerForNotification("alertmodal"); + + LLNotificationsUI::LLSysHandler * sys_handler = dynamic_cast(handler); + llassert(sys_handler); + + sys_handler->processNotification(notify); +*/ + LLNotifications::instance().add(notification); +#endif //USE_WINDOWSHADE_DIALOGS +} + diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h new file mode 100644 index 000000000..92f301416 --- /dev/null +++ b/indra/newview/llfloateroutbox.h @@ -0,0 +1,115 @@ +/** + * @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 LLTextEditor; +class LLView; +//class LLWindowShade; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFloaterOutbox +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFloaterOutbox : public LLFloater, public LLFloaterSingleton +{ +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(const LLSD& notify); + + BOOL handleHover(S32 x, S32 y, MASK mask); +// void onMouseLeave(S32 x, S32 y, MASK mask); + +protected: + void fetchOutboxContents(); + + void importReportResults(U32 status, const LLSD& content); + void importStatusChanged(bool inProgress); + void initializationReportError(U32 status, const LLSD& content); + + void onClose(bool app_quitting); + void onOpen(); + + void onFocusReceived(); + + void onImportButtonClicked(); + void onOutboxChanged(); + + void setStatusString(const std::string& statusString); + + void updateFolderCount(); + void updateFolderCountStatus(); + void updateView(); + +private: + LLInventoryCategoriesObserver * mCategoriesObserver; + LLInventoryCategoryAddedObserver * mCategoryAddedObserver; + + bool mImportBusy; + LLButton * mImportButton; + + LLTextBox * mInventoryFolderCountText; + LLView * mInventoryImportInProgress; + LLView * mInventoryPlaceholder; + LLTextEditor * mInventoryText; + LLTextBox * mInventoryTitle; + + LLUUID mOutboxId; + LLInventoryPanel * mOutboxInventoryPanel; + U32 mOutboxItemCount; + LLPanel * mOutboxTopLevelDropZone; + + //LLWindowShade * mWindowShade; +}; + +#endif // LL_LLFLOATEROUTBOX_H diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 43499ff8d..b9d07da6d 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llinventorybridge.cpp * @brief Implementation of the Inventory-Folder-View-Bridge classes. * @@ -34,49 +34,47 @@ #include // for std::pair<> -#include "llinventorypanel.h" #include "llinventorybridge.h" -#include "llinventorydefines.h" -#include "llinventoryfunctions.h" -#include "llinventoryicon.h" -#include "llinventorymodelbackgroundfetch.h" - -#include "lltrans.h" #include "message.h" -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llattachmentsmgr.h" -#include "llagentcamera.h" -#include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons #include "llradiogroup.h" #include "llspinctrl.h" #include "lltextbox.h" #include "llui.h" -#include "llviewerfoldertype.h" +#include "lluictrlfactory.h" -#include "llviewercontrol.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llattachmentsmgr.h" +#include "llcallingcard.h" #include "llfirstuse.h" #include "llfloateravatarinfo.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterinventory.h" +#include "llfloateropenobject.h" #include "llfloaterproperties.h" - #include "llfloaterworldmap.h" #include "llfocusmgr.h" #include "llfolderview.h" #include "llgesturemgr.h" #include "llgiveinventory.h" #include "lliconctrl.h" -#include "llinventorymodel.h" +#include "llimview.h" #include "llinventoryclipboard.h" +#include "llinventorydefines.h" +#include "llinventoryfunctions.h" +#include "llinventoryicon.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventorypanel.h" #include "lllineeditor.h" +#include "llmarketplacefunctions.h" #include "llmenugl.h" -//#include "llmarketplacefunctions.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llpreviewanim.h" @@ -87,27 +85,25 @@ #include "llpreviewsound.h" #include "llpreviewtexture.h" #include "llresmgr.h" +#include "llselectmgr.h" #include "llscrollcontainer.h" -#include "llimview.h" -#include "llviewerassettype.h" -#include "llfoldertype.h" #include "lltooldraganddrop.h" - -#include "llviewertexturelist.h" +#include "lltabcontainer.h" +#include "lltrans.h" +#include "llviewerassettype.h" +#include "llviewercontrol.h" +#include "llviewerfoldertype.h" #include "llviewerinventory.h" - +#include "llviewermessage.h" #include "llviewerobjectlist.h" - +#include "llviewerregion.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llvoavatar.h" +#include "llfoldertype.h" #include "llwearable.h" #include "llwearablelist.h" -#include "llviewermessage.h" -#include "llviewerregion.h" -#include "lltabcontainer.h" -#include "lluictrlfactory.h" -#include "llselectmgr.h" -#include "llfloateropenobject.h" + // #include "llappviewer.h" // System Folders #include "llfloateranimpreview.h" // for reuploads @@ -133,7 +129,7 @@ // Marketplace outbox current disabled #define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 1 -#define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 0 +#define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 1 #define BLOCK_WORN_ITEMS_IN_OUTBOX 1 bool InventoryLinksEnabled() @@ -270,7 +266,7 @@ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const std::string& LLInvFVBridge::getName() const { - LLInventoryObject* obj = getInventoryObject(); + const LLInventoryObject* obj = getInventoryObject(); if(obj) { return obj->getName(); @@ -354,7 +350,7 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc S32 count = batch.count(); S32 i,j; for(i = 0; i < count; ++i) - { + { bridge = (LLInvFVBridge*)(batch.get(i)); if(!bridge || !bridge->isItemRemovable()) continue; item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); @@ -367,7 +363,7 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc } } for(i = 0; i < count; ++i) - { + { bridge = (LLInvFVBridge*)(batch.get(i)); if(!bridge || !bridge->isItemRemovable()) continue; cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); @@ -778,7 +774,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, } } - // Don't allow items to be pasted directly into the COF. + // 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")); @@ -861,7 +857,7 @@ void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items, items.push_back(std::string("Purge Item")); if (!isItemRemovable()) { - disabled_items.push_back(std::string("Purge Item")); + disabled_items.push_back(std::string("Purge Item")); } items.push_back(std::string("Restore Item")); } @@ -945,7 +941,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { return FALSE; } - + *id = obj->getUUID(); //object_ids.put(obj->getUUID()); @@ -1148,8 +1144,8 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, new_listener = new LLItemBridge(inventory, root, uuid); break; - case LLAssetType::AT_OBJECT: - if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT) + case LLAssetType::AT_OBJECT: + if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT) || inv_type == LLInventoryType::IT_TEXTURE ) //There's an abundance of objects in inv that have texture (0) as their inv type, right out of unpack. //May have been bug either in an old client, or server version. Either way... it causes a lot of spam over something ultimately harmless. { @@ -1242,7 +1238,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) { LLInventoryCategory* cat = model->getCategory(uuid); - if(cat) + if (cat) { model->purgeDescendentsOf(uuid); model->notifyObservers(); @@ -1311,10 +1307,10 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const bool can_list = true; // Do not allow listing while import is in progress - /*if (LLMarketplaceInventoryImporter::instanceExists()) + if (LLMarketplaceInventoryImporter::instanceExists()) { can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress(); - }*/ + } const LLInventoryObject* obj = getInventoryObject(); can_list &= (obj != NULL); @@ -2861,10 +2857,11 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) { llinfos << "Send to marketplace action!" << llendl; - LLInventoryCategory * cat = gInventory.getCategory(mUUID); + /*LLInventoryCategory * cat = gInventory.getCategory(mUUID); if (!cat) return; - send_to_marketplace(cat); + send_to_marketplace(cat);*/ + LLMarketplaceInventoryImporter::instance().triggerImport(); } #endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU } @@ -3028,13 +3025,55 @@ void LLFolderBridge::pasteFromClipboard() if(model && isClipboardPasteable()) { 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_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - - const LLUUID parent_id(mUUID); + const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); LLDynamicArray objects; LLInventoryClipboard::instance().retrieve(objects); + + if (move_is_into_outbox) + { + LLFolderViewItem * outbox_itemp = mRoot->getItemByID(mUUID); + + if (outbox_itemp) + { + //LLToolDragAndDrop::instance().setCargoCount(objects.size()); + + BOOL can_list = TRUE; + + for (LLDynamicArray::const_iterator iter = objects.begin(); + (iter != objects.end()) && (can_list == TRUE); + ++iter) + { + const LLUUID& item_id = (*iter); + LLInventoryItem *item = model->getItem(item_id); + + if (item) + { + MASK mask = 0x0; + BOOL drop = FALSE; + EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(item->getActualType()); + void * cargo_data = (void *) item; + //std::string tooltip_msg; + + can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data/*, tooltip_msg*/); + } + } + + //LLToolDragAndDrop::instance().resetCargoCount(); + + if (can_list == FALSE) + { + // Notify user of failure somehow -- play error sound? modal dialog? + return; + } + } + } + + const LLUUID parent_id(mUUID); + for (LLDynamicArray::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 14c2de40f..06153ad72 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -45,6 +45,7 @@ #include "llappviewer.h" //#include "llfirstuse.h" #include "llfloaterinventory.h" +#include "llfloateroutbox.h" #include "llfocusmgr.h" #include "llfolderview.h" #include "llgesturemgr.h" @@ -430,7 +431,7 @@ void show_item_profile(const LLUUID& item_uuid) void open_outbox() { - //LLFloaterReg::showInstance("outbox"); + LLFloaterOutbox::showInstance(); } LLUUID create_folder_in_outbox_for_item(LLInventoryItem* item, const LLUUID& destFolderId, S32 operation_id) diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 0f6fa9e78..2fcdd59f2 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -44,6 +44,7 @@ #include "llscrollcontainer.h" #include "llviewerassettype.h" #include "llpanelmaininventory.h" +#include "llpanelmarketplaceoutboxinventory.h" #include "llsdserialize.h" @@ -130,6 +131,7 @@ void LLInvPanelComplObserver::done() LLInventoryPanel::LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, + const std::string& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -140,6 +142,7 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, mFolderRoot(NULL), mScroller(NULL), mSortOrderSetting(sort_order_setting), + mStartFolder(start_folder), mInventory(inventory), mAllowMultiSelect(allow_multi_select), mViewsInitialized(false), @@ -154,12 +157,38 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, void LLInventoryPanel::buildFolderView() { + // Determine the root folder in case specified, and + // build the views starting with that folder. + + //std::string start_folder_name(params.start_folder()); + + const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolder); + + LLUUID root_id; + + if ("LIBRARY" == mStartFolder) + { + root_id = gInventory.getLibraryRootFolderID(); + } + else + { + root_id = (preferred_type != LLFolderType::FT_NONE) + ? gInventory.findCategoryUUIDForType(preferred_type, false, false) + : LLUUID::null; + } + + if ((root_id == LLUUID::null) && !mStartFolder.empty()) + { + llwarns << "No category found that matches start_folder: " << mStartFolder << llendl; + root_id = LLUUID::generateNewID(); + } + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, LLAssetType::AT_CATEGORY, LLInventoryType::IT_CATEGORY, this, NULL, - LLUUID::null); + root_id); mFolderRoot = createFolderView(new_listener, true/*params.use_label_suffix()*/); } @@ -247,6 +276,7 @@ class LLInventoryRecentItemsPanel : public LLInventoryPanel public: LLInventoryRecentItemsPanel(const std::string& name, const std::string& sort_order_setting, + const std::string& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -270,12 +300,19 @@ LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac std::string sort_order(INHERIT_SORT_ORDER); node->getAttributeString("sort_order", sort_order); - if(name != "Recent Items") - panel = new LLInventoryPanel(name, sort_order, + std::string start_folder; + node->getAttributeString("start_folder", start_folder); + + if(name == "Recent Items") + panel = new LLInventoryRecentItemsPanel(name, sort_order, start_folder, + rect, &gInventory, + allow_multi_select, parent); + else if(name == "panel_outbox_inventory") + panel = new LLOutboxInventoryPanel(name, sort_order, start_folder, rect, &gInventory, allow_multi_select, parent); else - panel = new LLInventoryRecentItemsPanel(name, sort_order, + panel = new LLInventoryPanel(name, sort_order, start_folder, rect, &gInventory, allow_multi_select, parent); @@ -1058,11 +1095,12 @@ static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER; LLInventoryRecentItemsPanel:: LLInventoryRecentItemsPanel(const std::string& name, const std::string& sort_order_setting, + const std::string& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, - LLView *parent_view) : - LLInventoryPanel(name, sort_order_setting,rect,inventory,allow_multi_select,parent_view) + LLView *parent_view) : + LLInventoryPanel(name, sort_order_setting, start_folder,rect,inventory,allow_multi_select,parent_view) { mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER; } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 4a2953f7f..330e8d3d2 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -69,6 +69,7 @@ class LLInventoryPanel : public LLPanel protected: LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, + const std::string& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -188,6 +189,7 @@ public: void requestSort(); private: + const std::string mStartFolder; const std::string mSortOrderSetting; //-------------------------------------------------------------------- diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp new file mode 100644 index 000000000..8eb0de6ff --- /dev/null +++ b/indra/newview/llmarketplacefunctions.cpp @@ -0,0 +1,484 @@ +/** + * @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 "lltimer.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +#include "llviewernetwork.h" +#include "hippogridmanager.h" + + +// +// Helpers +// + +static std::string getMarketplaceDomain() +{ + std::string domain = "secondlife.com"; + if (gHippoGridManager->getCurrentGrid()->isSecondLife()) + { + if (!LLViewerLogin::getInstance()->isInProductionGrid()) + { + domain = "secondlife.aditi.lindenlab.com"; + } + } + else + { + // TODO: Find out if OpenSim, and Avination adopted any outbox stuffs, if so code HippoGridManager for this + // Aurora grid has not. + // For now, reset domain on other grids, so we don't harass LL web services. + domain = ""; //gHippoGridManager->getCurrentGrid()->getMarketPlaceDomain(); + } + + 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; +} + +LLSD 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_imports = getMarketplaceURL("MarketplaceURL_Imports"); + std::string marketplace_url_info = getMarketplaceURL("MarketplaceURL_LearnMore"); + + LLSD 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; + marketplace_sub_map["[MARKETPLACE_IMPORTS_URL]"] = marketplace_url_imports; + + return marketplace_sub_map; +} + +namespace LLMarketplaceImport +{ + // Basic interface for this namespace + + bool hasSessionCookie(); + bool inProgress(); + bool resultPending(); + U32 getResultStatus(); + const LLSD& getResults(); + + bool establishMarketplaceSessionCookie(); + bool pollStatus(); + bool triggerImport(); + + // Internal state variables + + static std::string sMarketplaceCookie = ""; + static LLSD sImportId = LLSD::emptyMap(); + static bool sImportInProgress = false; + static bool sImportPostPending = false; + static bool sImportGetPending = false; + static U32 sImportResultStatus = 0; + static LLSD sImportResults = LLSD::emptyMap(); + + static LLTimer slmGetTimer; + static LLTimer slmPostTimer; + + // Responders + + class LLImportPostResponder : public LLHTTPClient::Responder + { + public: + LLImportPostResponder() : LLCurl::Responder() {} + + void completed(U32 status, const std::string& reason, const LLSD& content) + { + slmPostTimer.stop(); + + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM POST status: " << status << llendl; + llinfos << " SLM POST reason: " << reason << llendl; + llinfos << " SLM POST content: " << content.asString() << llendl; + + llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl; + } + + if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || + (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || + (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) + { + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM POST clearing marketplace cookie due to authentication failure or timeout" << llendl; + } + + sMarketplaceCookie.clear(); + } + + sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); + sImportPostPending = false; + sImportResultStatus = status; + sImportId = content; + } + }; + + class LLImportGetResponder : public LLHTTPClient::Responder + { + public: + LLImportGetResponder() : LLCurl::Responder() {} + + void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + const std::string& set_cookie_string = content["set-cookie"].asString(); + + if (!set_cookie_string.empty()) + { + sMarketplaceCookie = set_cookie_string; + } + } + + void completed(U32 status, const std::string& reason, const LLSD& content) + { + slmGetTimer.stop(); + + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM GET status: " << status << llendl; + llinfos << " SLM GET reason: " << reason << llendl; + llinfos << " SLM GET content: " << content.asString() << llendl; + + llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl; + } + + if ((status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || + (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) + { + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM GET clearing marketplace cookie due to authentication failure or timeout" << llendl; + } + + sMarketplaceCookie.clear(); + } + + sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); + sImportGetPending = false; + sImportResultStatus = status; + sImportResults = content; + } + }; + + // Basic API + + bool hasSessionCookie() + { + return !sMarketplaceCookie.empty(); + } + + 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; + } + + bool establishMarketplaceSessionCookie() + { + if (hasSessionCookie()) + { + return false; + } + + sImportInProgress = true; + sImportGetPending = true; + + std::string url = getInventoryImportURL(); + + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM GET: " << url << llendl; + } + + slmGetTimer.start(); + LLHTTPClient::get(url, new LLImportGetResponder(), LLViewerMedia::getHeaders()); + + return true; + } + + bool pollStatus() + { + if (!hasSessionCookie()) + { + return false; + } + + sImportGetPending = true; + + std::string url = getInventoryImportURL(); + + url += sImportId.asString(); + + // Make the headers for the post + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sMarketplaceCookie; + headers["Content-Type"] = "application/llsd+xml"; + headers["User-Agent"] = LLViewerMedia::getCurrentUserAgent(); + + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM GET: " << url << llendl; + } + + slmGetTimer.start(); + LLHTTPClient::get(url, new LLImportGetResponder(), headers); + + return true; + } + + bool triggerImport() + { + if (!hasSessionCookie()) + { + return false; + } + + sImportId = LLSD::emptyMap(); + 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(); + + if (gSavedSettings.getBOOL("InventoryOutboxLogging")) + { + llinfos << " SLM POST: " << url << llendl; + } + + slmPostTimer.start(); + LLHTTPClient::post(url, LLSD(), new LLImportPostResponder(), headers); + + return true; + } +} + + +// +// Interface class +// + +static const F32 MARKET_IMPORTER_UPDATE_FREQUENCY = 300.0f; //1.0f; + +//static +void LLMarketplaceInventoryImporter::update() +{ + if (instanceExists()) + { + static LLTimer update_timer; + if (update_timer.hasExpired()) + { + LLMarketplaceInventoryImporter::instance().updateImport(); + update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY); + } + } +} + +LLMarketplaceInventoryImporter::LLMarketplaceInventoryImporter() + : mAutoTriggerImport(false) + , mImportInProgress(false) + , mInitialized(false) + , mErrorInitSignal(NULL) + , mStatusChangedSignal(NULL) + , mStatusReportSignal(NULL) +{ +} + +boost::signals2::connection LLMarketplaceInventoryImporter::setInitializationErrorCallback(const status_report_signal_t::slot_type& cb) +{ + if (mErrorInitSignal == NULL) + { + mErrorInitSignal = new status_report_signal_t(); + } + + return mErrorInitSignal->connect(cb); +} + +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); +} + +void LLMarketplaceInventoryImporter::initialize() +{ + llassert(!mInitialized); + + if (!LLMarketplaceImport::hasSessionCookie()) + { + LLMarketplaceImport::establishMarketplaceSessionCookie(); + } +} + +void LLMarketplaceInventoryImporter::reinitializeAndTriggerImport() +{ + mInitialized = false; + + initialize(); + + mAutoTriggerImport = true; +} + +bool LLMarketplaceInventoryImporter::triggerImport() +{ + const bool import_triggered = LLMarketplaceImport::triggerImport(); + + if (!import_triggered) + { + reinitializeAndTriggerImport(); + } + + return import_triggered; +} + +void LLMarketplaceInventoryImporter::updateImport() +{ + const bool in_progress = LLMarketplaceImport::inProgress(); + + if (in_progress && !LLMarketplaceImport::resultPending()) + { + const bool polling_status = LLMarketplaceImport::pollStatus(); + + if (!polling_status) + { + reinitializeAndTriggerImport(); + } + } + + if (mImportInProgress != in_progress) + { + mImportInProgress = in_progress; + + // If we are no longer in progress + if (!mImportInProgress) + { + if (mInitialized) + { + // Report results + if (mStatusReportSignal) + { + (*mStatusReportSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + } + } + else + { + // Look for results success + mInitialized = LLMarketplaceImport::hasSessionCookie(); + + if (mInitialized) + { + // Follow up with auto trigger of import + if (mAutoTriggerImport) + { + mAutoTriggerImport = false; + + mImportInProgress = triggerImport(); + } + } + else if (mErrorInitSignal) + { + (*mErrorInitSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + } + } + } + + // Make sure we trigger the status change with the final state (in case of auto trigger after initialize) + if (mStatusChangedSignal) + { + (*mStatusChangedSignal)(mImportInProgress); + } + } +} + diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h new file mode 100644 index 000000000..4c4e07903 --- /dev/null +++ b/indra/newview/llmarketplacefunctions.h @@ -0,0 +1,94 @@ +/** + * @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 +#include +#include + +#include "llsingleton.h" +#include "llstring.h" + + +LLSD getMarketplaceStringSubstitutions(); + + +namespace MarketplaceErrorCodes +{ + enum eCode + { + IMPORT_DONE = 200, + IMPORT_PROCESSING = 202, + IMPORT_REDIRECT = 302, + IMPORT_AUTHENTICATION_ERROR = 401, + IMPORT_DONE_WITH_ERRORS = 409, + IMPORT_JOB_FAILED = 410, + IMPORT_JOB_TIMEOUT = 499, + }; +} + + +class LLMarketplaceInventoryImporter + : public LLSingleton +{ +public: + static void update(); + + LLMarketplaceInventoryImporter(); + + typedef boost::signals2::signal status_changed_signal_t; + typedef boost::signals2::signal status_report_signal_t; + + boost::signals2::connection setInitializationErrorCallback(const status_report_signal_t::slot_type& cb); + boost::signals2::connection setStatusChangedCallback(const status_changed_signal_t::slot_type& cb); + boost::signals2::connection setStatusReportCallback(const status_report_signal_t::slot_type& cb); + + void initialize(); + bool triggerImport(); + bool isImportInProgress() const { return mImportInProgress; } + +protected: + void reinitializeAndTriggerImport(); + void updateImport(); + +private: + bool mAutoTriggerImport; + bool mImportInProgress; + bool mInitialized; + + status_report_signal_t * mErrorInitSignal; + status_changed_signal_t * mStatusChangedSignal; + status_report_signal_t * mStatusReportSignal; +}; + + + +#endif // LL_LLMARKETPLACEFUNCTIONS_H + diff --git a/indra/newview/llpanelmarketplaceoutboxinventory.cpp b/indra/newview/llpanelmarketplaceoutboxinventory.cpp new file mode 100644 index 000000000..7800eb791 --- /dev/null +++ b/indra/newview/llpanelmarketplaceoutboxinventory.cpp @@ -0,0 +1,149 @@ +/** + * @file llpanelmarketplaceoutboxinventory.cpp + * @brief LLOutboxInventoryPanel class definition + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelmarketplaceoutboxinventory.h" + +//#include "llfolderview.h" +//#include "llfoldervieweventlistener.h" +#include "llinventorybridge.h" +//#include "llinventoryfunctions.h" +#include "lltrans.h" +//#include "llviewerfoldertype.h" + + +// +// statics +// + +static LLRegisterWidget r1("outbox_inventory_panel"); +//static LLRegisterWidget r2("outbox_folder_view_folder"); + +// +// LLOutboxInventoryPanel Implementation +// + +LLOutboxInventoryPanel::LLOutboxInventoryPanel(const std::string& name, + const std::string& sort_order_setting, + const std::string& start_folder, + const LLRect& rect, + LLInventoryModel* inventory, + BOOL allow_multi_select, + LLView* parent_view) + : LLInventoryPanel(name, sort_order_setting, start_folder, rect, inventory, allow_multi_select, parent_view) +{ +} + +LLOutboxInventoryPanel::~LLOutboxInventoryPanel() +{ +} + +// virtual +void LLOutboxInventoryPanel::buildFolderView(/*const LLInventoryPanel::Params& params*/) +{ + // Determine the root folder in case specified, and + // build the views starting with that folder. + + LLUUID root_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); + + if (root_id == LLUUID::null) + { + llwarns << "Outbox inventory panel has no root folder!" << llendl; + root_id = LLUUID::generateNewID(); + } + + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, + LLAssetType::AT_CATEGORY, + LLInventoryType::IT_CATEGORY, + this, + NULL, + root_id); + + mFolderRoot = createFolderView(new_listener, true/*params.use_label_suffix()*/); +} + +LLFolderViewFolder * LLOutboxInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) +{ + return new LLOutboxFolderViewFolder( + bridge->getDisplayName(), + bridge->getIcon(), + bridge->getOpenIcon(), + LLUI::getUIImage("inv_link_overlay.tga"), + mFolderRoot, + bridge); +} + +LLFolderViewItem * LLOutboxInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge) +{ + return new LLOutboxFolderViewItem( + bridge->getDisplayName(), + bridge->getIcon(), + bridge->getOpenIcon(), + LLUI::getUIImage("inv_link_overlay.tga"), + bridge->getCreationDate(), + mFolderRoot, + bridge); +} + +// +// LLOutboxFolderViewFolder Implementation +// + +LLOutboxFolderViewFolder::LLOutboxFolderViewFolder(const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_open, + LLUIImagePtr icon_link, + LLFolderView* root, + LLFolderViewEventListener* listener) + : LLFolderViewFolder(name, icon, icon_open, icon_link, root, listener) +{ +} + +// +// LLOutboxFolderViewItem Implementation +// + +LLOutboxFolderViewItem::LLOutboxFolderViewItem(const std::string& name, LLUIImagePtr icon, + LLUIImagePtr icon_open, + LLUIImagePtr icon_overlay, + S32 creation_date, + LLFolderView* root, + LLFolderViewEventListener* listener) + : LLFolderViewItem(name, icon, icon_open, icon_overlay, creation_date, root, listener) +{ +} + +BOOL LLOutboxFolderViewItem::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + return TRUE; +} + +void LLOutboxFolderViewItem::openItem() +{ + // Intentionally do nothing to block attaching items from the outbox +} + +// eof diff --git a/indra/newview/llpanelmarketplaceoutboxinventory.h b/indra/newview/llpanelmarketplaceoutboxinventory.h new file mode 100644 index 000000000..0eee7ed9e --- /dev/null +++ b/indra/newview/llpanelmarketplaceoutboxinventory.h @@ -0,0 +1,74 @@ +/** + * @file llpanelmarketplaceoutboxinventory.h + * @brief LLOutboxInventoryPanel class declaration + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_OUTBOXINVENTORYPANEL_H +#define LL_OUTBOXINVENTORYPANEL_H + + +#include "llinventorypanel.h" +#include "llfolderviewitem.h" + + +class LLOutboxInventoryPanel : public LLInventoryPanel +{ +public: + LLOutboxInventoryPanel(const std::string& name, + const std::string& sort_order_setting, + const std::string& start_folder, + const LLRect& rect, + LLInventoryModel* inventory, + BOOL allow_multi_select, + LLView *parent_view = NULL); + ~LLOutboxInventoryPanel(); + + // virtual + void buildFolderView(/*const LLInventoryPanel::Params& params*/); + + // virtual + LLFolderViewFolder * createFolderViewFolder(LLInvFVBridge * bridge); + LLFolderViewItem * createFolderViewItem(LLInvFVBridge * bridge); +}; + + +class LLOutboxFolderViewFolder : public LLFolderViewFolder +{ +public: + LLOutboxFolderViewFolder(const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener); +}; + + +class LLOutboxFolderViewItem : public LLFolderViewItem +{ +public: + LLOutboxFolderViewItem(const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_open, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener); + + // virtual + BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + void openItem(); +}; + + +#endif //LL_OUTBOXINVENTORYPANEL_H diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 3447341f6..d39061bb4 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -358,7 +358,7 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() addEntry(DAD_NOTECARD, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearCategory, &LLToolDragAndDrop::dad3dGiveInventoryCategory, &LLToolDragAndDrop::dad3dUpdateInventoryCategory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_ROOT_CATEGORY, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); - addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); + addEntry(DAD_BODYPART, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dWearItem, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_ANIMATION, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_GESTURE, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dActivateGesture, &LLToolDragAndDrop::dad3dGiveInventory, &LLToolDragAndDrop::dad3dUpdateInventory, &LLToolDragAndDrop::dad3dNULL)); addEntry(DAD_LINK, new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL, &LLToolDragAndDrop::dad3dNULL)); @@ -1710,6 +1710,12 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( //} // + const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) + { + return ACCEPT_NO; + } + // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) { @@ -1739,7 +1745,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( else { // rez_attachment(item, 0); -// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-08 (Catznip-2.2.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a // Make this behave consistent with dad3dWearItem rez_attachment(item, 0, !(mask & MASK_CONTROL)); // [/SL:KB] @@ -2068,7 +2074,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { // it's in the agent inventory - LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -2118,7 +2124,7 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY) { // it's in the agent inventory - LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) ) { return ACCEPT_NO; @@ -2191,7 +2197,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( if(drop) { - BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE ); + BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE ); LLAppearanceMgr::instance().wearInventoryCategory(category, false, append); } return ACCEPT_YES_MULTI; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0c0b12075..35a89cc0d 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -139,6 +139,7 @@ #include "llfloatermute.h" #include "llfloateropenobject.h" +#include "llfloateroutbox.h" #include "llfloaterpermissionsmgr.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -6537,6 +6538,10 @@ class LLShowFloater : public view_listener_t { LLFloaterPerms::toggleInstance(LLSD()); } + else if (floater_name == "outbox") + { + LLFloaterOutbox::toggleInstance(LLSD()); + } return true; } }; @@ -6611,6 +6616,10 @@ class LLFloaterVisible : public view_listener_t if (!instn) new_value = false; else new_value = instn->getVisible(); } + else if (floater_name == "outbox") + { + new_value = LLFloaterOutbox::instanceVisible(LLSD()); + } gMenuHolder->findControl(control_name)->setValue(new_value); return true; } diff --git a/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml new file mode 100644 index 000000000..e6ff5213b --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml @@ -0,0 +1,146 @@ + + + No folders + 1 folder + [NUM] folders + Sending folders... + Initializing... + + + + Loading... + + + + + + + + Drag items here to create folders + + + +