diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f5f0d74f0f2661d129b0073ca43323aad82d2703..4aeacae6edc613d6d37f87758a815cdf85437252 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -454,7 +454,10 @@ void copy_inventory_category(LLInventoryModel* model,
     inventory_func_type func = [model, cat, root_copy_id, move_no_copy_items, callback](const LLUUID &new_id)
     {
         copy_inventory_category_content(new_id, model, cat, root_copy_id, move_no_copy_items);
-        callback(new_id);
+        if (callback)
+        {
+            callback(new_id);
+        }
     };
 	gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName(), func, cat->getThumbnailUUID());
 }
diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp
index 8170c0c63b8f5de7ac1f41aefb148ba84138797d..eab15b79adfeace75a21baed27aa19a30e88d137 100644
--- a/indra/newview/llinventorygallery.cpp
+++ b/indra/newview/llinventorygallery.cpp
@@ -107,7 +107,6 @@ LLInventoryGallery::LLInventoryGallery(const LLInventoryGallery::Params& p)
       mIsInitialized(false),
       mRootDirty(false),
       mNeedsArrange(false),
-      mNeedsSelection(false),
       mSearchType(LLInventoryFilter::SEARCHTYPE_NAME),
       mSortOrder(LLInventoryFilter::SO_DATE)
 {
@@ -219,10 +218,10 @@ void LLInventoryGallery::setRootFolder(const LLUUID cat_id)
     gIdleCallbacks.deleteFunction(onIdle, (void*)this);
 
     mFolderID = cat_id;
-    mItemToSelect.setNull();
+    mItemsToSelect.clear();
+    mSelectedItemIDs.clear();
     mItemBuildQuery.clear();
     mNeedsArrange = false;
-    mNeedsSelection = false;
     dirtyRootFolder();
 }
 
@@ -831,15 +830,17 @@ void LLInventoryGallery::onIdle(void* userdata)
         self->updateMessageVisibility();
     }
 
-    if (self->mNeedsSelection)
+    if (!self->mItemsToSelect.empty() && !self->mNeedsArrange)
     {
-        LLUUID item_to_select = self->mItemToSelect;
-        self->mItemToSelect = LLUUID::null;
-        self->mNeedsSelection = false;
-        self->changeItemSelection(item_to_select, true);
+        selection_deque selection_list(self->mItemsToSelect);
+        self->mItemsToSelect.clear();
+        for (LLUUID & item_to_select : selection_list)
+        {
+            self->addItemSelection(item_to_select, true);
+        }
     }
 
-    if (!self->mNeedsSelection && self->mItemBuildQuery.empty())
+    if (self->mItemsToSelect.empty() && self->mItemBuildQuery.empty())
     {
         gIdleCallbacks.deleteFunction(onIdle, (void*)self);
     }
@@ -911,7 +912,6 @@ bool LLInventoryGallery::updateAddedItem(LLUUID item_id)
 
     LLInventoryGalleryItem* item = buildGalleryItem(name, item_id, obj->getType(), thumbnail_id, inventory_type, misc_flags, obj->getCreationDate(), obj->getIsLinkType(), is_worn);
     mItemMap.insert(LLInventoryGallery::gallery_item_map_t::value_type(item_id, item));
-    item->setFocusReceivedCallback(boost::bind(&LLInventoryGallery::changeItemSelection, this, item_id, false));
     if (mGalleryCreated)
     {
         res = applyFilter(item, mFilterSubString);
@@ -1074,8 +1074,7 @@ BOOL LLInventoryGallery::handleKeyHere(KEY key, MASK mask)
             mFilterSubString.clear();
             if (mInventoryGalleryMenu && mSelectedItemIDs.size() == 1)
             {
-                selection_deque::iterator iter = mSelectedItemIDs.begin();
-                mInventoryGalleryMenu->doToSelected("rename", *iter);
+                mInventoryGalleryMenu->rename(mSelectedItemIDs.front());
             }
             handled = TRUE;
             break;
@@ -1117,22 +1116,22 @@ BOOL LLInventoryGallery::handleKeyHere(KEY key, MASK mask)
             break;
 
         case KEY_LEFT:
-            moveLeft();
+            moveLeft(mask);
             handled = TRUE;
             break;
 
         case KEY_RIGHT:
-            moveRight();
+            moveRight(mask);
             handled = TRUE;
             break;
 
         case KEY_UP:
-            moveUp();
+            moveUp(mask);
             handled = TRUE;
             break;
 
         case KEY_DOWN:
-            moveDown();
+            moveDown(mask);
             handled = TRUE;
             break;
 
@@ -1148,59 +1147,107 @@ BOOL LLInventoryGallery::handleKeyHere(KEY key, MASK mask)
     return handled;
 }
 
-void LLInventoryGallery::moveUp()
+void LLInventoryGallery::moveUp(MASK mask)
 {
     mFilterSubString.clear();
 
     if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
     {
-        LLInventoryGalleryItem* item = getFirstSelectedItem();
+        LLInventoryGalleryItem* item = mItemMap[mLastSelectedUUID];
         if (item)
         {
-            S32 n = mItemIndexMap[item];
-            n -= mItemsInRow;
-            if (n >= 0)
+            if (mask == MASK_NONE || mask == MASK_CONTROL)
             {
-                item = mIndexToItemMap[n];
-                LLUUID item_id = item->getUUID();
-                changeItemSelection(item_id, true);
-                item->setFocus(TRUE);
-                claimEditHandler();
+                S32 n = mItemIndexMap[item];
+                n -= mItemsInRow;
+                if (n >= 0)
+                {
+                    item = mIndexToItemMap[n];
+                    LLUUID item_id = item->getUUID();
+                    if (mask == MASK_CONTROL)
+                    {
+                        addItemSelection(item_id, true);
+                    }
+                    else
+                    {
+                        changeItemSelection(item_id, true);
+                    }
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                S32 n = mItemIndexMap[item];
+                S32 target  = llmax(0, n - mItemsInRow);
+                toggleSelectionRange(target, n - 1);
+                if (target != n)
+                {
+                    item = mIndexToItemMap[target];
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
             }
         }
     }
 }
 
-void LLInventoryGallery::moveDown()
+void LLInventoryGallery::moveDown(MASK mask)
 {
     mFilterSubString.clear();
 
     if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
     {
-        LLInventoryGalleryItem* item = getFirstSelectedItem();
+        LLInventoryGalleryItem* item = mItemMap[mLastSelectedUUID];
         if (item)
         {
-            S32 n = mItemIndexMap[item];
-            n += mItemsInRow;
-            if (n < mItemsAddedCount)
+            if (mask == MASK_NONE || mask == MASK_CONTROL)
             {
-                item = mIndexToItemMap[n];
-                LLUUID item_id = item->getUUID();
-                changeItemSelection(item_id, true);
-                item->setFocus(TRUE);
-                claimEditHandler();
+                S32 n = mItemIndexMap[item];
+                n += mItemsInRow;
+                if (n < mItemsAddedCount)
+                {
+                    item = mIndexToItemMap[n];
+                    LLUUID item_id = item->getUUID();
+                    if (mask == MASK_CONTROL)
+                    {
+                        addItemSelection(item_id, true);
+                    }
+                    else
+                    {
+                        changeItemSelection(item_id, true);
+                    }
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                S32 n = mItemIndexMap[item];
+                S32 target = llmin(mItemsAddedCount - 1, n + mItemsInRow);
+                toggleSelectionRange(n + 1, target);
+                if (target != n)
+                {
+                    item = mIndexToItemMap[target];
+                    item->setFocus(TRUE);
+                    claimEditHandler();
+                }
             }
         }
     }
 }
 
-void LLInventoryGallery::moveLeft()
+void LLInventoryGallery::moveLeft(MASK mask)
 {
     mFilterSubString.clear();
 
     if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
     {
-        LLInventoryGalleryItem* item = getFirstSelectedItem();
+        LLInventoryGalleryItem* item = mItemMap[mLastSelectedUUID];
+        if (mask == MASK_SHIFT)
+        {
+            item = mItemMap[mLastSelectedUUID];
+        }
         if (item)
         {
             // Might be better to get item from panel
@@ -1212,20 +1259,31 @@ void LLInventoryGallery::moveLeft()
             }
             item = mIndexToItemMap[n];
             LLUUID item_id = item->getUUID();
-            changeItemSelection(item_id, true);
+            if (mask == MASK_CONTROL)
+            {
+                addItemSelection(item_id, true);
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                toggleItemSelection(item_id, true);
+            }
+            else
+            {
+                changeItemSelection(item_id, true);
+            }
             item->setFocus(TRUE);
             claimEditHandler();
         }
     }
 }
 
-void LLInventoryGallery::moveRight()
+void LLInventoryGallery::moveRight(MASK mask)
 {
     mFilterSubString.clear();
 
     if (mInventoryGalleryMenu && mSelectedItemIDs.size() > 0 && mItemsAddedCount > 1)
     {
-        LLInventoryGalleryItem* item = getFirstSelectedItem();
+        LLInventoryGalleryItem* item = mItemMap[mLastSelectedUUID];
         if (item)
         {
             S32 n = mItemIndexMap[item];
@@ -1236,13 +1294,58 @@ void LLInventoryGallery::moveRight()
             }
             item = mIndexToItemMap[n];
             LLUUID item_id = item->getUUID();
-            changeItemSelection(item_id, true);
+            if (mask == MASK_CONTROL)
+            {
+                addItemSelection(item_id, true);
+            }
+            else if (mask == MASK_SHIFT)
+            {
+                toggleItemSelection(item_id, true);
+            }
+            else
+            {
+                changeItemSelection(item_id, true);
+            }
             item->setFocus(TRUE);
             claimEditHandler();
         }
     }
 }
 
+void LLInventoryGallery::toggleSelectionRange(S32 start_idx, S32 end_idx)
+{
+    LLInventoryGalleryItem* item = NULL;
+    for (S32 i = start_idx; i <= end_idx; i++)
+    {
+        item = mIndexToItemMap[i];
+        LLUUID item_id = item->getUUID();
+        toggleItemSelection(item_id, true);
+    }
+}
+
+void LLInventoryGallery::toggleSelectionRangeFromLast(const LLUUID target)
+{
+    if (mLastSelectedUUID == target)
+    {
+        return;
+    }
+    LLInventoryGalleryItem* last_item = mItemMap[mLastSelectedUUID];
+    LLInventoryGalleryItem* next_item = mItemMap[target];
+    if (last_item && next_item)
+    {
+        S32 last_idx = mItemIndexMap[last_item];
+        S32 next_idx = mItemIndexMap[next_item];
+        if (last_idx < next_idx)
+        {
+            toggleSelectionRange(last_idx + 1, next_idx);
+        }
+        else
+        {
+            toggleSelectionRange(next_idx, last_idx - 1);
+        }
+    }
+}
+
 void LLInventoryGallery::onFocusLost()
 {
     // inventory no longer handles cut/copy/paste/delete
@@ -1270,17 +1373,21 @@ void LLInventoryGallery::onFocusReceived()
     // Tab support, when tabbing into this view, select first item
     if (mSelectedItemIDs.size() > 0)
     {
+        LLInventoryGalleryItem* focus_item = NULL;
         for (const LLUUID& id : mSelectedItemIDs)
         {
             if (mItemMap[id])
             {
-                LLInventoryGalleryItem* focus_item = mItemMap[id];
+                focus_item = mItemMap[id];
                 focus_item->setSelected(true);
-                focus_item->setFocus(TRUE);
             }
         }
+        if (focus_item)
+        {
+            focus_item->setFocus(TRUE);
+        }
     }
-    else if (mIndexToItemMap.size() > 0 && !mNeedsSelection)
+    else if (mIndexToItemMap.size() > 0 && mItemsToSelect.empty())
     {
         // choose any items from visible rect
         S32 vert_offset = mScrollPanel->getDocPosVertical();
@@ -1304,18 +1411,26 @@ void LLInventoryGallery::showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLU
             mSelectedItemIDs.clear();
             changeItemSelection(item_id, false);
         }
-        uuid_vec_t selected_uuids;
-        selected_uuids.push_back(item_id);
+        uuid_vec_t selected_uuids(mSelectedItemIDs.begin(), mSelectedItemIDs.end());
         mInventoryGalleryMenu->show(ctrl, selected_uuids, x, y);
     }
 }
 
 void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_to_selection)
 {
+    for (const LLUUID& id : mSelectedItemIDs)
+    {
+        if (mItemMap[id])
+        {
+            mItemMap[id]->setSelected(FALSE);
+        }
+    }
+    mSelectedItemIDs.clear();
+
     if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
     {
-        mItemToSelect = item_id;
-        mNeedsSelection = true;
+        mItemsToSelect.clear();
+        mItemsToSelect.push_back(item_id);
         return;
     }
     if (mSelectedItemIDs.size() == 1
@@ -1325,14 +1440,32 @@ void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_
         return;
     }
 
-    for (const LLUUID& id : mSelectedItemIDs)
+    if (mItemMap[item_id])
     {
-        if (mItemMap[id])
-        {
-            mItemMap[id]->setSelected(FALSE);
-        }
+        mItemMap[item_id]->setSelected(TRUE);
+    }
+    mSelectedItemIDs.push_back(item_id);
+    signalSelectionItemID(item_id);
+    mLastSelectedUUID = item_id;
+
+    if (scroll_to_selection)
+    {
+        scrollToShowItem(item_id);
+    }
+}
+
+void LLInventoryGallery::addItemSelection(const LLUUID& item_id, bool scroll_to_selection)
+{
+    if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
+    {
+        mItemsToSelect.push_back(item_id);
+        return;
+    }
+    if (std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id) != mSelectedItemIDs.end())
+    {
+        // Already selected
+        return;
     }
-    mSelectedItemIDs.clear();
 
     if (mItemMap[item_id])
     {
@@ -1340,6 +1473,7 @@ void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_
     }
     mSelectedItemIDs.push_back(item_id);
     signalSelectionItemID(item_id);
+    mLastSelectedUUID = item_id;
 
     if (scroll_to_selection)
     {
@@ -1347,6 +1481,43 @@ void LLInventoryGallery::changeItemSelection(const LLUUID& item_id, bool scroll_
     }
 }
 
+bool LLInventoryGallery::toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection)
+{
+    bool result = false;
+    if ((mItemMap.count(item_id) == 0) || mNeedsArrange)
+    {
+        mItemsToSelect.push_back(item_id);
+        return result;
+    }
+    selection_deque::iterator found = std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), item_id);
+    if (found != mSelectedItemIDs.end())
+    {
+        if (mItemMap[item_id])
+        {
+            mItemMap[item_id]->setSelected(FALSE);
+        }
+        mSelectedItemIDs.erase(found);
+        result = false;
+    }
+    else
+    {
+        if (mItemMap[item_id])
+        {
+            mItemMap[item_id]->setSelected(TRUE);
+        }
+        mSelectedItemIDs.push_back(item_id);
+        signalSelectionItemID(item_id);
+        mLastSelectedUUID = item_id;
+        result = true;
+    }
+
+    if (scroll_to_selection)
+    {
+        scrollToShowItem(item_id);
+    }
+    return result;
+}
+
 void LLInventoryGallery::scrollToShowItem(const LLUUID& item_id)
 {
     LLInventoryGalleryItem* item = mItemMap[item_id];
@@ -1476,32 +1647,63 @@ void LLInventoryGallery::paste()
         return;
     }
 
-    LLUUID first_selected_id;
-    if (mSelectedItemIDs.size() > 0)
-    {
-        first_selected_id = *mSelectedItemIDs.begin();
-    }
-
-    LLInventoryObject* obj = gInventory.getObject(first_selected_id);
-    bool is_folder = obj && (obj->getType() == LLAssetType::AT_CATEGORY);
-    LLUUID dest = is_folder ? first_selected_id : mFolderID;
     bool is_cut_mode = LLClipboard::instance().isCutMode();
-
     std::vector<LLUUID> objects;
     LLClipboard::instance().pasteFromClipboard(objects);
 
-    LLHandle<LLPanel> handle = getHandle();
-    std::function <void(const LLUUID)> on_copy_callback = [handle](const LLUUID& inv_item)
+    bool paste_into_root = mSelectedItemIDs.empty();
+    for (LLUUID& dest : mSelectedItemIDs)
     {
-        LLInventoryGallery* panel = (LLInventoryGallery*)handle.get();
-        if (panel)
+        LLInventoryObject* obj = gInventory.getObject(dest);
+        if (!obj || (obj->getType() != LLAssetType::AT_CATEGORY))
         {
-            // Scroll to pasted item and highlight it
-            // Should it only highlight the last one?
-            panel->changeItemSelection(inv_item, true);
+            paste_into_root = true;
+            continue;
         }
-    };
-    LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(on_copy_callback);
+
+        paste(dest, objects, is_cut_mode, marketplacelistings_id);
+        is_cut_mode = false;
+    }
+
+    if (paste_into_root)
+    {
+        for (const LLUUID& id : mSelectedItemIDs)
+        {
+            if (mItemMap[id])
+            {
+                mItemMap[id]->setSelected(FALSE);
+            }
+        }
+        mSelectedItemIDs.clear();
+
+        paste(mFolderID, objects, is_cut_mode, marketplacelistings_id);
+    }
+
+    LLClipboard::instance().setCutMode(false);
+}
+
+void LLInventoryGallery::paste(const LLUUID& dest,
+                               std::vector<LLUUID>& objects,
+                               bool is_cut_mode,
+                               const LLUUID& marketplacelistings_id)
+{
+    LLHandle<LLPanel> handle = getHandle();
+    std::function <void(const LLUUID)> on_copy_callback = NULL;
+    LLPointer<LLInventoryCallback> cb = NULL;
+    if (dest == mFolderID)
+    {
+        on_copy_callback = [handle](const LLUUID& inv_item)
+            {
+                LLInventoryGallery* panel = (LLInventoryGallery*)handle.get();
+                if (panel)
+                {
+                    // Scroll to pasted item and highlight it
+                    // Should it only highlight the last one?
+                    panel->addItemSelection(inv_item, true);
+                }
+            };
+        cb = new LLBoostFuncInventoryCallback(on_copy_callback);
+    }
 
     for (std::vector<LLUUID>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
     {
@@ -1517,9 +1719,11 @@ void LLInventoryGallery::paste()
             if (is_cut_mode)
             {
                 gInventory.changeCategoryParent(cat, dest, false);
-                // Don't select immediately, wait for item to arrive
-                mItemToSelect = item_id;
-                mNeedsSelection = true;
+                if (dest == mFolderID)
+                {
+                    // Don't select immediately, wait for item to arrive
+                    mItemsToSelect.push_back(item_id);
+                }
             }
             else
             {
@@ -1534,9 +1738,11 @@ void LLInventoryGallery::paste()
                 if (is_cut_mode)
                 {
                     gInventory.changeItemParent(item, dest, false);
-                    // Don't select immediately, wait for item to arrive
-                    mItemToSelect = item_id;
-                    mNeedsSelection = true;
+                    if (dest == mFolderID)
+                    {
+                        // Don't select immediately, wait for item to arrive
+                        mItemsToSelect.push_back(item_id);
+                    }
                 }
                 else
                 {
@@ -1679,17 +1885,45 @@ void LLInventoryGallery::pasteAsLink()
     const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS);
     const LLUUID& my_outifts_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
 
-    LLUUID dest;
-    if (mSelectedItemIDs.size() > 0)
+    std::vector<LLUUID> objects;
+    LLClipboard::instance().pasteFromClipboard(objects);
+
+    bool paste_into_root = mSelectedItemIDs.empty();
+    for (LLUUID& dest : mSelectedItemIDs)
     {
-        dest = *mSelectedItemIDs.begin();
+        LLInventoryObject* obj = gInventory.getObject(dest);
+        if (!obj || obj->getType() != LLAssetType::AT_CATEGORY)
+        {
+            paste_into_root = true;
+            continue;
+        }
+
+        pasteAsLink(dest, objects, current_outfit_id, marketplacelistings_id, my_outifts_id);
     }
-    LLInventoryObject* obj = gInventory.getObject(dest);
-    if (!obj || obj->getType() != LLAssetType::AT_CATEGORY)
+
+    if (paste_into_root)
     {
-        dest = mFolderID;
+        for (const LLUUID& id : mSelectedItemIDs)
+        {
+            if (mItemMap[id])
+            {
+                mItemMap[id]->setSelected(FALSE);
+            }
+        }
+        mSelectedItemIDs.clear();
+
+        pasteAsLink(mFolderID, objects, current_outfit_id, marketplacelistings_id, my_outifts_id);
     }
 
+    LLClipboard::instance().setCutMode(false);
+}
+
+void LLInventoryGallery::pasteAsLink(const LLUUID& dest,
+                                     std::vector<LLUUID>& objects,
+                                     const LLUUID& current_outfit_id,
+                                     const LLUUID& marketplacelistings_id,
+                                     const LLUUID& my_outifts_id)
+{
     const BOOL move_is_into_current_outfit = (dest == current_outfit_id);
     const BOOL move_is_into_my_outfits = (dest == my_outifts_id) || gInventory.isObjectDescendentOf(dest, my_outifts_id);
     const BOOL move_is_into_marketplacelistings = gInventory.isObjectDescendentOf(dest, marketplacelistings_id);
@@ -1698,21 +1932,23 @@ void LLInventoryGallery::pasteAsLink()
     {
         return;
     }
-    std::vector<LLUUID> objects;
-    LLClipboard::instance().pasteFromClipboard(objects);
 
-    LLHandle<LLPanel> handle = getHandle();
-    std::function <void(const LLUUID)> on_link_callback = [handle](const LLUUID& inv_item)
+    LLPointer<LLInventoryCallback> cb = NULL;
+    if (dest == mFolderID)
     {
-        LLInventoryGallery *panel = (LLInventoryGallery*)handle.get();
-        if (panel)
-        {
-            // Scroll to pasted item and highlight it
-            // Should it only highlight the last one?
-            panel->changeItemSelection(inv_item, true);
-        }
-    };
-    LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(on_link_callback);
+        LLHandle<LLPanel> handle = getHandle();
+        std::function <void(const LLUUID)> on_link_callback = [handle](const LLUUID& inv_item)
+            {
+                LLInventoryGallery* panel = (LLInventoryGallery*)handle.get();
+                if (panel)
+                {
+                    // Scroll to pasted item and highlight it
+                    // Should it only highlight the last one?
+                    panel->addItemSelection(inv_item, true);
+                }
+            };
+        cb = new LLBoostFuncInventoryCallback(on_link_callback);
+    }
 
     for (std::vector<LLUUID>::const_iterator iter = objects.begin();
          iter != objects.end();
@@ -1724,8 +1960,6 @@ void LLInventoryGallery::pasteAsLink()
             link_inventory_object(dest, link_obj, cb);
         }
     }
-
-    LLClipboard::instance().setCutMode(false);
 }
 
 void LLInventoryGallery::claimEditHandler()
@@ -1852,7 +2086,7 @@ void LLInventoryGallery::refreshList(const LLUUID& category_id)
         mNeedsArrange = true;
     }
 
-    if(mNeedsArrange || mItemToSelect.notNull())
+    if(mNeedsArrange || !mItemsToSelect.empty())
     {
         // Don't scroll to target/arrange immediately
         // since more updates might be pending
@@ -1969,7 +2203,7 @@ void LLInventoryGallery::deselectItem(const LLUUID& category_id)
         mItemMap[category_id]->setSelected(FALSE);
         setFocus(true);
         // Todo: support multiselect
-        signalSelectionItemID(LLUUID::null);
+        // signalSelectionItemID(LLUUID::null);
     }
 
     selection_deque::iterator found = std::find(mSelectedItemIDs.begin(), mSelectedItemIDs.end(), category_id);
@@ -1991,6 +2225,7 @@ void LLInventoryGallery::clearSelection()
     if (!mSelectedItemIDs.empty())
     {
         mSelectedItemIDs.clear();
+        // BUG: wrong, item can be null
         signalSelectionItemID(LLUUID::null);
     }
 }
@@ -2350,8 +2585,6 @@ void LLInventoryGalleryItem::draw()
         border.mTop = border.mTop + 1;
         gl_rect_2d(border, border_color.get(), FALSE);
     }
-
-
 }
 
 void LLInventoryGalleryItem::setItemName(std::string name)
@@ -2379,7 +2612,18 @@ BOOL LLInventoryGalleryItem::handleMouseDown(S32 x, S32 y, MASK mask)
 {
     // call changeItemSelection directly, before setFocus
     // to avoid autoscroll from LLInventoryGallery::onFocusReceived()
-    mGallery->changeItemSelection(mUUID, false);
+    if (mask == MASK_CONTROL)
+    {
+        mGallery->addItemSelection(mUUID, false);
+    }
+    else if (mask == MASK_SHIFT)
+    {
+        mGallery->toggleSelectionRangeFromLast(mUUID);
+    }
+    else
+    {
+        mGallery->changeItemSelection(mUUID, false);
+    }
     setFocus(TRUE);
     mGallery->claimEditHandler();
 
@@ -2496,22 +2740,22 @@ BOOL LLInventoryGalleryItem::handleKeyHere(KEY key, MASK mask)
     switch (key)
     {
         case KEY_LEFT:
-            mGallery->moveLeft();
+            mGallery->moveLeft(mask);
             handled = true;
             break;
 
         case KEY_RIGHT:
-            mGallery->moveRight();
+            mGallery->moveRight(mask);
             handled = true;
             break;
 
         case KEY_UP:
-            mGallery->moveUp();
+            mGallery->moveUp(mask);
             handled = true;
             break;
 
         case KEY_DOWN:
-            mGallery->moveDown();
+            mGallery->moveDown(mask);
             handled = true;
             break;
 
@@ -2525,7 +2769,6 @@ void LLInventoryGalleryItem::onFocusLost()
 {
     // inventory no longer handles cut/copy/paste/delete
     mGallery->resetEditHandler();
-    setSelected(false);
 
     LLPanel::onFocusLost();
 }
@@ -2534,7 +2777,6 @@ void LLInventoryGalleryItem::onFocusReceived()
 {
     // inventory now handles cut/copy/paste/delete
     mGallery->claimEditHandler();
-    setSelected(true);
 
     LLPanel::onFocusReceived();
 }
@@ -2649,6 +2891,11 @@ BOOL LLInventoryGallery::baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
 {
     LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
 
+    if (drop && LLToolDragAndDrop::getInstance()->getCargoIndex() == 0)
+    {
+        clearSelection();
+    }
+
     BOOL accepted = FALSE;
     switch(cargo_type)
     {
@@ -2669,8 +2916,7 @@ BOOL LLInventoryGallery::baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
             if (accepted && drop)
             {
                 // Don't select immediately, wait for item to arrive
-                mItemToSelect = inv_item->getUUID();
-                mNeedsSelection = true;
+                mItemsToSelect.push_back(inv_item->getUUID());
             }
             break;
         case DAD_LINK:
@@ -2691,8 +2937,7 @@ BOOL LLInventoryGallery::baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
             }
             if (accepted && drop && inv_item)
             {
-                mItemToSelect = inv_item->getUUID();
-                mNeedsSelection = true;
+                mItemsToSelect.push_back(inv_item->getUUID());
             }
             break;
         case DAD_CATEGORY:
@@ -2706,8 +2951,7 @@ BOOL LLInventoryGallery::baseHandleDragAndDrop(LLUUID dest_id, BOOL drop,
                 accepted = dragCategoryIntoFolder(dest_id, cat_ptr, drop, tooltip_msg, FALSE);
                 if (accepted && drop)
                 {
-                    mItemToSelect = cat_ptr->getUUID();
-                    mNeedsSelection = true;
+                    mItemsToSelect.push_back(cat_ptr->getUUID());
                 }
             }
             break;
diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h
index f2e5e38940a4479073b121f6187c2535e324c53e..44e0dcf960bf0fabf2880fa0a5caac4dc29d5b51 100644
--- a/indra/newview/llinventorygallery.h
+++ b/indra/newview/llinventorygallery.h
@@ -82,10 +82,12 @@ class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
                            void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) override;
     BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;
     BOOL handleKeyHere(KEY key, MASK mask) override;
-    void moveUp();
-    void moveDown();
-    void moveLeft();
-    void moveRight();
+    void moveUp(MASK mask);
+    void moveDown(MASK mask);
+    void moveLeft(MASK mask);
+    void moveRight(MASK mask);
+    void toggleSelectionRange(S32 start_idx, S32 end_idx);
+    void toggleSelectionRangeFromLast(const LLUUID target);
 
     void onFocusLost() override;
     void onFocusReceived() override;
@@ -130,6 +132,8 @@ class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
     void deselectItem(const LLUUID& category_id);
     void clearSelection();
     void changeItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
+    void addItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
+    bool toggleItemSelection(const LLUUID& item_id, bool scroll_to_selection = false);
     void scrollToShowItem(const LLUUID& item_id);
     void signalSelectionItemID(const LLUUID& category_id);
     boost::signals2::connection setSelectionChangeCallback(selection_change_callback_t cb);
@@ -174,6 +178,15 @@ class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
     void showContextMenu(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& item_id);
 
 protected:
+    void paste(const LLUUID& dest,
+               std::vector<LLUUID>& objects,
+               bool is_cut_mode,
+               const LLUUID& marketplacelistings_id);
+    void pasteAsLink(const LLUUID& dest,
+                     std::vector<LLUUID>& objects,
+                     const LLUUID& current_outfit_id,
+                     const LLUUID& marketplacelistings_id,
+                     const LLUUID& my_outifts_id);
 
     bool applyFilter(LLInventoryGalleryItem* item, const std::string& filter_substring);
     bool checkAgainstFilters(LLInventoryGalleryItem* item, const std::string& filter_substring);
@@ -185,8 +198,8 @@ class LLInventoryGallery : public LLPanel, public LLEditMenuHandler
     LLGalleryGestureObserver*          mGestureObserver;
     LLInventoryObserver*               mInventoryObserver;
     selection_deque                    mSelectedItemIDs;
-    LLUUID                             mItemToSelect;
-    bool                               mNeedsSelection;
+    selection_deque                    mItemsToSelect;
+    LLUUID                             mLastSelectedUUID;
     bool                               mIsInitialized;
     bool                               mRootDirty;
 
diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp
index bca10b9c0ee30c1b2b1696d4e20ba3491923d20a..5f4b816b99b6715cc2be45fbe33ae68b40eef78d 100644
--- a/indra/newview/llinventorygallerymenu.cpp
+++ b/indra/newview/llinventorygallerymenu.cpp
@@ -51,16 +51,17 @@
 LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
 {
     LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-    //LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
-    LLUUID selected_id = mUUIDs.front();
+    LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar;
 
-    registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2, selected_id));
-    registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2, selected_id));
+    registrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryGalleryContextMenu::doToSelected, this, _2));
+    registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2));
     registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
     registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
 
-    std::set<LLUUID> uuids{selected_id};
+    std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end());
     registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
+
+    enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
     
     LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml");
 
@@ -69,49 +70,52 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
     return menu;
 }
 
-void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLUUID& selected_id)
+void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
 {
     std::string action = userdata.asString();
-    LLInventoryObject* obj = gInventory.getObject(selected_id);
+    LLInventoryObject* obj = gInventory.getObject(mUUIDs.front());
     if(!obj) return;
 
     if ("open_selected_folder" == action)
     {
-        mGallery->setRootFolder(selected_id);
+        mGallery->setRootFolder(mUUIDs.front());
     }
     else if ("open_in_new_window" == action)
     {
-        new_folder_window(selected_id);
+        new_folder_window(mUUIDs.front());
     }
     else if ("properties" == action)
     {
-        show_item_profile(selected_id);
+        show_item_profile(mUUIDs.front());
     }
     else if ("restore" == action)
     {
-        LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
-        if(cat)
+        for (LLUUID& selected_id : mUUIDs)
         {
-            const LLUUID new_parent = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
-            // do not restamp children on restore
-            gInventory.changeCategoryParent(cat, new_parent, false);
-        }
-        else
-        {
-            LLViewerInventoryItem* item = gInventory.getItem(selected_id);
-            if(item)
+            LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id);
+            if (cat)
             {
-                bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
-
-                const LLUUID new_parent = gInventory.findCategoryUUIDForType(is_snapshot? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
+                const LLUUID new_parent = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(cat->getType()));
                 // do not restamp children on restore
-                gInventory.changeItemParent(item, new_parent, false);
+                gInventory.changeCategoryParent(cat, new_parent, false);
+            }
+            else
+            {
+                LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+                if (item)
+                {
+                    bool is_snapshot = (item->getInventoryType() == LLInventoryType::IT_SNAPSHOT);
+
+                    const LLUUID new_parent = gInventory.findCategoryUUIDForType(is_snapshot ? LLFolderType::FT_SNAPSHOT_CATEGORY : LLFolderType::assetTypeToFolderType(item->getType()));
+                    // do not restamp children on restore
+                    gInventory.changeItemParent(item, new_parent, false);
+                }
             }
         }
     }
     else if ("copy_uuid" == action)
     {
-        LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+        LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
         if(item)
         {
             LLUUID asset_id = item->getProtectedAssetUUID();
@@ -123,15 +127,18 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
     }
     else if ("purge" == action)
     {
-        remove_inventory_object(selected_id, NULL);
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            remove_inventory_object(selected_id, NULL);
+        }
     }
     else if ("goto" == action)
     {
-        show_item_original(selected_id);
+        show_item_original(mUUIDs.front());
     }
     else if ("thumbnail" == action)
     {
-        LLSD data(selected_id);
+        LLSD data(mUUIDs.front());
         LLFloaterReg::showInstance("change_item_thumbnail", data);
     }
     else if ("cut" == action)
@@ -165,61 +172,70 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
     }
     else if ("rename" == action)
     {
-        LLSD args;
-        args["NAME"] = obj->getName();
-
-        LLSD payload;
-        payload["id"] = selected_id;
-
-        LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
+        rename(mUUIDs.front());
     }
     else if ("open" == action || "open_original" == action)
     {
-        LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+        LLViewerInventoryItem* item = gInventory.getItem(mUUIDs.front());
         if (item)
         {
-            LLInvFVBridgeAction::doAction(item->getType(), selected_id , &gInventory);
+            LLInvFVBridgeAction::doAction(item->getType(), mUUIDs.front(), &gInventory);
         }
     }
     else if ("ungroup_folder_items" == action)
     {
-        ungroup_folder_items(selected_id);
+        ungroup_folder_items(mUUIDs.front());
     }
     else if ("take_off" == action || "detach" == action)
     {
-        LLAppearanceMgr::instance().removeItemFromAvatar(selected_id);
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().removeItemFromAvatar(selected_id);
+        }
     }
     else if ("wear_add" == action)
     {
-        LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, false); // Don't replace if adding.
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, false); // Don't replace if adding.
+        }
     }
     else if ("wear" == action)
     {
-        LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, true);
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLAppearanceMgr::instance().wearItemOnAvatar(selected_id, true, true);
+        }
     }
     else if ("activate" == action)
     {
-        LLGestureMgr::instance().activateGesture(selected_id);
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLGestureMgr::instance().activateGesture(selected_id);
 
-        LLViewerInventoryItem* item = gInventory.getItem(selected_id);
-        if (!item) return;
+            LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+            if (!item) return;
 
-        gInventory.updateItem(item);
+            gInventory.updateItem(item);
+        }
         gInventory.notifyObservers();
     }
     else if ("deactivate" == action)
     {
-        LLGestureMgr::instance().deactivateGesture(selected_id);
+        for (LLUUID& selected_id : mUUIDs)
+        {
+            LLGestureMgr::instance().deactivateGesture(selected_id);
 
-        LLViewerInventoryItem* item = gInventory.getItem(selected_id);
-        if (!item) return;
+            LLViewerInventoryItem* item = gInventory.getItem(selected_id);
+            if (!item) return;
 
-        gInventory.updateItem(item);
+            gInventory.updateItem(item);
+        }
         gInventory.notifyObservers();
     }
     else if ("replace_links" == action)
     {
-        LLFloaterReg::showInstance("linkreplace", LLSD(selected_id));
+        LLFloaterReg::showInstance("linkreplace", LLSD(mUUIDs.front()));
     }
     else if ("copy_slurl" == action)
     {
@@ -236,7 +252,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
             };
             LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
         };
-        LLLandmark* landmark = LLLandmarkActions::getLandmark(selected_id, copy_slurl_cb);
+        LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), copy_slurl_cb);
         if (landmark)
         {
             copy_slurl_cb(landmark);
@@ -246,7 +262,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
     {
         LLSD key;
         key["type"] = "landmark";
-        key["id"] = selected_id;
+        key["id"] = mUUIDs.front();
         LLFloaterSidePanelContainer::showPanel("places", key);
     }
     else if ("show_on_map" == action)
@@ -264,7 +280,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
                 }
             }
         };
-        LLLandmark* landmark = LLLandmarkActions::getLandmark(selected_id, show_on_map_cb);
+        LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), show_on_map_cb);
         if(landmark)
         {
             show_on_map_cb(landmark);
@@ -272,7 +288,7 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
     }
     else if ("save_as" == action)
     {
-        LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", selected_id);
+        LLPreviewTexture* preview_texture = LLFloaterReg::getTypedInstance<LLPreviewTexture>("preview_texture", mUUIDs.front());
         if (preview_texture)
         {
             preview_texture->openToSave();
@@ -281,6 +297,20 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata, const LLU
     }
 }
 
+void LLInventoryGalleryContextMenu::rename(const LLUUID& item_id)
+{
+    LLInventoryObject* obj = gInventory.getObject(item_id);
+    if (!obj) return;
+
+    LLSD args;
+    args["NAME"] = obj->getName();
+
+    LLSD payload;
+    payload["id"] = mUUIDs.front();
+
+    LLNotificationsUtil::add("RenameItem", args, payload, boost::bind(onRename, _1, _2));
+}
+
 void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLSD& response)
 {
     S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
@@ -311,25 +341,39 @@ void LLInventoryGalleryContextMenu::onRename(const LLSD& notification, const LLS
     }
 }
 
-void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata, const LLUUID& selected_id)
+void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
 {
     const std::string param = userdata.asString();
     if (param == "model")
     {
-        gSavedPerAccountSettings.setString("ModelUploadFolder", selected_id.asString());
+        gSavedPerAccountSettings.setString("ModelUploadFolder", mUUIDs.front().asString());
     }
     else if (param == "texture")
     {
-        gSavedPerAccountSettings.setString("TextureUploadFolder", selected_id.asString());
+        gSavedPerAccountSettings.setString("TextureUploadFolder", mUUIDs.front().asString());
     }
     else if (param == "sound")
     {
-        gSavedPerAccountSettings.setString("SoundUploadFolder", selected_id.asString());
+        gSavedPerAccountSettings.setString("SoundUploadFolder", mUUIDs.front().asString());
     }
     else if (param == "animation")
     {
-        gSavedPerAccountSettings.setString("AnimationUploadFolder", selected_id.asString());
+        gSavedPerAccountSettings.setString("AnimationUploadFolder", mUUIDs.front().asString());
+    }
+}
+
+bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
+{
+    if (mUUIDs.size() != 1)
+    {
+        return false;
+    }
+    LLInventoryCategory* cat = gInventory.getCategory(mUUIDs.front());
+    if (!cat)
+    {
+        return false;
     }
+    return true;
 }
 
 bool is_inbox_folder(LLUUID item_id)
diff --git a/indra/newview/llinventorygallerymenu.h b/indra/newview/llinventorygallerymenu.h
index 67cf9a569aecdcd17d1420ea7869b56309230c3d..7c3545432b1d3797c77366036bf778bbc4d6beca 100644
--- a/indra/newview/llinventorygallerymenu.h
+++ b/indra/newview/llinventorygallerymenu.h
@@ -39,13 +39,15 @@ class LLInventoryGalleryContextMenu : public LLListContextMenu
 
     bool isRootFolder() { return mRootFolder; }
     void setRootFolder(bool is_root) { mRootFolder = is_root; }
-    void doToSelected(const LLSD& userdata, const LLUUID& selected_id);
+    void doToSelected(const LLSD& userdata);
+    void rename(const LLUUID& item_id);
 
 protected:
     //virtual void buildContextMenu(class LLMenuGL& menu, U32 flags);
     void updateMenuItemsVisibility(LLContextMenu* menu);
 
-    void fileUploadLocation(const LLSD& userdata, const LLUUID& selected_id);
+    void fileUploadLocation(const LLSD& userdata);
+    bool canSetUploadLocation(const LLSD& userdata);
 
     static void onRename(const LLSD& notification, const LLSD& response);
 
diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
index 46afa3821b85dc91d5f58b68576a5b82ab856407..d82c453e5f731328d4ca725ceb3108251d1c91ea 100644
--- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
+++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml
@@ -453,30 +453,38 @@
       <menu_item_call.on_click
        function="Inventory.FileUploadLocation"
         parameter="texture" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
     </menu_item_call>
     <menu_item_call
      label="Sound uploads"
      layout="topleft"
      name="Sound uploads">
-    <menu_item_call.on_click
-     function="Inventory.FileUploadLocation"
-     parameter="sound" />
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="sound" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
     </menu_item_call>
     <menu_item_call
      label="Animation uploads"
      layout="topleft"
      name="Animation uploads">
-    <menu_item_call.on_click
-     function="Inventory.FileUploadLocation"
-     parameter="animation" />
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="animation" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
     </menu_item_call>
     <menu_item_call
      label="Model uploads"
      layout="topleft"
      name="Model uploads">
-    <menu_item_call.on_click
-     function="Inventory.FileUploadLocation"
-     parameter="model" />
+      <menu_item_call.on_click
+       function="Inventory.FileUploadLocation"
+       parameter="model" />
+      <menu_item_call.on_visible
+       function="Inventory.CanSetUploadLocation" />
     </menu_item_call>
   </menu>
 	<menu_item_separator