diff options
Diffstat (limited to 'indra/newview/llpanellandmarks.cpp')
-rw-r--r-- | indra/newview/llpanellandmarks.cpp | 1436 |
1 files changed, 1298 insertions, 138 deletions
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 24b4082630..c4a484d368 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -2,61 +2,210 @@ * @file llpanellandmarks.cpp * @brief Landmarks tab for Side Bar "Places" panel * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llpanellandmarks.h" + +#include "llbutton.h" #include "llfloaterreg.h" -#include "lllandmark.h" +#include "llnotificationsutil.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "llregionhandle.h" +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" +#include "llagent.h" +#include "llagentpicksinfo.h" +#include "llagentui.h" +#include "llcallbacklist.h" +#include "lldndbutton.h" #include "llfloaterworldmap.h" -#include "lllandmarklist.h" -#include "llpanellandmarks.h" +#include "llfolderviewitem.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llinventorypanel.h" +#include "lllandmarkactions.h" +#include "llplacesinventorybridge.h" +#include "llplacesinventorypanel.h" #include "llsidetray.h" -#include "lltabcontainer.h" -#include "llworldmap.h" +#include "llviewermenu.h" +#include "llviewerregion.h" // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks"); +static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn"; +static const std::string ADD_BUTTON_NAME = "add_btn"; +static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn"; +static const std::string TRASH_BUTTON_NAME = "trash_btn"; + + +// helper functions +static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string); +static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list); +static void collapse_all_folders(LLFolderView* root_folder); +static void expand_all_folders(LLFolderView* root_folder); +static bool has_expanded_folders(LLFolderView* root_folder); +static bool has_collapsed_folders(LLFolderView* root_folder); + +/** + * Functor counting expanded and collapsed folders in folder view tree to know + * when to enable or disable "Expand all folders" and "Collapse all folders" commands. + */ +class LLCheckFolderState : public LLFolderViewFunctor +{ +public: + LLCheckFolderState() + : mCollapsedFolders(0), + mExpandedFolders(0) + {} + virtual ~LLCheckFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + S32 getCollapsedFolders() { return mCollapsedFolders; } + S32 getExpandedFolders() { return mExpandedFolders; } + +private: + S32 mCollapsedFolders; + S32 mExpandedFolders; +}; + +// virtual +void LLCheckFolderState::doFolder(LLFolderViewFolder* folder) +{ + // Counting only folders that pass the filter. + // The listener check allow us to avoid counting the folder view + // object itself because it has no listener assigned. + if (folder->hasFilteredDescendants() && folder->getListener()) + { + if (folder->isOpen()) + { + ++mExpandedFolders; + } + else + { + ++mCollapsedFolders; + } + } +} + +// Functor searching and opening a folder specified by UUID +// in a folder view tree. +class LLOpenFolderByID : public LLFolderViewFunctor +{ +public: + LLOpenFolderByID(const LLUUID& folder_id) + : mFolderID(folder_id) + , mIsFolderOpen(false) + {} + virtual ~LLOpenFolderByID() {} + /*virtual*/ void doFolder(LLFolderViewFolder* folder); + /*virtual*/ void doItem(LLFolderViewItem* item) {} + + bool isFolderOpen() { return mIsFolderOpen; } + +private: + bool mIsFolderOpen; + LLUUID mFolderID; +}; + +// virtual +void LLOpenFolderByID::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getListener() && folder->getListener()->getUUID() == mFolderID) + { + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + mIsFolderOpen = true; + } + } +} + +/** + * Bridge to support knowing when the inventory has changed to update Landmarks tab + * ShowFolderState filter setting to show all folders when the filter string is empty and + * empty folder message when Landmarks inventory category has no children. + * Ensures that "Landmarks" folder in the Library is open on strart up. + */ +class LLLandmarksPanelObserver : public LLInventoryObserver +{ +public: + LLLandmarksPanelObserver(LLLandmarksPanel* lp) + : mLP(lp), + mIsLibraryLandmarksOpen(false) + {} + virtual ~LLLandmarksPanelObserver() {} + /*virtual*/ void changed(U32 mask); + +private: + LLLandmarksPanel* mLP; + bool mIsLibraryLandmarksOpen; +}; + +void LLLandmarksPanelObserver::changed(U32 mask) +{ + mLP->updateShowFolderState(); + + LLPlacesInventoryPanel* library = mLP->getLibraryInventoryPanel(); + if (!mIsLibraryLandmarksOpen && library) + { + // Search for "Landmarks" folder in the Library and open it once on start up. See EXT-4827. + const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true); + if (landmarks_cat.notNull()) + { + LLOpenFolderByID opener(landmarks_cat); + library->getRootFolder()->applyFunctorRecursively(opener); + mIsLibraryLandmarksOpen = opener.isFolderOpen(); + } + } +} + LLLandmarksPanel::LLLandmarksPanel() - : LLPanelPlacesTab(), - mInventoryPanel(NULL) + : LLPanelPlacesTab() + , mFavoritesInventoryPanel(NULL) + , mLandmarksInventoryPanel(NULL) + , mMyInventoryPanel(NULL) + , mLibraryInventoryPanel(NULL) + , mCurrentSelectedList(NULL) + , mListCommands(NULL) + , mGearFolderMenu(NULL) + , mGearLandmarkMenu(NULL) { - mSavedFolderState = new LLSaveFolderState(); - mSavedFolderState->setApply(FALSE); + mInventoryObserver = new LLLandmarksPanelObserver(this); + gInventory.addObserver(mInventoryObserver); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml"); + buildFromFile( "panel_landmarks.xml"); } LLLandmarksPanel::~LLLandmarksPanel() { - delete mSavedFolderState; + if (gInventory.containsObserver(mInventoryObserver)) + { + gInventory.removeObserver(mInventoryObserver); + } } BOOL LLLandmarksPanel::postBuild() @@ -64,19 +213,13 @@ BOOL LLLandmarksPanel::postBuild() if (!gInventory.isInventoryUsable()) return FALSE; - mInventoryPanel = getChild<LLInventoryPanel>("landmarks_list"); - mInventoryPanel->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); - mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_LANDMARK); - mInventoryPanel->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2)); - - LLFolderView* root_folder = mInventoryPanel->getRootFolder(); - root_folder->setReshapeCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2)); + // mast be called before any other initXXX methods to init Gear menu + initListCommandsHandlers(); - mActionBtn = getChild<LLButton>("selector"); - root_folder->addChild(mActionBtn); - mActionBtn->setEnabled(TRUE); - childSetAction("selector", boost::bind(&LLLandmarksPanel::onSelectorButtonClicked, this), this); + initFavoritesInventoryPanel(); + initLandmarksInventoryPanel(); + initMyInventoryPanel(); + initLibraryInventoryPanel(); return TRUE; } @@ -84,169 +227,1186 @@ BOOL LLLandmarksPanel::postBuild() // virtual void LLLandmarksPanel::onSearchEdit(const std::string& string) { - if (string == "") + // give FolderView a chance to be refreshed. So, made all accordions visible + for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) { - mInventoryPanel->setFilterSubString(LLStringUtil::null); + LLAccordionCtrlTab* tab = *iter; + tab->setVisible(TRUE); - // re-open folders that were initially open - mSavedFolderState->setApply(TRUE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - LLOpenFoldersWithSelection opener; - mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); - mInventoryPanel->getRootFolder()->scrollToShowSelection(); - } + // expand accordion to see matched items in each one. See EXT-2014. + if (string != "") + { + tab->changeOpenClose(false); + } - gInventory.startBackgroundFetch(); + LLPlacesInventoryPanel* inventory_list = dynamic_cast<LLPlacesInventoryPanel*>(tab->getAccordionView()); + if (NULL == inventory_list) continue; - if (mInventoryPanel->getFilterSubString().empty() && string.empty()) - { - // current filter and new filter empty, do nothing - return; + if (inventory_list->getFilter()) + { + filter_list(inventory_list, string); + } } - // save current folder open state if no filter currently applied - if (mInventoryPanel->getRootFolder()->getFilterSubString().empty()) - { - mSavedFolderState->setApply(FALSE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } + if (sFilterSubString != string) + sFilterSubString = string; - // set new filter string - mInventoryPanel->setFilterSubString(string); + // show all folders in Landmarks Accordion for empty filter + // only if Landmarks inventory folder is not empty + updateShowFolderState(); } // virtual void LLLandmarksPanel::onShowOnMap() { - LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); - if (!current_item) + if (NULL == mCurrentSelectedList) + { + llwarns << "There are no selected list. No actions are performed." << llendl; return; + } - LLFolderViewEventListener* listenerp = current_item->getListener(); - if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK) - return; + // Disable the "Map" button because loading landmark can take some time. + // During this time the button is useless. It will be enabled on callback finish + // or upon switching to other item. + mShowOnMapBtn->setEnabled(FALSE); - LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID()); - if (!inventory_item) - return; + doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doShowOnMap, this, _1)); +} - LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID()); - if (!landmark) - return; +//virtual +void LLLandmarksPanel::onShowProfile() +{ + LLFolderViewItem* cur_item = getCurSelectedItem(); - LLVector3d landmark_global_pos; - if (!landmark->getGlobalPos(landmark_global_pos)) + if(!cur_item) return; - - if (!landmark_global_pos.isExactlyZero()) - { - LLFloaterWorldMap::getInstance()->trackLocation(landmark_global_pos); - LLFloaterReg::showInstance("world_map", "center"); - } + + cur_item->getListener()->performAction(mCurrentSelectedList->getModel(),"about"); } // virtual void LLLandmarksPanel::onTeleport() { - LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + LLFolderViewItem* current_item = getCurSelectedItem(); if (!current_item) + { + llwarns << "There are no selected list. No actions are performed." << llendl; return; + } LLFolderViewEventListener* listenerp = current_item->getListener(); if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) { listenerp->openItem(); } +} + +// virtual +bool LLLandmarksPanel::isSingleItemSelected() +{ + bool result = false; + + if (mCurrentSelectedList != NULL) + { + LLPlacesFolderView* root_view = + static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder()); + + if (root_view->getSelectedCount() == 1) + { + result = isLandmarkSelected(); + } + } - togglePanelPlacesButtons(TRUE); + return result; } -/* // virtual -void LLLandmarksPanel::onCopySLURL() +void LLLandmarksPanel::updateVerbs() { - LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); - if (!current_item) + if (!isTabVisible()) return; - LLFolderViewEventListener* listenerp = current_item->getListener(); - if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK) + bool landmark_selected = isLandmarkSelected(); + mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport")); + mShowProfile->setEnabled(landmark_selected && isActionEnabled("more_info")); + mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map")); + + // TODO: mantipov: Uncomment when mShareBtn is supported + // Share button should be enabled when neither a folder nor a landmark is selected + //mShareBtn->setEnabled(NULL != current_item); + + updateListCommands(); +} + +void LLLandmarksPanel::onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action) +{ + if (user_action && (items.size() > 0)) + { + deselectOtherThan(inventory_list); + mCurrentSelectedList = inventory_list; + } + updateVerbs(); +} + +void LLLandmarksPanel::onSelectorButtonClicked() +{ + // TODO: mantipov: update getting of selected item + // TODO: bind to "i" button + LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (!cur_item) return; + + LLFolderViewEventListener* listenerp = cur_item->getListener(); + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + LLSD key; + key["type"] = "landmark"; + key["id"] = listenerp->getUUID(); + + LLSideTray::getInstance()->showPanel("panel_places", key); + } +} + +void LLLandmarksPanel::updateShowFolderState() +{ + if (!mLandmarksInventoryPanel->getFilter()) return; - LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID()); - if (!inventory_item) + bool show_all_folders = mLandmarksInventoryPanel->getRootFolder()->getFilterSubString().empty(); + if (show_all_folders) + { + show_all_folders = category_has_descendents(mLandmarksInventoryPanel); + } + + mLandmarksInventoryPanel->setShowFolderState(show_all_folders ? + LLInventoryFilter::SHOW_ALL_FOLDERS : + LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS + ); +} + +void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus)) + { return; + } - LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID()); - if (!landmark) + if (selectItemInAccordionTab(mLandmarksInventoryPanel, "tab_landmarks", obj_id, take_keyboard_focus)) + { return; + } - LLVector3d landmark_global_pos; - if (!landmark->getGlobalPos(landmark_global_pos)) + if (selectItemInAccordionTab(mMyInventoryPanel, "tab_inventory", obj_id, take_keyboard_focus)) + { return; + } - U64 new_region_handle = to_region_handle(landmark_global_pos); + if (selectItemInAccordionTab(mLibraryInventoryPanel, "tab_library", obj_id, take_keyboard_focus)) + { + return; + } +} + +////////////////////////////////////////////////////////////////////////// +// PROTECTED METHODS +////////////////////////////////////////////////////////////////////////// - LLWorldMap::url_callback_t cb = boost::bind( - &LLPanelPlacesTab::onRegionResponse, this, - landmark_global_pos, _1, _2, _3, _4); +bool LLLandmarksPanel::isLandmarkSelected() const +{ + LLFolderViewItem* current_item = getCurSelectedItem(); + if(current_item && current_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + return true; + } - LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, cb, std::string("unused"), false); + return false; } -*/ -void LLLandmarksPanel::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action) +bool LLLandmarksPanel::isReceivedFolderSelected() const { - LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); - if (!current_item) + // Received Folder can be only in Landmarks accordion + if (mCurrentSelectedList != mLandmarksInventoryPanel) return false; + + // *TODO: it should be filled with logic when EXT-976 is done. + + llwarns << "Not implemented yet until EXT-976 is done." << llendl; + + return false; +} + +void LLLandmarksPanel::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb) +{ + LLFolderViewItem* cur_item = getCurSelectedItem(); + if(cur_item && cur_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + LLLandmark* landmark = LLLandmarkActions::getLandmark(cur_item->getListener()->getUUID(), cb); + if (landmark) + { + cb(landmark); + } + } +} + +LLFolderViewItem* LLLandmarksPanel::getCurSelectedItem() const +{ + return mCurrentSelectedList ? mCurrentSelectedList->getRootFolder()->getCurSelectedItem() : NULL; +} + +LLFolderViewItem* LLLandmarksPanel::selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list, + const std::string& tab_name, + const LLUUID& obj_id, + BOOL take_keyboard_focus) const +{ + if (!inventory_list) + return NULL; + + LLFolderView* root = inventory_list->getRootFolder(); + + LLFolderViewItem* item = root->getItemByID(obj_id); + if (!item) + return NULL; + + LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(tab_name); + if (!tab->isExpanded()) + { + tab->changeOpenClose(false); + } + + root->setSelection(item, FALSE, take_keyboard_focus); + + LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); + LLRect screen_rc; + localRectToScreen(item->getRect(), &screen_rc); + accordion->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue())); + + return item; +} + +void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate) +{ + if(!panel) return; + + U32 order = panel->getSortOrder(); + if (byDate) + { + panel->setSortOrder( order | LLInventoryFilter::SO_DATE ); + } + else + { + panel->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); + } +} + +// virtual +void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data) +{ + //this function will be called after user will try to create a pick for selected landmark. + // We have to make request to sever to get parcel_id and snaption_id. + if(isLandmarkSelected()) + { + LLFolderViewItem* cur_item = getCurSelectedItem(); + if (!cur_item) return; + LLUUID id = cur_item->getListener()->getUUID(); + LLInventoryItem* inv_item = mCurrentSelectedList->getModel()->getItem(id); + doActionOnCurSelectedLandmark(boost::bind( + &LLLandmarksPanel::doProcessParcelInfo, this, _1, cur_item, inv_item, parcel_data)); + } +} + +// virtual +void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id) +{ + if (!parcel_id.isNull()) + { + //ext-4655, defensive. remove now incase this gets called twice without a remove + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_id, this); + + LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); + } +} + +// virtual +void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason) +{ + llerrs<< "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl; +} + + +////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS +////////////////////////////////////////////////////////////////////////// + +void LLLandmarksPanel::initFavoritesInventoryPanel() +{ + mFavoritesInventoryPanel = getChild<LLPlacesInventoryPanel>("favorites_list"); + + initLandmarksPanel(mFavoritesInventoryPanel); + mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems"); + + initAccordion("tab_favorites", mFavoritesInventoryPanel, true); +} + +void LLLandmarksPanel::initLandmarksInventoryPanel() +{ + mLandmarksInventoryPanel = getChild<LLPlacesInventoryPanel>("landmarks_list"); + + initLandmarksPanel(mLandmarksInventoryPanel); + + // Check if mLandmarksInventoryPanel is properly initialized and has a Filter created. + // In case of a dummy widget getFilter() will return NULL. + if (mLandmarksInventoryPanel->getFilter()) + { + mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); + } + + // subscribe to have auto-rename functionality while creating New Folder + mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2)); + + mMyLandmarksAccordionTab = initAccordion("tab_landmarks", mLandmarksInventoryPanel, true); +} + +void LLLandmarksPanel::initMyInventoryPanel() +{ + mMyInventoryPanel= getChild<LLPlacesInventoryPanel>("my_inventory_list"); + + initLandmarksPanel(mMyInventoryPanel); + + initAccordion("tab_inventory", mMyInventoryPanel, false); +} + +void LLLandmarksPanel::initLibraryInventoryPanel() +{ + mLibraryInventoryPanel = getChild<LLPlacesInventoryPanel>("library_list"); + + initLandmarksPanel(mLibraryInventoryPanel); + + // We want to fetch only "Landmarks" category from the library. + const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true); + if (landmarks_cat.notNull()) + { + LLInventoryModelBackgroundFetch::instance().start(landmarks_cat); + } + + // Expanding "Library" tab for new users who have no landmarks in "My Inventory". + initAccordion("tab_library", mLibraryInventoryPanel, true); +} + +void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list) +{ + // In case of a dummy widget further we have no Folder View widget and no Filter, + // so further initialization leads to crash. + if (!inventory_list->getFilter()) return; - LLFolderViewEventListener* listenerp = current_item->getListener(); - if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems"); + inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); + inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2)); + + inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate"); + updateSortOrder(inventory_list, sorting_order); + + LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder()); + if (root_folder) + { + root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle()); + root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle()); + + root_folder->setParentLandmarksPanel(this); + } + + inventory_list->saveFolderState(); +} + +LLAccordionCtrlTab* LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab) +{ + LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name); + + mAccordionTabs.push_back(accordion_tab); + accordion_tab->setDropDownStateChangedCallback( + boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list)); + accordion_tab->setDisplayChildren(expand_tab); + return accordion_tab; +} + +void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list) +{ + bool expanded = param.asBoolean(); + + if(!expanded && (mCurrentSelectedList == inventory_list)) { - S32 bottom = 0; - LLFolderViewItem* folder = current_item->getParentFolder(); + inventory_list->getRootFolder()->clearSelection(); - while ( folder->getParentFolder() != NULL ) + mCurrentSelectedList = NULL; + updateVerbs(); + } + + // Start background fetch, mostly for My Inventory and Library + if (expanded) + { + const LLUUID &cat_id = inventory_list->getStartFolderID(); + // Just because the category itself has been fetched, doesn't mean its child folders have. + /* + if (!gInventory.isCategoryComplete(cat_id)) + */ { - bottom += folder->getRect().mBottom; - folder = folder->getParentFolder(); + LLInventoryModelBackgroundFetch::instance().start(cat_id); } - LLRect rect = current_item->getRect(); - LLRect btn_rect( - rect.mRight - mActionBtn->getRect().getWidth(), - bottom + rect.mTop, - rect.mRight, - bottom + rect.mBottom); + // Apply filter substring because it might have been changed + // while accordion was closed. See EXT-3714. + filter_list(inventory_list, sFilterSubString); + } +} - mActionBtn->setRect(btn_rect); +void LLLandmarksPanel::deselectOtherThan(const LLPlacesInventoryPanel* inventory_list) +{ + if (inventory_list != mFavoritesInventoryPanel) + { + mFavoritesInventoryPanel->getRootFolder()->clearSelection(); + } - if (!mActionBtn->getVisible()) - mActionBtn->setVisible(TRUE); + if (inventory_list != mLandmarksInventoryPanel) + { + mLandmarksInventoryPanel->getRootFolder()->clearSelection(); + } + if (inventory_list != mMyInventoryPanel) + { + mMyInventoryPanel->getRootFolder()->clearSelection(); + } + if (inventory_list != mLibraryInventoryPanel) + { + mLibraryInventoryPanel->getRootFolder()->clearSelection(); + } +} + +// List Commands Handlers +void LLLandmarksPanel::initListCommandsHandlers() +{ + mListCommands = getChild<LLPanel>("bottom_panel"); - togglePanelPlacesButtons(TRUE); + mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this)); + mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this)); + + LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME); + trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this + , _4 // BOOL drop + , _5 // EDragAndDropType cargo_type + , _6 // void* cargo_data + , _7 // EAcceptance* accept + )); + + mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2)); + mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2)); + mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2)); + mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2)); + mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2)); + mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2)); + mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + + mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME)); +} + + +void LLLandmarksPanel::updateListCommands() +{ + bool add_folder_enabled = isActionEnabled("category"); + bool trash_enabled = isActionEnabled("delete"); + + // keep Options & Add Landmark buttons always enabled + mListCommands->getChildView(ADD_FOLDER_BUTTON_NAME)->setEnabled(add_folder_enabled); + mListCommands->getChildView(TRASH_BUTTON_NAME)->setEnabled(trash_enabled); +} + +void LLLandmarksPanel::onActionsButtonClick() +{ + LLMenuGL* menu = mGearFolderMenu; + + LLFolderViewItem* cur_item = NULL; + if(mCurrentSelectedList) + { + cur_item = mCurrentSelectedList->getRootFolder()->getCurSelectedItem(); + if(!cur_item) + return; + + LLFolderViewEventListener* listenerp = cur_item->getListener(); + if(!listenerp) + return; + + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + menu = mGearLandmarkMenu; + } + } + + showActionMenu(menu,OPTIONS_BUTTON_NAME); +} + +void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) +{ + if (menu) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLView* spawning_view = getChild<LLView> (spawning_view_name); + S32 menu_x, menu_y; + //show menu in co-ordinates of panel + spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); + menu_y += menu->getRect().getHeight(); + LLMenuGL::showPopup(this, menu, menu_x, menu_y); + } +} + +void LLLandmarksPanel::onTrashButtonClick() const +{ + onClipboardAction("delete"); +} + +void LLLandmarksPanel::onAddAction(const LLSD& userdata) const +{ + std::string command_name = userdata.asString(); + if("add_landmark" == command_name) + { + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + if(landmark) + { + LLNotificationsUtil::add("LandmarkAlreadyExists"); + } + else + { + LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark")); + } + } + else if ("category" == command_name) + { + LLFolderViewItem* item = getCurSelectedItem(); + if (item && mCurrentSelectedList == mLandmarksInventoryPanel) + { + LLFolderViewEventListener* folder_bridge = NULL; + if (item-> getListener()->getInventoryType() + == LLInventoryType::IT_LANDMARK) + { + // for a landmark get parent folder bridge + folder_bridge = item->getParentFolder()->getListener(); + } + else if (item-> getListener()->getInventoryType() + == LLInventoryType::IT_CATEGORY) + { + // for a folder get its own bridge + folder_bridge = item->getListener(); + } + + menu_create_inventory_item(mCurrentSelectedList->getRootFolder(), + dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD( + "category"), gInventory.findCategoryUUIDForType( + LLFolderType::FT_LANDMARK)); + } + else + { + //in case My Landmarks tab is completely empty (thus cannot be determined as being selected) + menu_create_inventory_item(mLandmarksInventoryPanel->getRootFolder(), NULL, LLSD("category"), + gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK)); + + if (mMyLandmarksAccordionTab) + { + mMyLandmarksAccordionTab->changeOpenClose(false); + } + } + } +} + +void LLLandmarksPanel::onClipboardAction(const LLSD& userdata) const +{ + if(!mCurrentSelectedList) + return; + std::string command_name = userdata.asString(); + if("copy_slurl" == command_name) + { + LLFolderViewItem* cur_item = getCurSelectedItem(); + if(cur_item) + LLLandmarkActions::copySLURLtoClipboard(cur_item->getListener()->getUUID()); + } + else if ( "paste" == command_name) + { + mCurrentSelectedList->getRootFolder()->paste(); + } + else if ( "cut" == command_name) + { + mCurrentSelectedList->getRootFolder()->cut(); } else { - if (mActionBtn->getVisible()) - mActionBtn->setVisible(FALSE); + mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(),command_name); + } +} + +void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) +{ + std::string command_name = userdata.asString(); - togglePanelPlacesButtons(FALSE); + if ("expand_all" == command_name) + { + expand_all_folders(mFavoritesInventoryPanel->getRootFolder()); + expand_all_folders(mLandmarksInventoryPanel->getRootFolder()); + expand_all_folders(mMyInventoryPanel->getRootFolder()); + expand_all_folders(mLibraryInventoryPanel->getRootFolder()); + + for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) + { + (*iter)->changeOpenClose(false); + } + } + else if ("collapse_all" == command_name) + { + collapse_all_folders(mFavoritesInventoryPanel->getRootFolder()); + collapse_all_folders(mLandmarksInventoryPanel->getRootFolder()); + collapse_all_folders(mMyInventoryPanel->getRootFolder()); + collapse_all_folders(mLibraryInventoryPanel->getRootFolder()); + + for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) + { + (*iter)->changeOpenClose(true); + } + } + else if ("sort_by_date" == command_name) + { + bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate"); + sorting_order=!sorting_order; + gSavedSettings.setBOOL("LandmarksSortedByDate",sorting_order); + updateSortOrder(mLandmarksInventoryPanel, sorting_order); + updateSortOrder(mMyInventoryPanel, sorting_order); + updateSortOrder(mLibraryInventoryPanel, sorting_order); + } + else + { + if(mCurrentSelectedList) + { + mCurrentSelectedList->getRootFolder()->doToSelected(&gInventory, userdata); + } } } -void LLLandmarksPanel::onSelectorButtonClicked() +bool LLLandmarksPanel::isActionChecked(const LLSD& userdata) const { - LLFolderViewItem* cur_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + const std::string command_name = userdata.asString(); - LLFolderViewEventListener* listenerp = cur_item->getListener(); - if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + if ( "sort_by_date" == command_name) { - LLSD key; - key["type"] = LLPanelPlaces::LANDMARK; - key["id"] = listenerp->getUUID(); + bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate"); + return sorting_order; + } - LLSideTray::getInstance()->showPanel("panel_places", key); + return false; +} + +bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const +{ + std::string command_name = userdata.asString(); + + LLPlacesFolderView* root_folder_view = mCurrentSelectedList ? + static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder()) : NULL; + + if ("collapse_all" == command_name) + { + bool disable_collapse_all = !has_expanded_folders(mFavoritesInventoryPanel->getRootFolder()) + && !has_expanded_folders(mLandmarksInventoryPanel->getRootFolder()) + && !has_expanded_folders(mMyInventoryPanel->getRootFolder()) + && !has_expanded_folders(mLibraryInventoryPanel->getRootFolder()); + if (disable_collapse_all) + { + for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) + { + if ((*iter)->isExpanded()) + { + disable_collapse_all = false; + break; + } + } + } + + return !disable_collapse_all; + } + else if ("expand_all" == command_name) + { + bool disable_expand_all = !has_collapsed_folders(mFavoritesInventoryPanel->getRootFolder()) + && !has_collapsed_folders(mLandmarksInventoryPanel->getRootFolder()) + && !has_collapsed_folders(mMyInventoryPanel->getRootFolder()) + && !has_collapsed_folders(mLibraryInventoryPanel->getRootFolder()); + if (disable_expand_all) + { + for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) + { + if (!(*iter)->isExpanded()) + { + disable_expand_all = false; + break; + } + } + } + + return !disable_expand_all; + } + else if ("sort_by_date" == command_name) + { + // disable "sort_by_date" for Favorites accordion because + // it has its own items order. EXT-1758 + if (mCurrentSelectedList == mFavoritesInventoryPanel) + { + return false; + } + } + else if ( "paste" == command_name + || "cut" == command_name + || "copy" == command_name + || "delete" == command_name + || "collapse" == command_name + || "expand" == command_name + ) + { + if (!root_folder_view) return false; + + std::set<LLUUID> selected_uuids = root_folder_view->getSelectionList(); + + // Allow to execute the command only if it can be applied to all selected items. + for (std::set<LLUUID>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter) + { + LLFolderViewItem* item = root_folder_view->getItemByID(*iter); + + // If no item is found it might be a folder id. + if (!item) + { + item = root_folder_view->getFolderByID(*iter); + } + if (!item) return false; + + if (!canItemBeModified(command_name, item)) return false; + } + + return true; + } + else if ( "teleport" == command_name + || "more_info" == command_name + || "show_on_map" == command_name + || "copy_slurl" == command_name + || "rename" == command_name + ) + { + // disable some commands for multi-selection. EXT-1757 + bool is_single_selection = root_folder_view && root_folder_view->getSelectedCount() == 1; + if (!is_single_selection) + { + return false; + } + + if ("show_on_map" == command_name) + { + LLFolderViewItem* cur_item = root_folder_view->getCurSelectedItem(); + if (!cur_item) return false; + + LLViewerInventoryItem* inv_item = cur_item->getInventoryItem(); + if (!inv_item) return false; + + LLUUID asset_uuid = inv_item->getAssetUUID(); + if (asset_uuid.isNull()) return false; + + // Disable "Show on Map" if landmark loading is in progress. + return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid); + } + else if ("rename" == command_name) + { + LLFolderViewItem* selected_item = getCurSelectedItem(); + if (!selected_item) return false; + + return canItemBeModified(command_name, selected_item); + } + + return true; + } + else if("category" == command_name) + { + // we can add folder only in Landmarks Accordion + if (mCurrentSelectedList == mLandmarksInventoryPanel) + { + // ... but except Received folder + return !isReceivedFolderSelected(); + } + //"Add a folder" is enabled by default (case when My Landmarks is empty) + else return true; + } + else if("create_pick" == command_name) + { + if (mCurrentSelectedList) + { + std::set<LLUUID> selection = mCurrentSelectedList->getRootFolder()->getSelectionList(); + if (!selection.empty()) + { + return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() ); + } + } + return false; + } + else + { + llwarns << "Unprocessed command has come: " << command_name << llendl; + } + + return true; +} + +void LLLandmarksPanel::onCustomAction(const LLSD& userdata) +{ + std::string command_name = userdata.asString(); + if("more_info" == command_name) + { + onShowProfile(); + } + else if ("teleport" == command_name) + { + onTeleport(); + } + else if ("show_on_map" == command_name) + { + onShowOnMap(); + } + else if ("create_pick" == command_name) + { + doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1)); + } +} + +/* +Processes such actions: cut/rename/delete/paste actions + +Rules: + 1. We can't perform any action in Library + 2. For Landmarks we can: + - cut/rename/delete in any other accordions + - paste - only in Favorites, Landmarks accordions + 3. For Folders we can: perform any action in Landmarks accordion, except Received folder + 4. We can not paste folders from Clipboard (processed by LLFolderView::canPaste()) + 5. Check LLFolderView/Inventory Bridges rules + */ +bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFolderViewItem* item) const +{ + // validate own rules first + + if (!item) return false; + + // nothing can be modified in Library + if (mLibraryInventoryPanel == mCurrentSelectedList) return false; + + bool can_be_modified = false; + + // landmarks can be modified in any other accordion... + if (item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + can_be_modified = true; + + // we can modify landmarks anywhere except paste to My Inventory + if ("paste" == command_name) + { + can_be_modified = (mCurrentSelectedList != mMyInventoryPanel); + } + } + else + { + // ...folders only in the Landmarks accordion... + can_be_modified = mLandmarksInventoryPanel == mCurrentSelectedList; + + // ...except "Received" folder + can_be_modified &= !isReceivedFolderSelected(); + } + + // then ask LLFolderView permissions + + LLFolderView* root_folder = mCurrentSelectedList->getRootFolder(); + + if ("copy" == command_name) + { + return root_folder->canCopy(); + } + else if ("collapse" == command_name) + { + return item->isOpen(); + } + else if ("expand" == command_name) + { + return !item->isOpen(); + } + + if (can_be_modified) + { + LLFolderViewEventListener* listenerp = item->getListener(); + + if ("cut" == command_name) + { + // "Cut" disabled for folders. See EXT-8697. + can_be_modified = root_folder->canCut() && listenerp->getInventoryType() != LLInventoryType::IT_CATEGORY; + } + else if ("rename" == command_name) + { + can_be_modified = listenerp ? listenerp->isItemRenameable() : false; + } + else if ("delete" == command_name) + { + can_be_modified = listenerp ? listenerp->isItemRemovable() && !listenerp->isItemInTrash() : false; + } + else if("paste" == command_name) + { + can_be_modified = root_folder->canPaste(); + } + else + { + llwarns << "Unprocessed command has come: " << command_name << llendl; + } + } + + return can_be_modified; +} + +void LLLandmarksPanel::onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params) +{ + pick_panel->setVisible(FALSE); + owner->removeChild(pick_panel); + //we need remove observer to avoid processParcelInfo in the future. + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this); + + delete pick_panel; + pick_panel = NULL; +} + +bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data , EAcceptance* accept) +{ + *accept = ACCEPT_NO; + + switch (cargo_type) + { + + case DAD_LANDMARK: + case DAD_CATEGORY: + { + bool is_enabled = isActionEnabled("delete"); + + if (is_enabled) *accept = ACCEPT_YES_MULTI; + + if (is_enabled && drop) + { + // don't call onClipboardAction("delete") + // this lead to removing (N * 2 - 1) items if drag N>1 items into trash. EXT-6757 + // So, let remove items one by one. + LLInventoryItem* item = static_cast<LLInventoryItem*>(cargo_data); + if (item) + { + LLFolderViewItem* fv_item = (mCurrentSelectedList && mCurrentSelectedList->getRootFolder()) ? + mCurrentSelectedList->getRootFolder()->getItemByID(item->getUUID()) : NULL; + + if (fv_item) + { + // is Item Removable checked inside of remove() + fv_item->remove(); + } + } + } + } + break; + default: + break; + } + + return true; +} + +void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark) +{ + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return; + + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if (!landmark_global_pos.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(landmark_global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } + + mShowOnMapBtn->setEnabled(TRUE); + mGearLandmarkMenu->setItemEnabled("show_on_map", TRUE); +} + +void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark, + LLFolderViewItem* cur_item, + LLInventoryItem* inv_item, + const LLParcelData& parcel_data) +{ + LLPanelPickEdit* panel_pick = LLPanelPickEdit::create(); + LLVector3d landmark_global_pos; + landmark->getGlobalPos(landmark_global_pos); + + // let's toggle pick panel into panel places + LLPanel* panel_places = LLSideTray::getInstance()->getPanel("panel_places");//-> sidebar_places + if (!panel_places) + { + llassert(NULL != panel_places); + return; + } + panel_places->addChild(panel_pick); + LLRect paren_rect(panel_places->getRect()); + panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE); + panel_pick->setRect(paren_rect); + panel_pick->onOpen(LLSD()); + + LLPickData data; + data.pos_global = landmark_global_pos; + data.name = cur_item->getName(); + data.desc = inv_item->getDescription(); + data.snapshot_id = parcel_data.snapshot_id; + data.parcel_id = parcel_data.parcel_id; + panel_pick->setPickData(&data); + + LLSD params; + params["parcel_id"] = parcel_data.parcel_id; + /* set exit callback to get back onto panel places + in callback we will make cleaning up( delete pick_panel instance, + remove landmark panel from observer list + */ + panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, + panel_pick, panel_places,params)); + panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, + panel_pick, panel_places,params)); + panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, + panel_pick, panel_places,params)); +} + +void LLLandmarksPanel::doCreatePick(LLLandmark* landmark) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; + + LLGlobalVec pos_global; + LLUUID region_id; + landmark->getGlobalPos(pos_global); + landmark->getRegionID(region_id); + LLVector3 region_pos((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS), + (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS), + (F32)pos_global.mdV[VZ]); + + LLSD body; + std::string url = region->getCapability("RemoteParcelRequest"); + if (!url.empty()) + { + body["location"] = ll_sd_from_vector3(region_pos); + if (!region_id.isNull()) + { + body["region_id"] = region_id; + } + if (!pos_global.isExactlyZero()) + { + U64 region_handle = to_region_handle(pos_global); + body["region_handle"] = ll_sd_from_U64(region_handle); + } + LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); } + else + { + llwarns << "Can't create pick for landmark for region" << region_id + << ". Region: " << region->getName() + << " does not support RemoteParcelRequest" << llendl; + } +} + +////////////////////////////////////////////////////////////////////////// +// HELPER FUNCTIONS +////////////////////////////////////////////////////////////////////////// +static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string) +{ + // When search is cleared, restore the old folder state. + if (!inventory_list->getRootFolder()->getFilterSubString().empty() && string == "") + { + inventory_list->setFilterSubString(LLStringUtil::null); + // Re-open folders that were open before + inventory_list->restoreFolderState(); + } + + // Open the immediate children of the root folder, since those + // are invisible in the UI and thus must always be open. + inventory_list->getRootFolder()->openTopLevelFolders(); + + if (inventory_list->getFilterSubString().empty() && string.empty()) + { + // current filter and new filter empty, do nothing + return; + } + + // save current folder open state if no filter currently applied + if (inventory_list->getRootFolder()->getFilterSubString().empty()) + { + inventory_list->saveFolderState(); + } + + // Set new filter string + inventory_list->setFilterSubString(string); +} + +static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list) +{ + LLViewerInventoryCategory* category = gInventory.getCategory(inventory_list->getStartFolderID()); + if (category) + { + return category->getDescendentCount() > 0; + } + + return false; +} + +static void collapse_all_folders(LLFolderView* root_folder) +{ + if (!root_folder) + return; + + root_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + + // The top level folder is invisible, it must be open to + // display its sub-folders. + root_folder->openTopLevelFolders(); + root_folder->arrangeAll(); +} + +static void expand_all_folders(LLFolderView* root_folder) +{ + if (!root_folder) + return; + + root_folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + root_folder->arrangeAll(); +} + +static bool has_expanded_folders(LLFolderView* root_folder) +{ + LLCheckFolderState checker; + root_folder->applyFunctorRecursively(checker); + + // We assume that the root folder is always expanded so we enable "collapse_all" + // command when we have at least one more expanded folder. + if (checker.getExpandedFolders() < 2) + { + return false; + } + + return true; +} + +static bool has_collapsed_folders(LLFolderView* root_folder) +{ + LLCheckFolderState checker; + root_folder->applyFunctorRecursively(checker); + + if (checker.getCollapsedFolders() < 1) + { + return false; + } + + return true; } +// EOF |