llpanellandmarks.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:36k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file llpanellandmarks.cpp
  3.  * @brief Landmarks tab for Side Bar "Places" panel
  4.  *
  5.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2009-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpanellandmarks.h"
  34. #include "llbutton.h"
  35. #include "llfloaterreg.h"
  36. #include "llnotificationsutil.h"
  37. #include "llsdutil.h"
  38. #include "llsdutil_math.h"
  39. #include "llregionhandle.h"
  40. #include "llaccordionctrl.h"
  41. #include "llaccordionctrltab.h"
  42. #include "llagent.h"
  43. #include "llagentpicksinfo.h"
  44. #include "llagentui.h"
  45. #include "llcallbacklist.h"
  46. #include "lldndbutton.h"
  47. #include "llfloaterworldmap.h"
  48. #include "llfolderviewitem.h"
  49. #include "llinventorypanel.h"
  50. #include "lllandmarkactions.h"
  51. #include "llplacesinventorybridge.h"
  52. #include "llplacesinventorypanel.h"
  53. #include "llsidetray.h"
  54. #include "llviewermenu.h"
  55. #include "llviewerregion.h"
  56. // Not yet implemented; need to remove buildPanel() from constructor when we switch
  57. //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");
  58. static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn";
  59. static const std::string ADD_BUTTON_NAME = "add_btn";
  60. static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";
  61. static const std::string TRASH_BUTTON_NAME = "trash_btn";
  62. // helper functions
  63. static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string);
  64. static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list);
  65. /**
  66.  * Functor counting expanded and collapsed folders in folder view tree to know
  67.  * when to enable or disable "Expand all folders" and "Collapse all folders" commands.
  68.  */
  69. class LLCheckFolderState : public LLFolderViewFunctor
  70. {
  71. public:
  72. LLCheckFolderState()
  73. : mCollapsedFolders(0),
  74. mExpandedFolders(0)
  75. {}
  76. virtual ~LLCheckFolderState() {}
  77. virtual void doFolder(LLFolderViewFolder* folder);
  78. virtual void doItem(LLFolderViewItem* item) {}
  79. S32 getCollapsedFolders() { return mCollapsedFolders; }
  80. S32 getExpandedFolders() { return mExpandedFolders; }
  81. private:
  82. S32 mCollapsedFolders;
  83. S32 mExpandedFolders;
  84. };
  85. // virtual
  86. void LLCheckFolderState::doFolder(LLFolderViewFolder* folder)
  87. {
  88. // Counting only folders that pass the filter.
  89. // The listener check allow us to avoid counting the folder view
  90. // object itself because it has no listener assigned.
  91. if (folder->hasFilteredDescendants() && folder->getListener())
  92. {
  93. if (folder->isOpen())
  94. {
  95. ++mExpandedFolders;
  96. }
  97. else
  98. {
  99. ++mCollapsedFolders;
  100. }
  101. }
  102. }
  103. // Functor searching and opening a folder specified by UUID
  104. // in a folder view tree.
  105. class LLOpenFolderByID : public LLFolderViewFunctor
  106. {
  107. public:
  108. LLOpenFolderByID(const LLUUID& folder_id)
  109. : mFolderID(folder_id)
  110. , mIsFolderOpen(false)
  111. {}
  112. virtual ~LLOpenFolderByID() {}
  113. /*virtual*/ void doFolder(LLFolderViewFolder* folder);
  114. /*virtual*/ void doItem(LLFolderViewItem* item) {}
  115. bool isFolderOpen() { return mIsFolderOpen; }
  116. private:
  117. bool mIsFolderOpen;
  118. LLUUID mFolderID;
  119. };
  120. // virtual
  121. void LLOpenFolderByID::doFolder(LLFolderViewFolder* folder)
  122. {
  123. if (folder->getListener() && folder->getListener()->getUUID() == mFolderID)
  124. {
  125. if (!folder->isOpen())
  126. {
  127. folder->setOpen(TRUE);
  128. mIsFolderOpen = true;
  129. }
  130. }
  131. }
  132. /**
  133.  * Bridge to support knowing when the inventory has changed to update Landmarks tab
  134.  * ShowFolderState filter setting to show all folders when the filter string is empty and
  135.  * empty folder message when Landmarks inventory category has no children.
  136.  * Ensures that "Landmarks" folder in the Library is open on strart up.
  137.  */
  138. class LLLandmarksPanelObserver : public LLInventoryObserver
  139. {
  140. public:
  141. LLLandmarksPanelObserver(LLLandmarksPanel* lp)
  142. : mLP(lp),
  143.   mIsLibraryLandmarksOpen(false)
  144. {}
  145. virtual ~LLLandmarksPanelObserver() {}
  146. /*virtual*/ void changed(U32 mask);
  147. private:
  148. LLLandmarksPanel* mLP;
  149. bool mIsLibraryLandmarksOpen;
  150. };
  151. void LLLandmarksPanelObserver::changed(U32 mask)
  152. {
  153. mLP->updateShowFolderState();
  154. LLPlacesInventoryPanel* library = mLP->getLibraryInventoryPanel();
  155. if (!mIsLibraryLandmarksOpen && library)
  156. {
  157. // Search for "Landmarks" folder in the Library and open it once on start up. See EXT-4827.
  158. const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);
  159. if (landmarks_cat.notNull())
  160. {
  161. LLOpenFolderByID opener(landmarks_cat);
  162. library->getRootFolder()->applyFunctorRecursively(opener);
  163. mIsLibraryLandmarksOpen = opener.isFolderOpen();
  164. }
  165. }
  166. }
  167. LLLandmarksPanel::LLLandmarksPanel()
  168. : LLPanelPlacesTab()
  169. , mFavoritesInventoryPanel(NULL)
  170. , mLandmarksInventoryPanel(NULL)
  171. , mMyInventoryPanel(NULL)
  172. , mLibraryInventoryPanel(NULL)
  173. , mCurrentSelectedList(NULL)
  174. , mListCommands(NULL)
  175. , mGearFolderMenu(NULL)
  176. , mGearLandmarkMenu(NULL)
  177. {
  178. mInventoryObserver = new LLLandmarksPanelObserver(this);
  179. gInventory.addObserver(mInventoryObserver);
  180. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");
  181. }
  182. LLLandmarksPanel::~LLLandmarksPanel()
  183. {
  184. if (gInventory.containsObserver(mInventoryObserver))
  185. {
  186. gInventory.removeObserver(mInventoryObserver);
  187. }
  188. }
  189. BOOL LLLandmarksPanel::postBuild()
  190. {
  191. if (!gInventory.isInventoryUsable())
  192. return FALSE;
  193. // mast be called before any other initXXX methods to init Gear menu
  194. initListCommandsHandlers();
  195. U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER);
  196. mSortByDate = sort_order & LLInventoryFilter::SO_DATE;
  197. initFavoritesInventoryPanel();
  198. initLandmarksInventoryPanel();
  199. initMyInventoryPanel();
  200. initLibraryInventoryPanel();
  201. return TRUE;
  202. }
  203. // virtual
  204. void LLLandmarksPanel::onSearchEdit(const std::string& string)
  205. {
  206. // give FolderView a chance to be refreshed. So, made all accordions visible
  207. for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
  208. {
  209. LLAccordionCtrlTab* tab = *iter;
  210. tab->setVisible(TRUE);
  211. // expand accordion to see matched items in each one. See EXT-2014.
  212. if (string != "")
  213. {
  214. tab->changeOpenClose(false);
  215. }
  216. LLPlacesInventoryPanel* inventory_list = dynamic_cast<LLPlacesInventoryPanel*>(tab->getAccordionView());
  217. if (NULL == inventory_list) continue;
  218. if (inventory_list->getFilter())
  219. {
  220. filter_list(inventory_list, string);
  221. }
  222. }
  223. if (sFilterSubString != string)
  224. sFilterSubString = string;
  225. // show all folders in Landmarks Accordion for empty filter
  226. // only if Landmarks inventory folder is not empty
  227. updateShowFolderState();
  228. }
  229. // virtual
  230. void LLLandmarksPanel::onShowOnMap()
  231. {
  232. if (NULL == mCurrentSelectedList)
  233. {
  234. llwarns << "There are no selected list. No actions are performed." << llendl;
  235. return;
  236. }
  237. // Disable the "Map" button because loading landmark can take some time.
  238. // During this time the button is useless. It will be enabled on callback finish
  239. // or upon switching to other item.
  240. mShowOnMapBtn->setEnabled(FALSE);
  241. doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doShowOnMap, this, _1));
  242. }
  243. // virtual
  244. void LLLandmarksPanel::onTeleport()
  245. {
  246. LLFolderViewItem* current_item = getCurSelectedItem();
  247. if (!current_item)
  248. {
  249. llwarns << "There are no selected list. No actions are performed." << llendl;
  250. return;
  251. }
  252. LLFolderViewEventListener* listenerp = current_item->getListener();
  253. if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
  254. {
  255. listenerp->openItem();
  256. }
  257. }
  258. // virtual
  259. void LLLandmarksPanel::updateVerbs()
  260. {
  261. if (!isTabVisible()) 
  262. return;
  263. bool landmark_selected = isLandmarkSelected();
  264. mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport"));
  265. mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map"));
  266. // TODO: mantipov: Uncomment when mShareBtn is supported
  267. // Share button should be enabled when neither a folder nor a landmark is selected
  268. //mShareBtn->setEnabled(NULL != current_item);
  269. updateListCommands();
  270. }
  271. void LLLandmarksPanel::onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
  272. {
  273. if (user_action && (items.size() > 0))
  274. {
  275. deselectOtherThan(inventory_list);
  276. mCurrentSelectedList = inventory_list;
  277. }
  278. updateVerbs();
  279. }
  280. void LLLandmarksPanel::onSelectorButtonClicked()
  281. {
  282. // TODO: mantipov: update getting of selected item
  283. // TODO: bind to "i" button
  284. LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem();
  285. if (!cur_item) return;
  286. LLFolderViewEventListener* listenerp = cur_item->getListener();
  287. if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
  288. {
  289. LLSD key;
  290. key["type"] = "landmark";
  291. key["id"] = listenerp->getUUID();
  292. LLSideTray::getInstance()->showPanel("panel_places", key);
  293. }
  294. }
  295. void LLLandmarksPanel::updateShowFolderState()
  296. {
  297. if (!mLandmarksInventoryPanel->getFilter())
  298. return;
  299. bool show_all_folders = mLandmarksInventoryPanel->getRootFolder()->getFilterSubString().empty();
  300. if (show_all_folders)
  301. {
  302. show_all_folders = category_has_descendents(mLandmarksInventoryPanel);
  303. }
  304. mLandmarksInventoryPanel->setShowFolderState(show_all_folders ?
  305. LLInventoryFilter::SHOW_ALL_FOLDERS :
  306. LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS
  307. );
  308. }
  309. void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus)
  310. {
  311. if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus))
  312. {
  313. return;
  314. }
  315. if (selectItemInAccordionTab(mLandmarksInventoryPanel, "tab_landmarks", obj_id, take_keyboard_focus))
  316. {
  317. return;
  318. }
  319. if (selectItemInAccordionTab(mMyInventoryPanel, "tab_inventory", obj_id, take_keyboard_focus))
  320. {
  321. return;
  322. }
  323. if (selectItemInAccordionTab(mLibraryInventoryPanel, "tab_library", obj_id, take_keyboard_focus))
  324. {
  325. return;
  326. }
  327. }
  328. //////////////////////////////////////////////////////////////////////////
  329. // PROTECTED METHODS
  330. //////////////////////////////////////////////////////////////////////////
  331. bool LLLandmarksPanel::isLandmarkSelected() const 
  332. {
  333. LLFolderViewItem* current_item = getCurSelectedItem();
  334. if(current_item && current_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
  335. {
  336. return true;
  337. }
  338. return false;
  339. }
  340. bool LLLandmarksPanel::isReceivedFolderSelected() const
  341. {
  342. // Received Folder can be only in Landmarks accordion
  343. if (mCurrentSelectedList != mLandmarksInventoryPanel) return false;
  344. // *TODO: it should be filled with logic when EXT-976 is done.
  345. llwarns << "Not implemented yet until EXT-976 is done." << llendl;
  346. return false;
  347. }
  348. void LLLandmarksPanel::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb)
  349. {
  350. LLFolderViewItem* cur_item = getCurSelectedItem();
  351. if(cur_item && cur_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
  352. LLLandmark* landmark = LLLandmarkActions::getLandmark(cur_item->getListener()->getUUID(), cb);
  353. if (landmark)
  354. {
  355. cb(landmark);
  356. }
  357. }
  358. }
  359. LLFolderViewItem* LLLandmarksPanel::getCurSelectedItem() const 
  360. {
  361. return mCurrentSelectedList ?  mCurrentSelectedList->getRootFolder()->getCurSelectedItem() : NULL;
  362. }
  363. LLFolderViewItem* LLLandmarksPanel::selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list,
  364.  const std::string& tab_name,
  365.  const LLUUID& obj_id,
  366.  BOOL take_keyboard_focus) const
  367. {
  368. if (!inventory_list)
  369. return NULL;
  370. LLFolderView* folder_view = inventory_list->getRootFolder();
  371. LLFolderViewItem* item = folder_view->getItemByID(obj_id);
  372. if (!item)
  373. return NULL;
  374. LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(tab_name);
  375. if (!tab->isExpanded())
  376. {
  377. tab->changeOpenClose(false);
  378. }
  379. folder_view->setSelection(item, FALSE, take_keyboard_focus);
  380. LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion");
  381. LLRect screen_rc;
  382. localRectToScreen(item->getRect(), &screen_rc);
  383. accordion->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue()));
  384. return item;
  385. }
  386. void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate)
  387. {
  388. if(!panel) return; 
  389. U32 order = panel->getSortOrder();
  390. if (byDate)
  391. {
  392. panel->setSortOrder( order | LLInventoryFilter::SO_DATE );
  393. }
  394. else 
  395. {
  396. panel->setSortOrder( order & ~LLInventoryFilter::SO_DATE );
  397. }
  398. }
  399. // virtual
  400. void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)
  401. {
  402. //this function will be called after user will try to create a pick for selected landmark.
  403. // We have to make request to sever to get parcel_id and snaption_id. 
  404. if(isLandmarkSelected())
  405. {
  406. LLFolderViewItem* cur_item = getCurSelectedItem();
  407. if (!cur_item) return;
  408. LLUUID id = cur_item->getListener()->getUUID();
  409. LLInventoryItem* inv_item = mCurrentSelectedList->getModel()->getItem(id);
  410. doActionOnCurSelectedLandmark(boost::bind(
  411. &LLLandmarksPanel::doProcessParcelInfo, this, _1, cur_item, inv_item, parcel_data));
  412. }
  413. }
  414. // virtual
  415. void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
  416. {
  417. if (!parcel_id.isNull())
  418. {
  419. LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
  420. LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
  421. }
  422. }
  423. // virtual
  424. void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason)
  425. {
  426. llerrs<< "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
  427. }
  428. //////////////////////////////////////////////////////////////////////////
  429. // PRIVATE METHODS
  430. //////////////////////////////////////////////////////////////////////////
  431. void LLLandmarksPanel::initFavoritesInventoryPanel()
  432. {
  433. mFavoritesInventoryPanel = getChild<LLPlacesInventoryPanel>("favorites_list");
  434. initLandmarksPanel(mFavoritesInventoryPanel);
  435. mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems");
  436. initAccordion("tab_favorites", mFavoritesInventoryPanel, true);
  437. }
  438. void LLLandmarksPanel::initLandmarksInventoryPanel()
  439. {
  440. mLandmarksInventoryPanel = getChild<LLPlacesInventoryPanel>("landmarks_list");
  441. initLandmarksPanel(mLandmarksInventoryPanel);
  442. // Check if mLandmarksInventoryPanel is properly initialized and has a Filter created.
  443. // In case of a dummy widget getFilter() will return NULL.
  444. if (mLandmarksInventoryPanel->getFilter())
  445. {
  446. mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS);
  447. }
  448. // subscribe to have auto-rename functionality while creating New Folder
  449. mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2));
  450. initAccordion("tab_landmarks", mLandmarksInventoryPanel, true);
  451. }
  452. void LLLandmarksPanel::initMyInventoryPanel()
  453. {
  454. mMyInventoryPanel= getChild<LLPlacesInventoryPanel>("my_inventory_list");
  455. initLandmarksPanel(mMyInventoryPanel);
  456. initAccordion("tab_inventory", mMyInventoryPanel, false);
  457. }
  458. void LLLandmarksPanel::initLibraryInventoryPanel()
  459. {
  460. mLibraryInventoryPanel = getChild<LLPlacesInventoryPanel>("library_list");
  461. initLandmarksPanel(mLibraryInventoryPanel);
  462. // We want to fetch only "Landmarks" category from the library.
  463. const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);
  464. if (landmarks_cat.notNull())
  465. {
  466. gInventory.startBackgroundFetch(landmarks_cat);
  467. }
  468. // Expanding "Library" tab for new users who have no landmarks in "My Inventory".
  469. initAccordion("tab_library", mLibraryInventoryPanel, true);
  470. }
  471. void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list)
  472. {
  473. // In case of a dummy widget further we have no Folder View widget and no Filter,
  474. // so further initialization leads to crash.
  475. if (!inventory_list->getFilter())
  476. return;
  477. inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
  478. inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2));
  479. inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
  480. updateSortOrder(inventory_list, mSortByDate);
  481. LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder());
  482. if (root_folder)
  483. {
  484. root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle());
  485. root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle());
  486. root_folder->setParentLandmarksPanel(this);
  487. }
  488. inventory_list->saveFolderState();
  489. }
  490. void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list, bool expand_tab)
  491. {
  492. LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name);
  493. mAccordionTabs.push_back(accordion_tab);
  494. accordion_tab->setDropDownStateChangedCallback(
  495. boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));
  496. accordion_tab->setDisplayChildren(expand_tab);
  497. }
  498. void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list)
  499. {
  500. bool expanded = param.asBoolean();
  501. if(!expanded && (mCurrentSelectedList == inventory_list))
  502. {
  503. inventory_list->getRootFolder()->clearSelection();
  504. mCurrentSelectedList = NULL;
  505. updateVerbs();
  506. }
  507. // Start background fetch, mostly for My Inventory and Library
  508. if (expanded)
  509. {
  510. const LLUUID &cat_id = inventory_list->getStartFolderID();
  511. // Just because the category itself has been fetched, doesn't mean its child folders have.
  512. /*
  513.   if (!gInventory.isCategoryComplete(cat_id))
  514. */
  515. {
  516. gInventory.startBackgroundFetch(cat_id);
  517. }
  518. // Apply filter substring because it might have been changed
  519. // while accordion was closed. See EXT-3714.
  520. filter_list(inventory_list, sFilterSubString);
  521. }
  522. }
  523. void LLLandmarksPanel::deselectOtherThan(const LLPlacesInventoryPanel* inventory_list)
  524. {
  525. if (inventory_list != mFavoritesInventoryPanel)
  526. {
  527. mFavoritesInventoryPanel->getRootFolder()->clearSelection();
  528. }
  529. if (inventory_list != mLandmarksInventoryPanel)
  530. {
  531. mLandmarksInventoryPanel->getRootFolder()->clearSelection();
  532. }
  533. if (inventory_list != mMyInventoryPanel)
  534. {
  535. mMyInventoryPanel->getRootFolder()->clearSelection();
  536. }
  537. if (inventory_list != mLibraryInventoryPanel)
  538. {
  539. mLibraryInventoryPanel->getRootFolder()->clearSelection();
  540. }
  541. }
  542. // List Commands Handlers
  543. void LLLandmarksPanel::initListCommandsHandlers()
  544. {
  545. mListCommands = getChild<LLPanel>("bottom_panel");
  546. mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
  547. mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this));
  548. mListCommands->getChild<LLButton>(ADD_BUTTON_NAME)->setHeldDownCallback(boost::bind(&LLLandmarksPanel::onAddButtonHeldDown, this));
  549. static const LLSD add_landmark_command("add_landmark");
  550. mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddAction, this, add_landmark_command));
  551. LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);
  552. trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this
  553. , _4 // BOOL drop
  554. , _5 // EDragAndDropType cargo_type
  555. , _7 // EAcceptance* accept
  556. ));
  557. mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2));
  558. mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2));
  559. mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2));
  560. mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
  561. mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2));
  562. mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
  563. mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  564. mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  565. mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  566. }
  567. void LLLandmarksPanel::updateListCommands()
  568. {
  569. bool add_folder_enabled = isActionEnabled("category");
  570. bool trash_enabled = isActionEnabled("delete");
  571. // keep Options & Add Landmark buttons always enabled
  572. mListCommands->childSetEnabled(ADD_FOLDER_BUTTON_NAME, add_folder_enabled);
  573. mListCommands->childSetEnabled(TRASH_BUTTON_NAME, trash_enabled);
  574. mListCommands->childSetEnabled(OPTIONS_BUTTON_NAME,getCurSelectedItem() != NULL);
  575. }
  576. void LLLandmarksPanel::onActionsButtonClick()
  577. {
  578. LLFolderViewItem* cur_item = NULL;
  579. if(mCurrentSelectedList)
  580. cur_item = mCurrentSelectedList->getRootFolder()->getCurSelectedItem();
  581. if(!cur_item)
  582. return;
  583. LLFolderViewEventListener* listenerp = cur_item->getListener();
  584. LLMenuGL* menu  =NULL;
  585. if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
  586. {
  587. menu = mGearLandmarkMenu;
  588. }
  589. else if (listenerp->getInventoryType() == LLInventoryType::IT_CATEGORY)
  590. {
  591. mGearFolderMenu->getChild<LLMenuItemCallGL>("expand")->setVisible(!cur_item->isOpen());
  592. mGearFolderMenu->getChild<LLMenuItemCallGL>("collapse")->setVisible(cur_item->isOpen());
  593. menu = mGearFolderMenu;
  594. }
  595. showActionMenu(menu,OPTIONS_BUTTON_NAME);
  596. }
  597. void LLLandmarksPanel::onAddButtonHeldDown()
  598. {
  599. showActionMenu(mMenuAdd,ADD_BUTTON_NAME);
  600. }
  601. void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
  602. {
  603. if (menu)
  604. {
  605. menu->buildDrawLabels();
  606. menu->updateParent(LLMenuGL::sMenuContainer);
  607. LLView* spawning_view = getChild<LLView> (spawning_view_name);
  608. S32 menu_x, menu_y;
  609. //show menu in co-ordinates of panel
  610. spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
  611. menu_y += menu->getRect().getHeight();
  612. LLMenuGL::showPopup(this, menu, menu_x, menu_y);
  613. }
  614. }
  615. void LLLandmarksPanel::onTrashButtonClick() const
  616. {
  617. onClipboardAction("delete");
  618. }
  619. void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
  620. {
  621. std::string command_name = userdata.asString();
  622. if("add_landmark" == command_name)
  623. {
  624. LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
  625. if(landmark)
  626. {
  627. LLNotificationsUtil::add("LandmarkAlreadyExists");
  628. }
  629. else
  630. {
  631. LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
  632. }
  633. else if ("category" == command_name)
  634. {
  635. LLFolderViewItem* item = getCurSelectedItem();
  636. if (item && mCurrentSelectedList == mLandmarksInventoryPanel)
  637. {
  638. LLFolderViewEventListener* folder_bridge = NULL;
  639. if (item-> getListener()->getInventoryType()
  640. == LLInventoryType::IT_LANDMARK)
  641. {
  642. // for a landmark get parent folder bridge
  643. folder_bridge = item->getParentFolder()->getListener();
  644. }
  645. else if (item-> getListener()->getInventoryType()
  646. == LLInventoryType::IT_CATEGORY)
  647. {
  648. // for a folder get its own bridge
  649. folder_bridge = item->getListener();
  650. }
  651. menu_create_inventory_item(mCurrentSelectedList->getRootFolder(),
  652. dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD(
  653. "category"), gInventory.findCategoryUUIDForType(
  654. LLFolderType::FT_LANDMARK));
  655. }
  656. }
  657. }
  658. void LLLandmarksPanel::onClipboardAction(const LLSD& userdata) const
  659. {
  660. if(!mCurrentSelectedList) 
  661. return;
  662. std::string command_name = userdata.asString();
  663.     if("copy_slurl" == command_name)
  664. {
  665.      LLFolderViewItem* cur_item = getCurSelectedItem();
  666. if(cur_item)
  667. LLLandmarkActions::copySLURLtoClipboard(cur_item->getListener()->getUUID());
  668. }
  669. else if ( "paste" == command_name)
  670. {
  671. mCurrentSelectedList->getRootFolder()->paste();
  672. else if ( "cut" == command_name)
  673. {
  674. mCurrentSelectedList->getRootFolder()->cut();
  675. }
  676. else
  677. {
  678. mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(),command_name);
  679. }
  680. }
  681. void LLLandmarksPanel::onFoldingAction(const LLSD& userdata)
  682. {
  683. if(!mCurrentSelectedList) return;
  684. LLFolderView* root_folder = mCurrentSelectedList->getRootFolder();
  685. std::string command_name = userdata.asString();
  686. if ("expand_all" == command_name)
  687. {
  688. root_folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
  689. root_folder->arrangeAll();
  690. }
  691. else if ("collapse_all" == command_name)
  692. {
  693. root_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
  694. // The top level folder is invisible, it must be open to
  695. // display its sub-folders.
  696. root_folder->openTopLevelFolders();
  697. root_folder->arrangeAll();
  698. }
  699. else if ( "sort_by_date" == command_name)
  700. {
  701. mSortByDate = !mSortByDate;
  702. updateSortOrder(mLandmarksInventoryPanel, mSortByDate);
  703. updateSortOrder(mMyInventoryPanel, mSortByDate);
  704. updateSortOrder(mLibraryInventoryPanel, mSortByDate);
  705. }
  706. else
  707. {
  708. root_folder->doToSelected(&gInventory, userdata);
  709. }
  710. }
  711. bool LLLandmarksPanel::isActionChecked(const LLSD& userdata) const
  712. {
  713. const std::string command_name = userdata.asString();
  714. if ( "sort_by_date" == command_name)
  715. {
  716. return  mSortByDate;
  717. }
  718. return false;
  719. }
  720. bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const
  721. {
  722. std::string command_name = userdata.asString();
  723. LLPlacesFolderView* rootFolderView = mCurrentSelectedList ?
  724. static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder()) : NULL;
  725. if (NULL == rootFolderView) return false;
  726. // disable some commands for multi-selection. EXT-1757
  727. if (rootFolderView->getSelectedCount() > 1)
  728. {
  729. if (   "teleport" == command_name 
  730. || "more_info" == command_name
  731. || "rename" == command_name
  732. || "show_on_map" == command_name
  733. || "copy_slurl" == command_name
  734. )
  735. {
  736. return false;
  737. }
  738. }
  739. // disable some commands for Favorites accordion. EXT-1758
  740. if (mCurrentSelectedList == mFavoritesInventoryPanel)
  741. {
  742. if (   "expand_all" == command_name
  743. || "collapse_all" == command_name
  744. || "sort_by_date" == command_name
  745. )
  746. return false;
  747. }
  748. LLCheckFolderState checker;
  749. rootFolderView->applyFunctorRecursively(checker);
  750. // We assume that the root folder is always expanded so we enable "collapse_all"
  751. // command when we have at least one more expanded folder.
  752. if (checker.getExpandedFolders() < 2 && "collapse_all" == command_name)
  753. {
  754. return false;
  755. }
  756. if (checker.getCollapsedFolders() < 1 && "expand_all" == command_name)
  757. {
  758. return false;
  759. }
  760. if("category" == command_name)
  761. {
  762. // we can add folder only in Landmarks Accordion
  763. if (mCurrentSelectedList == mLandmarksInventoryPanel)
  764. {
  765. // ... but except Received folder
  766. return !isReceivedFolderSelected();
  767. }
  768. else return false;
  769. }
  770. else if("paste" == command_name || "rename" == command_name || "cut" == command_name || "delete" == command_name)
  771. {
  772. return canSelectedBeModified(command_name);
  773. }
  774. else if("create_pick" == command_name)
  775. {
  776. std::set<LLUUID> selection;
  777. if ( mCurrentSelectedList && mCurrentSelectedList->getRootFolder()->getSelectionList(selection) )
  778. {
  779. return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() );
  780. }
  781. return false;
  782. }
  783. else
  784. {
  785. llwarns << "Unprocessed command has come: " << command_name << llendl;
  786. }
  787. return true;
  788. }
  789. void LLLandmarksPanel::onCustomAction(const LLSD& userdata)
  790. {
  791. LLFolderViewItem* cur_item = getCurSelectedItem();
  792. if(!cur_item)
  793. return;
  794. std::string command_name = userdata.asString();
  795. if("more_info" == command_name)
  796. {
  797. cur_item->getListener()->performAction(mCurrentSelectedList->getRootFolder(),mCurrentSelectedList->getModel(),"about");
  798. }
  799. else if ("teleport" == command_name)
  800. {
  801. onTeleport();
  802. }
  803. else if ("show_on_map" == command_name)
  804. {
  805. onShowOnMap();
  806. }
  807. else if ("create_pick" == command_name)
  808. {
  809. doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1));
  810. }
  811. }
  812. /*
  813. Processes such actions: cut/rename/delete/paste actions
  814. Rules:
  815.  1. We can't perform any action in Library
  816.  2. For Landmarks we can:
  817. - cut/rename/delete in any other accordions
  818. - paste - only in Favorites, Landmarks accordions
  819.  3. For Folders we can: perform any action in Landmarks accordion, except Received folder
  820.  4. We can not paste folders from Clipboard (processed by LLFolderView::canPaste())
  821.  5. Check LLFolderView/Inventory Bridges rules
  822.  */
  823. bool LLLandmarksPanel::canSelectedBeModified(const std::string& command_name) const
  824. {
  825. // validate own rules first
  826. // nothing can be modified in Library
  827. if (mLibraryInventoryPanel == mCurrentSelectedList) return false;
  828. bool can_be_modified = false;
  829. // landmarks can be modified in any other accordion...
  830. if (isLandmarkSelected())
  831. {
  832. can_be_modified = true;
  833. // we can modify landmarks anywhere except paste to My Inventory
  834. if ("paste" == command_name)
  835. {
  836. can_be_modified = (mCurrentSelectedList != mMyInventoryPanel);
  837. }
  838. }
  839. else
  840. {
  841. // ...folders only in the Landmarks accordion...
  842. can_be_modified = mLandmarksInventoryPanel == mCurrentSelectedList;
  843. // ...except "Received" folder
  844. can_be_modified &= !isReceivedFolderSelected();
  845. }
  846. // then ask LLFolderView permissions
  847. if (can_be_modified)
  848. {
  849. LLFolderViewItem* selected = getCurSelectedItem();
  850. if ("cut" == command_name)
  851. {
  852. can_be_modified = mCurrentSelectedList->getRootFolder()->canCut();
  853. }
  854. else if ("rename" == command_name)
  855. {
  856. can_be_modified = selected ? selected->getListener()->isItemRenameable() : false;
  857. }
  858. else if ("delete" == command_name)
  859. {
  860. can_be_modified = selected ? selected->getListener()->isItemRemovable(): false;
  861. }
  862. else if("paste" == command_name)
  863. {
  864. return mCurrentSelectedList->getRootFolder()->canPaste();
  865. }
  866. else
  867. {
  868. llwarns << "Unprocessed command has come: " << command_name << llendl;
  869. }
  870. }
  871. return can_be_modified;
  872. }
  873. void LLLandmarksPanel::onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params)
  874. {
  875. pick_panel->setVisible(FALSE);
  876. owner->removeChild(pick_panel);
  877. //we need remove  observer to  avoid  processParcelInfo in the future.
  878. LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this);
  879. delete pick_panel;
  880. pick_panel = NULL;
  881. }
  882. bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept)
  883. {
  884. *accept = ACCEPT_NO;
  885. switch (cargo_type)
  886. {
  887. case DAD_LANDMARK:
  888. case DAD_CATEGORY:
  889. {
  890. bool is_enabled = isActionEnabled("delete");
  891. if (is_enabled) *accept = ACCEPT_YES_MULTI;
  892. if (is_enabled && drop)
  893. {
  894. onClipboardAction("delete");
  895. }
  896. }
  897. break;
  898. default:
  899. break;
  900. }
  901. return true;
  902. }
  903. void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark)
  904. {
  905. LLVector3d landmark_global_pos;
  906. if (!landmark->getGlobalPos(landmark_global_pos))
  907. return;
  908. LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
  909. if (!landmark_global_pos.isExactlyZero() && worldmap_instance)
  910. {
  911. worldmap_instance->trackLocation(landmark_global_pos);
  912. LLFloaterReg::showInstance("world_map", "center");
  913. }
  914. mShowOnMapBtn->setEnabled(TRUE);
  915. }
  916. void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark,
  917.    LLFolderViewItem* cur_item,
  918.    LLInventoryItem* inv_item,
  919.    const LLParcelData& parcel_data)
  920. {
  921. LLPanelPickEdit* panel_pick = LLPanelPickEdit::create();
  922. LLVector3d landmark_global_pos;
  923. landmark->getGlobalPos(landmark_global_pos);
  924. // let's toggle pick panel into  panel places
  925. LLPanel* panel_places =  LLSideTray::getInstance()->getChild<LLPanel>("panel_places");//-> sidebar_places
  926. panel_places->addChild(panel_pick);
  927. LLRect paren_rect(panel_places->getRect());
  928. panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE);
  929. panel_pick->setRect(paren_rect);
  930. panel_pick->onOpen(LLSD());
  931. LLPickData data;
  932. data.pos_global = landmark_global_pos;
  933. data.name = cur_item->getName();
  934. data.desc = inv_item->getDescription();
  935. data.snapshot_id = parcel_data.snapshot_id;
  936. data.parcel_id = parcel_data.parcel_id;
  937. panel_pick->setPickData(&data);
  938. LLSD params;
  939. params["parcel_id"] = parcel_data.parcel_id;
  940. /* set exit callback to get back onto panel places
  941.  in callback we will make cleaning up( delete pick_panel instance,
  942.  remove landmark panel from observer list
  943. */
  944. panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
  945. panel_pick, panel_places,params));
  946. panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
  947. panel_pick, panel_places,params));
  948. panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
  949. panel_pick, panel_places,params));
  950. }
  951. void LLLandmarksPanel::doCreatePick(LLLandmark* landmark)
  952. {
  953. LLViewerRegion* region = gAgent.getRegion();
  954. if (!region) return;
  955. LLGlobalVec pos_global;
  956. LLUUID region_id;
  957. landmark->getGlobalPos(pos_global);
  958. landmark->getRegionID(region_id);
  959. LLVector3 region_pos((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS),
  960.   (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS),
  961.   (F32)pos_global.mdV[VZ]);
  962. LLSD body;
  963. std::string url = region->getCapability("RemoteParcelRequest");
  964. if (!url.empty())
  965. {
  966. body["location"] = ll_sd_from_vector3(region_pos);
  967. if (!region_id.isNull())
  968. {
  969. body["region_id"] = region_id;
  970. }
  971. if (!pos_global.isExactlyZero())
  972. {
  973. U64 region_handle = to_region_handle(pos_global);
  974. body["region_handle"] = ll_sd_from_U64(region_handle);
  975. }
  976. LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
  977. }
  978. else
  979. {
  980. llwarns << "Can't create pick for landmark for region" << region_id
  981. << ". Region: " << region->getName()
  982. << " does not support RemoteParcelRequest" << llendl;
  983. }
  984. }
  985. //////////////////////////////////////////////////////////////////////////
  986. // HELPER FUNCTIONS
  987. //////////////////////////////////////////////////////////////////////////
  988. static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string)
  989. {
  990. // When search is cleared, restore the old folder state.
  991. if (!inventory_list->getRootFolder()->getFilterSubString().empty() && string == "")
  992. {
  993. inventory_list->setFilterSubString(LLStringUtil::null);
  994. // Re-open folders that were open before
  995. inventory_list->restoreFolderState();
  996. }
  997. // Open the immediate children of the root folder, since those
  998. // are invisible in the UI and thus must always be open.
  999. inventory_list->getRootFolder()->openTopLevelFolders();
  1000. if (inventory_list->getFilterSubString().empty() && string.empty())
  1001. {
  1002. // current filter and new filter empty, do nothing
  1003. return;
  1004. }
  1005. // save current folder open state if no filter currently applied
  1006. if (inventory_list->getRootFolder()->getFilterSubString().empty())
  1007. {
  1008. inventory_list->saveFolderState();
  1009. }
  1010. // Set new filter string
  1011. inventory_list->setFilterSubString(string);
  1012. }
  1013. static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list)
  1014. {
  1015. LLViewerInventoryCategory* category = gInventory.getCategory(inventory_list->getStartFolderID());
  1016. if (category)
  1017. {
  1018. return category->getDescendentCount() > 0;
  1019. }
  1020. return false;
  1021. }
  1022. // EOF