/** * @file llpanellandmarks.cpp * @brief Landmarks tab for Side Bar "Places" panel * * $LicenseInfo:firstyear=2009&license=viewergpl$ * * Copyright (c) 2009, Linden Research, Inc. * * 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. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llpanellandmarks.h" #include "llbutton.h" #include "llfloaterreg.h" #include "llsdutil.h" #include "llsdutil_math.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 "llfolderviewitem.h" #include "llinventorypanel.h" #include "llinventorysubtreepanel.h" #include "lllandmarkactions.h" #include "llplacesinventorybridge.h" #include "llsidetray.h" #include "llviewermenu.h" #include "llviewerregion.h" // Not yet implemented; need to remove buildPanel() from constructor when we switch //static LLRegisterPanelClassWrapper 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(LLInventorySubTreePanel* inventory_list, const std::string& string); static void save_folder_state_if_no_filter(LLInventorySubTreePanel* inventory_list); /** * Bridge to support knowing when the inventory has changed to update folder (open/close) state * for landmarks panels. * * Due to Inventory data are loaded in background we need to save folder state each time * next level is loaded. See EXT-3094. */ class LLLandmarksPanelObserver : public LLInventoryObserver { public: LLLandmarksPanelObserver(LLLandmarksPanel* lp) : mLP(lp) {} virtual ~LLLandmarksPanelObserver() {} /*virtual*/ void changed(U32 mask); private: LLLandmarksPanel* mLP; }; void LLLandmarksPanelObserver::changed(U32 mask) { mLP->saveFolderStateIfNoFilter(); } LLLandmarksPanel::LLLandmarksPanel() : LLPanelPlacesTab() , mFavoritesInventoryPanel(NULL) , mLandmarksInventoryPanel(NULL) , mMyInventoryPanel(NULL) , mLibraryInventoryPanel(NULL) , mCurrentSelectedList(NULL) , mListCommands(NULL) , mGearFolderMenu(NULL) , mGearLandmarkMenu(NULL) { mInventoryObserver = new LLLandmarksPanelObserver(this); gInventory.addObserver(mInventoryObserver); LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml"); } LLLandmarksPanel::~LLLandmarksPanel() { if (gInventory.containsObserver(mInventoryObserver)) { gInventory.removeObserver(mInventoryObserver); } } BOOL LLLandmarksPanel::postBuild() { if (!gInventory.isInventoryUsable()) return FALSE; // mast be called before any other initXXX methods to init Gear menu initListCommandsHandlers(); U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER); mSortByDate = sort_order & LLInventoryFilter::SO_DATE; initFavoritesInventoryPanel(); initLandmarksInventoryPanel(); initMyInventoryPanel(); initLibraryInventoryPanel(); getChild("tab_favorites")->setDisplayChildren(true); getChild("tab_landmarks")->setDisplayChildren(true); gIdleCallbacks.addFunction(LLLandmarksPanel::doIdle, this); return TRUE; } // virtual void LLLandmarksPanel::onSearchEdit(const std::string& string) { // show all folders in Landmarks Accordion for empty filter if (mLandmarksInventoryPanel->getFilter()) { mLandmarksInventoryPanel->setShowFolderState(string.empty() ? LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS ); } // 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) { LLAccordionCtrlTab* tab = *iter; tab->setVisible(TRUE); // expand accordion to see matched items in each one. See EXT-2014. if (string != "") { tab->changeOpenClose(false); } LLInventorySubTreePanel* inventory_list = dynamic_cast(tab->getAccordionView()); if (NULL == inventory_list) continue; if (inventory_list->getFilter()) { filter_list(inventory_list, string); } } if (sFilterSubString != string) sFilterSubString = string; } // virtual void LLLandmarksPanel::onShowOnMap() { if (NULL == mCurrentSelectedList) { llwarns << "There are no selected list. No actions are performed." << llendl; 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); doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doShowOnMap, this, _1)); } // virtual void LLLandmarksPanel::onTeleport() { 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 void LLLandmarksPanel::updateVerbs() { if (!isTabVisible()) return; bool landmark_selected = isLandmarkSelected(); mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport")); 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(LLInventorySubTreePanel* inventory_list, const std::deque &items, BOOL user_action) { if (user_action && (items.size() > 0)) { deselectOtherThan(inventory_list); mCurrentSelectedList = inventory_list; } LLFolderViewItem* current_item = inventory_list->getRootFolder()->getCurSelectedItem(); if (!current_item) return; updateVerbs(); } void LLLandmarksPanel::onSelectorButtonClicked() { // TODO: mantipov: update getting of selected item // TODO: bind to "i" button LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem(); 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::saveFolderStateIfNoFilter() { save_folder_state_if_no_filter(mFavoritesInventoryPanel); save_folder_state_if_no_filter(mLandmarksInventoryPanel); save_folder_state_if_no_filter(mMyInventoryPanel); save_folder_state_if_no_filter(mLibraryInventoryPanel); } ////////////////////////////////////////////////////////////////////////// // PROTECTED METHODS ////////////////////////////////////////////////////////////////////////// bool LLLandmarksPanel::isLandmarkSelected() const { LLFolderViewItem* current_item = getCurSelectedItem(); if(current_item && current_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) { return true; } return false; } bool LLLandmarksPanel::isReceivedFolderSelected() const { // 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; } 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(); 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()) { 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<("favorites_list"); initLandmarksPanel(mFavoritesInventoryPanel); mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems"); initAccordion("tab_favorites", mFavoritesInventoryPanel); } void LLLandmarksPanel::initLandmarksInventoryPanel() { mLandmarksInventoryPanel = getChild("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)); initAccordion("tab_landmarks", mLandmarksInventoryPanel); } void LLLandmarksPanel::initMyInventoryPanel() { mMyInventoryPanel= getChild("my_inventory_list"); initLandmarksPanel(mMyInventoryPanel); initAccordion("tab_inventory", mMyInventoryPanel); } void LLLandmarksPanel::initLibraryInventoryPanel() { mLibraryInventoryPanel = getChild("library_list"); initLandmarksPanel(mLibraryInventoryPanel); initAccordion("tab_library", mLibraryInventoryPanel); } void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* 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; 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); updateSortOrder(inventory_list, mSortByDate); LLPlacesFolderView* root_folder = dynamic_cast(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); } void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list) { LLAccordionCtrlTab* accordion_tab = getChild(accordion_tab_name); mAccordionTabs.push_back(accordion_tab); accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list)); accordion_tab->setDisplayChildren(false); } void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLInventorySubTreePanel* inventory_list) { bool expanded = param.asBoolean(); if(!expanded && (mCurrentSelectedList == inventory_list)) { inventory_list->getRootFolder()->clearSelection(); 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)) */ { gInventory.startBackgroundFetch(cat_id); } } } void LLLandmarksPanel::deselectOtherThan(const LLInventorySubTreePanel* inventory_list) { if (inventory_list != mFavoritesInventoryPanel) { mFavoritesInventoryPanel->getRootFolder()->clearSelection(); } 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("bottom_panel"); mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this)); mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this)); mListCommands->getChild(ADD_BUTTON_NAME)->setHeldDownCallback(boost::bind(&LLLandmarksPanel::onAddButtonHeldDown, this)); static const LLSD add_landmark_command("add_landmark"); mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddAction, this, add_landmark_command)); LLDragAndDropButton* trash_btn = mListCommands->getChild(TRASH_BUTTON_NAME); trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this , _4 // BOOL drop , _5 // EDragAndDropType cargo_type , _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("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); } void LLLandmarksPanel::updateListCommands() { bool add_folder_enabled = isActionEnabled("category"); bool trash_enabled = isActionEnabled("delete"); // keep Options & Add Landmark buttons always enabled mListCommands->childSetEnabled(ADD_FOLDER_BUTTON_NAME, add_folder_enabled); mListCommands->childSetEnabled(TRASH_BUTTON_NAME, trash_enabled); mListCommands->childSetEnabled(OPTIONS_BUTTON_NAME,getCurSelectedItem() != NULL); } void LLLandmarksPanel::onActionsButtonClick() { LLFolderViewItem* cur_item = NULL; if(mCurrentSelectedList) cur_item = mCurrentSelectedList->getRootFolder()->getCurSelectedItem(); if(!cur_item) return; LLFolderViewEventListener* listenerp = cur_item->getListener(); LLMenuGL* menu =NULL; if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) { menu = mGearLandmarkMenu; } else if (listenerp->getInventoryType() == LLInventoryType::IT_CATEGORY) { mGearFolderMenu->getChild("expand")->setVisible(!cur_item->isOpen()); mGearFolderMenu->getChild("collapse")->setVisible(cur_item->isOpen()); menu = mGearFolderMenu; } showActionMenu(menu,OPTIONS_BUTTON_NAME); } void LLLandmarksPanel::onAddButtonHeldDown() { showActionMenu(mMenuAdd,ADD_BUTTON_NAME); } void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name) { if (menu) { menu->buildDrawLabels(); menu->updateParent(LLMenuGL::sMenuContainer); LLView* spawning_view = getChild (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) { LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); } 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 (folder_bridge), LLSD( "category"), gInventory.findCategoryUUIDForType( LLFolderType::FT_LANDMARK)); } } } 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 { mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(),command_name); } } void LLLandmarksPanel::onFoldingAction(const LLSD& userdata) { if(!mCurrentSelectedList) return; LLFolderView* root_folder = mCurrentSelectedList->getRootFolder(); std::string command_name = userdata.asString(); if ("expand_all" == command_name) { root_folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); root_folder->arrangeAll(); } else if ("collapse_all" == command_name) { root_folder->closeAllFolders(); } else if ( "sort_by_date" == command_name) { mSortByDate = !mSortByDate; updateSortOrder(mLandmarksInventoryPanel, mSortByDate); updateSortOrder(mMyInventoryPanel, mSortByDate); updateSortOrder(mLibraryInventoryPanel, mSortByDate); } else { root_folder->doToSelected(&gInventory, userdata); } } bool LLLandmarksPanel::isActionChecked(const LLSD& userdata) const { const std::string command_name = userdata.asString(); if ( "sort_by_date" == command_name) { return mSortByDate; } return false; } bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const { std::string command_name = userdata.asString(); LLPlacesFolderView* rootFolderView = mCurrentSelectedList ? static_cast(mCurrentSelectedList->getRootFolder()) : NULL; if (NULL == rootFolderView) return false; // disable some commands for multi-selection. EXT-1757 if (rootFolderView->getSelectedCount() > 1) { if ( "teleport" == command_name || "more_info" == command_name || "rename" == command_name || "show_on_map" == command_name || "copy_slurl" == command_name ) { return false; } } // disable some commands for Favorites accordion. EXT-1758 if (mCurrentSelectedList == mFavoritesInventoryPanel) { if ( "expand_all" == command_name || "collapse_all" == command_name || "sort_by_date" == command_name ) return false; } if("category" == command_name) { // we can add folder only in Landmarks Accordion if (mCurrentSelectedList == mLandmarksInventoryPanel) { // ... but except Received folder return !isReceivedFolderSelected(); } else return false; } else if("paste" == command_name || "rename" == command_name || "cut" == command_name || "delete" == command_name) { return canSelectedBeModified(command_name); } else if("create_pick" == command_name) { std::set selection; if ( mCurrentSelectedList && mCurrentSelectedList->getRootFolder()->getSelectionList(selection) ) { 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) { LLFolderViewItem* cur_item = getCurSelectedItem(); if(!cur_item) return ; std::string command_name = userdata.asString(); if("more_info" == command_name) { cur_item->getListener()->performAction(mCurrentSelectedList->getRootFolder(),mCurrentSelectedList->getModel(),"about"); } 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)); } } void LLLandmarksPanel::updateFilteredAccordions() { LLInventoryPanel* inventory_list = NULL; LLAccordionCtrlTab* accordion_tab = NULL; bool needs_arrange = false; for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) { accordion_tab = *iter; accordion_tab->setVisible(TRUE); inventory_list = dynamic_cast (accordion_tab->getAccordionView()); if (NULL == inventory_list) continue; // This doesn't seem to work correctly. Disabling for now. -Seraph // Enabled to show/hide accordions with/without landmarks. See EXT-2346. (Seth PE) LLFolderView* fv = inventory_list->getRootFolder(); // arrange folder view contents to draw its descendants if it has any fv->arrangeFromRoot(); bool has_descendants = fv->hasFilteredDescendants(); if (!has_descendants) needs_arrange = true; accordion_tab->setVisible(has_descendants); //accordion_tab->setVisible(TRUE); } // we have to arrange accordion tabs for cases when filter string is less restrictive but // all items are still filtered. if (needs_arrange) { static LLAccordionCtrl* accordion = getChild("landmarks_accordion"); accordion->arrange(); } } /* 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::canSelectedBeModified(const std::string& command_name) const { // validate own rules first // 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 (isLandmarkSelected()) { 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 if (can_be_modified) { LLFolderViewItem* selected = getCurSelectedItem(); if ("cut" == command_name) { can_be_modified = mCurrentSelectedList->getRootFolder()->canCut(); } else if ("rename" == command_name) { can_be_modified = selected? selected->getListener()->isItemRenameable() : false; } else if ("delete" == command_name) { can_be_modified = selected? selected->getListener()->isItemRemovable(): false; } else if("paste" == command_name) { return mCurrentSelectedList->getRootFolder()->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, 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) { onClipboardAction("delete"); } } break; default: break; } return true; } // static void LLLandmarksPanel::doIdle(void* landmarks_panel) { LLLandmarksPanel* panel = (LLLandmarksPanel* ) landmarks_panel; panel->updateFilteredAccordions(); } 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); } 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()->getChild("panel_places");//-> sidebar_places 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(LLInventorySubTreePanel* inventory_list, const std::string& string) { // 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 (string == "") { inventory_list->setFilterSubString(LLStringUtil::null); } if (inventory_list->getFilterSubString().empty() && string.empty()) { // current filter and new filter empty, do nothing return; } // Set new filter string inventory_list->setFilterSubString(string); } static void save_folder_state_if_no_filter(LLInventorySubTreePanel* inventory_list) { // save current folder open state if no filter currently applied if (inventory_list->getRootFolder() && inventory_list->getRootFolder()->getFilterSubString().empty()) { // inventory_list->saveFolderState(); // *TODO: commented out to fix build } } // EOF