PageRenderTime 28ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/llpanelteleporthistory.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1109 lines | 791 code | 199 blank | 119 comment | 121 complexity | f935aa1879f464755364025e5a632ad4 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llpanelteleporthistory.cpp
  3. * @brief Teleport history represented by a scrolling list
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llfloaterreg.h"
  28. #include "llmenubutton.h"
  29. #include "llfloaterworldmap.h"
  30. #include "llpanelteleporthistory.h"
  31. #include "llworldmap.h"
  32. #include "llteleporthistorystorage.h"
  33. #include "lltextutil.h"
  34. #include "llaccordionctrl.h"
  35. #include "llaccordionctrltab.h"
  36. #include "llflatlistview.h"
  37. #include "llfloatersidepanelcontainer.h"
  38. #include "llnotificationsutil.h"
  39. #include "lltextbox.h"
  40. #include "lltoggleablemenu.h"
  41. #include "llviewermenu.h"
  42. #include "lllandmarkactions.h"
  43. #include "llclipboard.h"
  44. // Maximum number of items that can be added to a list in one pass.
  45. // Used to limit time spent for items list update per frame.
  46. static const U32 ADD_LIMIT = 50;
  47. static const std::string COLLAPSED_BY_USER = "collapsed_by_user";
  48. class LLTeleportHistoryFlatItem : public LLPanel
  49. {
  50. public:
  51. LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string &region_name, const std::string &hl);
  52. virtual ~LLTeleportHistoryFlatItem();
  53. virtual BOOL postBuild();
  54. /*virtual*/ S32 notify(const LLSD& info);
  55. S32 getIndex() { return mIndex; }
  56. void setIndex(S32 index) { mIndex = index; }
  57. const std::string& getRegionName() { return mRegionName;}
  58. void setRegionName(const std::string& name);
  59. void setHighlightedText(const std::string& text);
  60. void updateTitle();
  61. /*virtual*/ void setValue(const LLSD& value);
  62. void onMouseEnter(S32 x, S32 y, MASK mask);
  63. void onMouseLeave(S32 x, S32 y, MASK mask);
  64. virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
  65. static void showPlaceInfoPanel(S32 index);
  66. LLHandle<LLTeleportHistoryFlatItem> getItemHandle() { mItemHandle.bind(this); return mItemHandle; }
  67. private:
  68. void onProfileBtnClick();
  69. LLButton* mProfileBtn;
  70. LLTextBox* mTitle;
  71. LLTeleportHistoryPanel::ContextMenu *mContextMenu;
  72. S32 mIndex;
  73. std::string mRegionName;
  74. std::string mHighlight;
  75. LLRootHandle<LLTeleportHistoryFlatItem> mItemHandle;
  76. };
  77. ////////////////////////////////////////////////////////////////////////////////
  78. ////////////////////////////////////////////////////////////////////////////////
  79. ////////////////////////////////////////////////////////////////////////////////
  80. class LLTeleportHistoryFlatItemStorage: public LLSingleton<LLTeleportHistoryFlatItemStorage> {
  81. protected:
  82. typedef std::vector< LLHandle<LLTeleportHistoryFlatItem> > flat_item_list_t;
  83. public:
  84. LLTeleportHistoryFlatItem* getFlatItemForPersistentItem (
  85. LLTeleportHistoryPanel::ContextMenu *context_menu,
  86. const LLTeleportHistoryPersistentItem& persistent_item,
  87. const S32 cur_item_index,
  88. const std::string &hl);
  89. void removeItem(LLTeleportHistoryFlatItem* item);
  90. void purge();
  91. private:
  92. flat_item_list_t mItems;
  93. };
  94. ////////////////////////////////////////////////////////////////////////////////
  95. ////////////////////////////////////////////////////////////////////////////////
  96. ////////////////////////////////////////////////////////////////////////////////
  97. LLTeleportHistoryFlatItem::LLTeleportHistoryFlatItem(S32 index, LLTeleportHistoryPanel::ContextMenu *context_menu, const std::string &region_name, const std::string &hl)
  98. : LLPanel(),
  99. mIndex(index),
  100. mContextMenu(context_menu),
  101. mRegionName(region_name),
  102. mHighlight(hl)
  103. {
  104. buildFromFile( "panel_teleport_history_item.xml");
  105. }
  106. LLTeleportHistoryFlatItem::~LLTeleportHistoryFlatItem()
  107. {
  108. }
  109. //virtual
  110. BOOL LLTeleportHistoryFlatItem::postBuild()
  111. {
  112. mTitle = getChild<LLTextBox>("region");
  113. mProfileBtn = getChild<LLButton>("profile_btn");
  114. mProfileBtn->setClickedCallback(boost::bind(&LLTeleportHistoryFlatItem::onProfileBtnClick, this));
  115. updateTitle();
  116. return true;
  117. }
  118. S32 LLTeleportHistoryFlatItem::notify(const LLSD& info)
  119. {
  120. if(info.has("detach"))
  121. {
  122. delete mMouseDownSignal;
  123. mMouseDownSignal = NULL;
  124. delete mRightMouseDownSignal;
  125. mRightMouseDownSignal = NULL;
  126. return 1;
  127. }
  128. return 0;
  129. }
  130. void LLTeleportHistoryFlatItem::setValue(const LLSD& value)
  131. {
  132. if (!value.isMap()) return;;
  133. if (!value.has("selected")) return;
  134. getChildView("selected_icon")->setVisible( value["selected"]);
  135. }
  136. void LLTeleportHistoryFlatItem::setHighlightedText(const std::string& text)
  137. {
  138. mHighlight = text;
  139. }
  140. void LLTeleportHistoryFlatItem::setRegionName(const std::string& name)
  141. {
  142. mRegionName = name;
  143. }
  144. void LLTeleportHistoryFlatItem::updateTitle()
  145. {
  146. static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", LLColor4U(255, 255, 255));
  147. LLTextUtil::textboxSetHighlightedVal(
  148. mTitle,
  149. LLStyle::Params().color(sFgColor),
  150. mRegionName,
  151. mHighlight);
  152. }
  153. void LLTeleportHistoryFlatItem::onMouseEnter(S32 x, S32 y, MASK mask)
  154. {
  155. getChildView("hovered_icon")->setVisible( true);
  156. mProfileBtn->setVisible(true);
  157. LLPanel::onMouseEnter(x, y, mask);
  158. }
  159. void LLTeleportHistoryFlatItem::onMouseLeave(S32 x, S32 y, MASK mask)
  160. {
  161. getChildView("hovered_icon")->setVisible( false);
  162. mProfileBtn->setVisible(false);
  163. LLPanel::onMouseLeave(x, y, mask);
  164. }
  165. // virtual
  166. BOOL LLTeleportHistoryFlatItem::handleRightMouseDown(S32 x, S32 y, MASK mask)
  167. {
  168. if (mContextMenu)
  169. mContextMenu->show(this, mIndex, x, y);
  170. return LLPanel::handleRightMouseDown(x, y, mask);
  171. }
  172. void LLTeleportHistoryFlatItem::showPlaceInfoPanel(S32 index)
  173. {
  174. LLSD params;
  175. params["id"] = index;
  176. params["type"] = "teleport_history";
  177. LLFloaterSidePanelContainer::showPanel("places", params);
  178. }
  179. void LLTeleportHistoryFlatItem::onProfileBtnClick()
  180. {
  181. LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex);
  182. }
  183. ////////////////////////////////////////////////////////////////////////////////
  184. ////////////////////////////////////////////////////////////////////////////////
  185. ////////////////////////////////////////////////////////////////////////////////
  186. LLTeleportHistoryFlatItem*
  187. LLTeleportHistoryFlatItemStorage::getFlatItemForPersistentItem (
  188. LLTeleportHistoryPanel::ContextMenu *context_menu,
  189. const LLTeleportHistoryPersistentItem& persistent_item,
  190. const S32 cur_item_index,
  191. const std::string &hl)
  192. {
  193. LLTeleportHistoryFlatItem* item = NULL;
  194. if ( cur_item_index < (S32) mItems.size() )
  195. {
  196. item = mItems[cur_item_index].get();
  197. if (item->getParent() == NULL)
  198. {
  199. item->setIndex(cur_item_index);
  200. item->setRegionName(persistent_item.mTitle);
  201. item->setHighlightedText(hl);
  202. item->setVisible(TRUE);
  203. item->updateTitle();
  204. }
  205. else
  206. {
  207. // Item already added to parent
  208. item = NULL;
  209. }
  210. }
  211. if ( !item )
  212. {
  213. item = new LLTeleportHistoryFlatItem(cur_item_index,
  214. context_menu,
  215. persistent_item.mTitle,
  216. hl);
  217. mItems.push_back(item->getItemHandle());
  218. }
  219. return item;
  220. }
  221. void LLTeleportHistoryFlatItemStorage::removeItem(LLTeleportHistoryFlatItem* item)
  222. {
  223. if (item)
  224. {
  225. flat_item_list_t::iterator item_iter = std::find(mItems.begin(),
  226. mItems.end(),
  227. item->getItemHandle());
  228. if (item_iter != mItems.end())
  229. {
  230. mItems.erase(item_iter);
  231. }
  232. }
  233. }
  234. void LLTeleportHistoryFlatItemStorage::purge()
  235. {
  236. for ( flat_item_list_t::iterator
  237. it = mItems.begin(),
  238. it_end = mItems.end();
  239. it != it_end; ++it )
  240. {
  241. LLHandle <LLTeleportHistoryFlatItem> item_handle = *it;
  242. if ( !item_handle.isDead() && item_handle.get()->getParent() == NULL )
  243. {
  244. item_handle.get()->die();
  245. }
  246. }
  247. mItems.clear();
  248. }
  249. ////////////////////////////////////////////////////////////////////////////////
  250. ////////////////////////////////////////////////////////////////////////////////
  251. ////////////////////////////////////////////////////////////////////////////////
  252. LLTeleportHistoryPanel::ContextMenu::ContextMenu() :
  253. mMenu(NULL), mIndex(0)
  254. {
  255. }
  256. void LLTeleportHistoryPanel::ContextMenu::show(LLView* spawning_view, S32 index, S32 x, S32 y)
  257. {
  258. if (mMenu)
  259. {
  260. //preventing parent (menu holder) from deleting already "dead" context menus on exit
  261. LLView* parent = mMenu->getParent();
  262. if (parent)
  263. {
  264. parent->removeChild(mMenu);
  265. }
  266. delete mMenu;
  267. }
  268. mIndex = index;
  269. mMenu = createMenu();
  270. mMenu->show(x, y);
  271. LLMenuGL::showPopup(spawning_view, mMenu, x, y);
  272. }
  273. LLContextMenu* LLTeleportHistoryPanel::ContextMenu::createMenu()
  274. {
  275. // set up the callbacks for all of the avatar menu items
  276. // (N.B. callbacks don't take const refs as mID is local scope)
  277. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  278. registrar.add("TeleportHistory.Teleport", boost::bind(&LLTeleportHistoryPanel::ContextMenu::onTeleport, this));
  279. registrar.add("TeleportHistory.MoreInformation",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onInfo, this));
  280. registrar.add("TeleportHistory.CopyToClipboard",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard, this));
  281. // create the context menu from the XUI
  282. return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
  283. "menu_teleport_history_item.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
  284. }
  285. void LLTeleportHistoryPanel::ContextMenu::onTeleport()
  286. {
  287. confirmTeleport(mIndex);
  288. }
  289. void LLTeleportHistoryPanel::ContextMenu::onInfo()
  290. {
  291. LLTeleportHistoryFlatItem::showPlaceInfoPanel(mIndex);
  292. }
  293. //static
  294. void LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback(const std::string& slurl)
  295. {
  296. gClipboard.copyFromString(utf8str_to_wstring(slurl));
  297. }
  298. void LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard()
  299. {
  300. LLVector3d globalPos = LLTeleportHistoryStorage::getInstance()->getItems()[mIndex].mGlobalPos;
  301. LLLandmarkActions::getSLURLfromPosGlobal(globalPos,
  302. boost::bind(&LLTeleportHistoryPanel::ContextMenu::gotSLURLCallback, _1));
  303. }
  304. // Not yet implemented; need to remove buildPanel() from constructor when we switch
  305. //static LLRegisterPanelClassWrapper<LLTeleportHistoryPanel> t_teleport_history("panel_teleport_history");
  306. LLTeleportHistoryPanel::LLTeleportHistoryPanel()
  307. : LLPanelPlacesTab(),
  308. mDirty(true),
  309. mCurrentItem(0),
  310. mTeleportHistory(NULL),
  311. mHistoryAccordion(NULL),
  312. mAccordionTabMenu(NULL),
  313. mLastSelectedFlatlList(NULL),
  314. mLastSelectedItemIndex(-1),
  315. mMenuGearButton(NULL)
  316. {
  317. buildFromFile( "panel_teleport_history.xml");
  318. }
  319. LLTeleportHistoryPanel::~LLTeleportHistoryPanel()
  320. {
  321. LLTeleportHistoryFlatItemStorage::instance().purge();
  322. if (mGearMenuHandle.get()) mGearMenuHandle.get()->die();
  323. mTeleportHistoryChangedConnection.disconnect();
  324. }
  325. BOOL LLTeleportHistoryPanel::postBuild()
  326. {
  327. mTeleportHistory = LLTeleportHistoryStorage::getInstance();
  328. if (mTeleportHistory)
  329. {
  330. mTeleportHistoryChangedConnection = mTeleportHistory->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryPanel::onTeleportHistoryChange, this, _1));
  331. }
  332. mHistoryAccordion = getChild<LLAccordionCtrl>("history_accordion");
  333. if (mHistoryAccordion)
  334. {
  335. for (child_list_const_iter_t iter = mHistoryAccordion->beginChild(); iter != mHistoryAccordion->endChild(); iter++)
  336. {
  337. if (dynamic_cast<LLAccordionCtrlTab*>(*iter))
  338. {
  339. LLAccordionCtrlTab* tab = (LLAccordionCtrlTab*)*iter;
  340. tab->setRightMouseDownCallback(boost::bind(&LLTeleportHistoryPanel::onAccordionTabRightClick, this, _1, _2, _3, _4));
  341. tab->setDisplayChildren(false);
  342. tab->setDropDownStateChangedCallback(boost::bind(&LLTeleportHistoryPanel::onAccordionExpand, this, _1, _2));
  343. // All accordion tabs are collapsed initially
  344. setAccordionCollapsedByUser(tab, true);
  345. mItemContainers.put(tab);
  346. LLFlatListView* fl = getFlatListViewFromTab(tab);
  347. if (fl)
  348. {
  349. fl->setCommitOnSelectionChange(true);
  350. fl->setDoubleClickCallback(boost::bind(&LLTeleportHistoryPanel::onDoubleClickItem, this));
  351. fl->setCommitCallback(boost::bind(&LLTeleportHistoryPanel::handleItemSelect, this, fl));
  352. fl->setReturnCallback(boost::bind(&LLTeleportHistoryPanel::onReturnKeyPressed, this));
  353. }
  354. }
  355. }
  356. // Open first 2 accordion tabs
  357. if (mItemContainers.size() > 1)
  358. {
  359. LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 1);
  360. tab->setDisplayChildren(true);
  361. setAccordionCollapsedByUser(tab, false);
  362. }
  363. if (mItemContainers.size() > 2)
  364. {
  365. LLAccordionCtrlTab* tab = mItemContainers.get(mItemContainers.size() - 2);
  366. tab->setDisplayChildren(true);
  367. setAccordionCollapsedByUser(tab, false);
  368. }
  369. }
  370. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  371. registrar.add("TeleportHistory.ExpandAllFolders", boost::bind(&LLTeleportHistoryPanel::onExpandAllFolders, this));
  372. registrar.add("TeleportHistory.CollapseAllFolders", boost::bind(&LLTeleportHistoryPanel::onCollapseAllFolders, this));
  373. registrar.add("TeleportHistory.ClearTeleportHistory", boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistory, this));
  374. mEnableCallbackRegistrar.add("TeleportHistory.GearMenu.Enable", boost::bind(&LLTeleportHistoryPanel::isActionEnabled, this, _2));
  375. mMenuGearButton = getChild<LLMenuButton>("gear_btn");
  376. LLToggleableMenu* gear_menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_teleport_history_gear.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());;
  377. if(gear_menu)
  378. {
  379. mGearMenuHandle = gear_menu->getHandle();
  380. mMenuGearButton->setMenu(gear_menu);
  381. }
  382. return TRUE;
  383. }
  384. // virtual
  385. void LLTeleportHistoryPanel::draw()
  386. {
  387. if (mDirty)
  388. refresh();
  389. LLPanelPlacesTab::draw();
  390. }
  391. // virtual
  392. void LLTeleportHistoryPanel::onSearchEdit(const std::string& string)
  393. {
  394. sFilterSubString = string;
  395. showTeleportHistory();
  396. }
  397. // virtual
  398. bool LLTeleportHistoryPanel::isSingleItemSelected()
  399. {
  400. return mLastSelectedFlatlList && mLastSelectedFlatlList->getSelectedItem();
  401. }
  402. // virtual
  403. void LLTeleportHistoryPanel::onShowOnMap()
  404. {
  405. if (!mLastSelectedFlatlList)
  406. return;
  407. LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
  408. if(!itemp)
  409. return;
  410. LLVector3d global_pos = mTeleportHistory->getItems()[itemp->getIndex()].mGlobalPos;
  411. if (!global_pos.isExactlyZero())
  412. {
  413. LLFloaterWorldMap::getInstance()->trackLocation(global_pos);
  414. LLFloaterReg::showInstance("world_map", "center");
  415. }
  416. }
  417. //virtual
  418. void LLTeleportHistoryPanel::onShowProfile()
  419. {
  420. if (!mLastSelectedFlatlList)
  421. return;
  422. LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
  423. if(!itemp)
  424. return;
  425. LLTeleportHistoryFlatItem::showPlaceInfoPanel(itemp->getIndex());
  426. }
  427. // virtual
  428. void LLTeleportHistoryPanel::onTeleport()
  429. {
  430. if (!mLastSelectedFlatlList)
  431. return;
  432. LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
  433. if(!itemp)
  434. return;
  435. // teleport to existing item in history, so we don't add it again
  436. confirmTeleport(itemp->getIndex());
  437. }
  438. /*
  439. // virtual
  440. void LLTeleportHistoryPanel::onCopySLURL()
  441. {
  442. LLScrollListItem* itemp = mHistoryItems->getFirstSelected();
  443. if(!itemp)
  444. return;
  445. S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger();
  446. const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems();
  447. LLVector3d global_pos = hist_items[index].mGlobalPos;
  448. U64 new_region_handle = to_region_handle(global_pos);
  449. LLWorldMapMessage::url_callback_t cb = boost::bind(
  450. &LLPanelPlacesTab::onRegionResponse, this,
  451. global_pos, _1, _2, _3, _4);
  452. LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, cb, std::string("unused"), false);
  453. }
  454. */
  455. // virtual
  456. void LLTeleportHistoryPanel::updateVerbs()
  457. {
  458. if (!isTabVisible())
  459. return;
  460. if (!mLastSelectedFlatlList)
  461. {
  462. mTeleportBtn->setEnabled(false);
  463. mShowProfile->setEnabled(false);
  464. mShowOnMapBtn->setEnabled(false);
  465. return;
  466. }
  467. LLTeleportHistoryFlatItem* itemp = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
  468. mTeleportBtn->setEnabled(NULL != itemp);
  469. mShowProfile->setEnabled(NULL != itemp);
  470. mShowOnMapBtn->setEnabled(NULL != itemp);
  471. }
  472. void LLTeleportHistoryPanel::getNextTab(const LLDate& item_date, S32& tab_idx, LLDate& tab_date)
  473. {
  474. const U32 seconds_in_day = 24 * 60 * 60;
  475. S32 tabs_cnt = mItemContainers.size();
  476. S32 curr_year = 0, curr_month = 0, curr_day = 0;
  477. tab_date = LLDate::now();
  478. tab_date.split(&curr_year, &curr_month, &curr_day);
  479. tab_date.fromYMDHMS(curr_year, curr_month, curr_day); // Set hour, min, and sec to 0
  480. tab_date.secondsSinceEpoch(tab_date.secondsSinceEpoch() + seconds_in_day);
  481. tab_idx = -1;
  482. while (tab_idx < tabs_cnt - 1 && item_date < tab_date)
  483. {
  484. tab_idx++;
  485. if (tab_idx <= tabs_cnt - 4)
  486. {
  487. // All tabs, except last three, are tabs for one day, so just push tab_date back by one day
  488. tab_date.secondsSinceEpoch(tab_date.secondsSinceEpoch() - seconds_in_day);
  489. }
  490. else if (tab_idx == tabs_cnt - 3) // 6 day and older, low boundary is 1 month
  491. {
  492. tab_date = LLDate::now();
  493. tab_date.split(&curr_year, &curr_month, &curr_day);
  494. curr_month--;
  495. if (0 == curr_month)
  496. {
  497. curr_month = 12;
  498. curr_year--;
  499. }
  500. tab_date.fromYMDHMS(curr_year, curr_month, curr_day);
  501. }
  502. else if (tab_idx == tabs_cnt - 2) // 1 month and older, low boundary is 6 months
  503. {
  504. tab_date = LLDate::now();
  505. tab_date.split(&curr_year, &curr_month, &curr_day);
  506. if (curr_month > 6)
  507. {
  508. curr_month -= 6;
  509. }
  510. else
  511. {
  512. curr_month += 6;
  513. curr_year--;
  514. }
  515. tab_date.fromYMDHMS(curr_year, curr_month, curr_day);
  516. }
  517. else // 6 months and older
  518. {
  519. tab_date.secondsSinceEpoch(0);
  520. }
  521. }
  522. }
  523. // Called to add items, no more, than ADD_LIMIT at time
  524. void LLTeleportHistoryPanel::refresh()
  525. {
  526. if (!mHistoryAccordion)
  527. {
  528. mDirty = false;
  529. return;
  530. }
  531. const LLTeleportHistoryStorage::slurl_list_t& items = mTeleportHistory->getItems();
  532. // Setting tab_boundary_date to "now", so date from any item would be earlier, than boundary.
  533. // That leads to call to getNextTab to get right tab_idx in first pass
  534. LLDate tab_boundary_date = LLDate::now();
  535. LLFlatListView* curr_flat_view = NULL;
  536. std::string filter_string = sFilterSubString;
  537. LLStringUtil::toUpper(filter_string);
  538. U32 added_items = 0;
  539. while (mCurrentItem >= 0)
  540. {
  541. // Filtering
  542. if (!filter_string.empty())
  543. {
  544. std::string landmark_title(items[mCurrentItem].mTitle);
  545. LLStringUtil::toUpper(landmark_title);
  546. if( std::string::npos == landmark_title.find(filter_string) )
  547. {
  548. mCurrentItem--;
  549. continue;
  550. }
  551. }
  552. // Checking whether date of item is earlier, than tab_boundary_date.
  553. // In that case, item should be added to another tab
  554. const LLDate &date = items[mCurrentItem].mDate;
  555. if (date < tab_boundary_date)
  556. {
  557. // Getting apropriate tab_idx for this and subsequent items,
  558. // tab_boundary_date would be earliest possible date for this tab
  559. S32 tab_idx = 0;
  560. getNextTab(date, tab_idx, tab_boundary_date);
  561. tab_idx = mItemContainers.size() - 1 - tab_idx;
  562. if (tab_idx >= 0)
  563. {
  564. LLAccordionCtrlTab* tab = mItemContainers.get(tab_idx);
  565. tab->setVisible(true);
  566. // Expand all accordion tabs when filtering
  567. if(!sFilterSubString.empty())
  568. {
  569. //store accordion tab state when filter is not empty
  570. tab->notifyChildren(LLSD().with("action","store_state"));
  571. tab->setDisplayChildren(true);
  572. }
  573. // Restore each tab's expand state when not filtering
  574. else
  575. {
  576. bool collapsed = isAccordionCollapsedByUser(tab);
  577. tab->setDisplayChildren(!collapsed);
  578. //restore accordion state after all those accodrion tabmanipulations
  579. tab->notifyChildren(LLSD().with("action","restore_state"));
  580. }
  581. curr_flat_view = getFlatListViewFromTab(tab);
  582. }
  583. }
  584. if (curr_flat_view)
  585. {
  586. LLTeleportHistoryFlatItem* item =
  587. LLTeleportHistoryFlatItemStorage::instance()
  588. .getFlatItemForPersistentItem(&mContextMenu,
  589. items[mCurrentItem],
  590. mCurrentItem,
  591. filter_string);
  592. if ( !curr_flat_view->addItem(item, LLUUID::null, ADD_BOTTOM, false) )
  593. llerrs << "Couldn't add flat item to teleport history." << llendl;
  594. if (mLastSelectedItemIndex == mCurrentItem)
  595. curr_flat_view->selectItem(item, true);
  596. }
  597. mCurrentItem--;
  598. if (++added_items >= ADD_LIMIT)
  599. break;
  600. }
  601. for (S32 n = mItemContainers.size() - 1; n >= 0; --n)
  602. {
  603. LLAccordionCtrlTab* tab = mItemContainers.get(n);
  604. LLFlatListView* fv = getFlatListViewFromTab(tab);
  605. if (fv)
  606. {
  607. fv->notify(LLSD().with("rearrange", LLSD()));
  608. }
  609. }
  610. mHistoryAccordion->setFilterSubString(sFilterSubString);
  611. mHistoryAccordion->arrange();
  612. updateVerbs();
  613. if (mCurrentItem < 0)
  614. mDirty = false;
  615. }
  616. void LLTeleportHistoryPanel::onTeleportHistoryChange(S32 removed_index)
  617. {
  618. mLastSelectedItemIndex = -1;
  619. if (-1 == removed_index)
  620. showTeleportHistory(); // recreate all items
  621. else
  622. {
  623. replaceItem(removed_index); // replace removed item by most recent
  624. updateVerbs();
  625. }
  626. }
  627. void LLTeleportHistoryPanel::replaceItem(S32 removed_index)
  628. {
  629. // Flat list for 'Today' (mItemContainers keeps accordion tabs in reverse order)
  630. LLFlatListView* fv = NULL;
  631. if (mItemContainers.size() > 0)
  632. {
  633. fv = getFlatListViewFromTab(mItemContainers[mItemContainers.size() - 1]);
  634. }
  635. // Empty flat list for 'Today' means that other flat lists are empty as well,
  636. // so all items from teleport history should be added.
  637. if (!fv || fv->size() == 0)
  638. {
  639. showTeleportHistory();
  640. return;
  641. }
  642. const LLTeleportHistoryStorage::slurl_list_t& history_items = mTeleportHistory->getItems();
  643. LLTeleportHistoryFlatItem* item = LLTeleportHistoryFlatItemStorage::instance()
  644. .getFlatItemForPersistentItem(&mContextMenu,
  645. history_items[history_items.size() - 1], // Most recent item, it was added instead of removed
  646. history_items.size(), // index will be decremented inside loop below
  647. sFilterSubString);
  648. fv->addItem(item, LLUUID::null, ADD_TOP);
  649. // Index of each item, from last to removed item should be decremented
  650. // to point to the right item in LLTeleportHistoryStorage
  651. for (S32 tab_idx = mItemContainers.size() - 1; tab_idx >= 0; --tab_idx)
  652. {
  653. LLAccordionCtrlTab* tab = mItemContainers.get(tab_idx);
  654. if (!tab->getVisible())
  655. continue;
  656. fv = getFlatListViewFromTab(tab);
  657. if (!fv)
  658. {
  659. showTeleportHistory();
  660. return;
  661. }
  662. std::vector<LLPanel*> items;
  663. fv->getItems(items);
  664. S32 items_cnt = items.size();
  665. for (S32 n = 0; n < items_cnt; ++n)
  666. {
  667. LLTeleportHistoryFlatItem *item = (LLTeleportHistoryFlatItem*) items[n];
  668. if (item->getIndex() == removed_index)
  669. {
  670. LLTeleportHistoryFlatItemStorage::instance().removeItem(item);
  671. fv->removeItem(item);
  672. // If flat list becames empty, then accordion tab should be hidden
  673. if (fv->size() == 0)
  674. tab->setVisible(false);
  675. mHistoryAccordion->arrange();
  676. return; // No need to decrement idexes for the rest of items
  677. }
  678. item->setIndex(item->getIndex() - 1);
  679. }
  680. }
  681. }
  682. void LLTeleportHistoryPanel::showTeleportHistory()
  683. {
  684. mDirty = true;
  685. // Starting to add items from last one, in reverse order,
  686. // since TeleportHistory keeps most recent item at the end
  687. if (!mTeleportHistory)
  688. {
  689. mTeleportHistory = LLTeleportHistoryStorage::getInstance();
  690. }
  691. mCurrentItem = mTeleportHistory->getItems().size() - 1;
  692. for (S32 n = mItemContainers.size() - 1; n >= 0; --n)
  693. {
  694. LLAccordionCtrlTab* tab = mItemContainers.get(n);
  695. if (tab)
  696. {
  697. tab->setVisible(false);
  698. LLFlatListView* fv = getFlatListViewFromTab(tab);
  699. if (fv)
  700. {
  701. // Detached panels are managed by LLTeleportHistoryFlatItemStorage
  702. std::vector<LLPanel*> detached_items;
  703. fv->detachItems(detached_items);
  704. }
  705. }
  706. }
  707. }
  708. void LLTeleportHistoryPanel::handleItemSelect(LLFlatListView* selected)
  709. {
  710. mLastSelectedFlatlList = selected;
  711. LLTeleportHistoryFlatItem* item = dynamic_cast<LLTeleportHistoryFlatItem *> (mLastSelectedFlatlList->getSelectedItem());
  712. if (item)
  713. mLastSelectedItemIndex = item->getIndex();
  714. S32 tabs_cnt = mItemContainers.size();
  715. for (S32 n = 0; n < tabs_cnt; n++)
  716. {
  717. LLAccordionCtrlTab* tab = mItemContainers.get(n);
  718. if (!tab->getVisible())
  719. continue;
  720. LLFlatListView *flv = getFlatListViewFromTab(tab);
  721. if (!flv)
  722. continue;
  723. if (flv == selected)
  724. continue;
  725. flv->resetSelection(true);
  726. }
  727. updateVerbs();
  728. }
  729. void LLTeleportHistoryPanel::onReturnKeyPressed()
  730. {
  731. // Teleport to selected region as default action on return key pressed
  732. onTeleport();
  733. }
  734. void LLTeleportHistoryPanel::onDoubleClickItem()
  735. {
  736. // If item got doubleclick, then that item is already selected
  737. onTeleport();
  738. }
  739. void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y, MASK mask)
  740. {
  741. LLAccordionCtrlTab *tab = (LLAccordionCtrlTab *) view;
  742. // If click occurred below the header, don't show this menu
  743. if (y < tab->getRect().getHeight() - tab->getHeaderHeight() - tab->getPaddingBottom())
  744. return;
  745. if (mAccordionTabMenu)
  746. {
  747. //preventing parent (menu holder) from deleting already "dead" context menus on exit
  748. LLView* parent = mAccordionTabMenu->getParent();
  749. if (parent)
  750. {
  751. parent->removeChild(mAccordionTabMenu);
  752. }
  753. delete mAccordionTabMenu;
  754. }
  755. // set up the callbacks for all of the avatar menu items
  756. // (N.B. callbacks don't take const refs as mID is local scope)
  757. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  758. registrar.add("TeleportHistory.TabOpen", boost::bind(&LLTeleportHistoryPanel::onAccordionTabOpen, this, tab));
  759. registrar.add("TeleportHistory.TabClose", boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab));
  760. // create the context menu from the XUI
  761. mAccordionTabMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
  762. "menu_teleport_history_tab.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
  763. mAccordionTabMenu->setItemVisible("TabOpen", !tab->isExpanded() ? true : false);
  764. mAccordionTabMenu->setItemVisible("TabClose", tab->isExpanded() ? true : false);
  765. mAccordionTabMenu->show(x, y);
  766. LLMenuGL::showPopup(tab, mAccordionTabMenu, x, y);
  767. }
  768. void LLTeleportHistoryPanel::onAccordionTabOpen(LLAccordionCtrlTab *tab)
  769. {
  770. tab->setDisplayChildren(true);
  771. mHistoryAccordion->arrange();
  772. }
  773. void LLTeleportHistoryPanel::onAccordionTabClose(LLAccordionCtrlTab *tab)
  774. {
  775. tab->setDisplayChildren(false);
  776. mHistoryAccordion->arrange();
  777. }
  778. void LLTeleportHistoryPanel::onExpandAllFolders()
  779. {
  780. S32 tabs_cnt = mItemContainers.size();
  781. for (S32 n = 0; n < tabs_cnt; n++)
  782. {
  783. mItemContainers.get(n)->setDisplayChildren(true);
  784. }
  785. mHistoryAccordion->arrange();
  786. }
  787. void LLTeleportHistoryPanel::onCollapseAllFolders()
  788. {
  789. S32 tabs_cnt = mItemContainers.size();
  790. for (S32 n = 0; n < tabs_cnt; n++)
  791. {
  792. mItemContainers.get(n)->setDisplayChildren(false);
  793. }
  794. mHistoryAccordion->arrange();
  795. }
  796. void LLTeleportHistoryPanel::onClearTeleportHistory()
  797. {
  798. LLNotificationsUtil::add("ConfirmClearTeleportHistory", LLSD(), LLSD(), boost::bind(&LLTeleportHistoryPanel::onClearTeleportHistoryDialog, this, _1, _2));
  799. }
  800. bool LLTeleportHistoryPanel::onClearTeleportHistoryDialog(const LLSD& notification, const LLSD& response)
  801. {
  802. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  803. if (0 == option)
  804. {
  805. // order does matter, call this first or teleport history will contain one record(current location)
  806. LLTeleportHistory::getInstance()->purgeItems();
  807. LLTeleportHistoryStorage *th = LLTeleportHistoryStorage::getInstance();
  808. th->purgeItems();
  809. th->save();
  810. }
  811. return false;
  812. }
  813. LLFlatListView* LLTeleportHistoryPanel::getFlatListViewFromTab(LLAccordionCtrlTab *tab)
  814. {
  815. for (child_list_const_iter_t iter = tab->beginChild(); iter != tab->endChild(); iter++)
  816. {
  817. if (dynamic_cast<LLFlatListView*>(*iter))
  818. {
  819. return (LLFlatListView*)*iter; // There should be one scroll list per tab.
  820. }
  821. }
  822. return NULL;
  823. }
  824. bool LLTeleportHistoryPanel::isActionEnabled(const LLSD& userdata) const
  825. {
  826. S32 tabs_cnt = mItemContainers.size();
  827. bool has_expanded_tabs = false;
  828. bool has_collapsed_tabs = false;
  829. for (S32 n = 0; n < tabs_cnt; n++)
  830. {
  831. LLAccordionCtrlTab* tab = mItemContainers.get(n);
  832. if (!tab->getVisible())
  833. continue;
  834. if (tab->getDisplayChildren())
  835. {
  836. has_expanded_tabs = true;
  837. }
  838. else
  839. {
  840. has_collapsed_tabs = true;
  841. }
  842. if (has_expanded_tabs && has_collapsed_tabs)
  843. {
  844. break;
  845. }
  846. }
  847. std::string command_name = userdata.asString();
  848. if (has_expanded_tabs && command_name == "collapse_all")
  849. {
  850. return true;
  851. }
  852. if (has_collapsed_tabs && command_name == "expand_all")
  853. {
  854. return true;
  855. }
  856. return false;
  857. }
  858. void LLTeleportHistoryPanel::setAccordionCollapsedByUser(LLUICtrl* acc_tab, bool collapsed)
  859. {
  860. LLSD param = acc_tab->getValue();
  861. param[COLLAPSED_BY_USER] = collapsed;
  862. acc_tab->setValue(param);
  863. }
  864. bool LLTeleportHistoryPanel::isAccordionCollapsedByUser(LLUICtrl* acc_tab)
  865. {
  866. LLSD param = acc_tab->getValue();
  867. if(!param.has(COLLAPSED_BY_USER))
  868. {
  869. return false;
  870. }
  871. return param[COLLAPSED_BY_USER].asBoolean();
  872. }
  873. void LLTeleportHistoryPanel::onAccordionExpand(LLUICtrl* ctrl, const LLSD& param)
  874. {
  875. bool expanded = param.asBoolean();
  876. // Save accordion tab state to restore it in refresh()
  877. setAccordionCollapsedByUser(ctrl, !expanded);
  878. // Reset selection upon accordion being collapsed
  879. // to disable "Teleport" and "Map" buttons for hidden item.
  880. if (!expanded && mLastSelectedFlatlList)
  881. {
  882. mLastSelectedFlatlList->resetSelection();
  883. }
  884. }
  885. // static
  886. void LLTeleportHistoryPanel::confirmTeleport(S32 hist_idx)
  887. {
  888. LLSD args;
  889. args["HISTORY_ENTRY"] = LLTeleportHistoryStorage::getInstance()->getItems()[hist_idx].mTitle;
  890. LLNotificationsUtil::add("TeleportToHistoryEntry", args, LLSD(),
  891. boost::bind(&LLTeleportHistoryPanel::onTeleportConfirmation, _1, _2, hist_idx));
  892. }
  893. // Called when user reacts upon teleport confirmation dialog.
  894. // static
  895. bool LLTeleportHistoryPanel::onTeleportConfirmation(const LLSD& notification, const LLSD& response, S32 hist_idx)
  896. {
  897. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  898. if (0 == option)
  899. {
  900. // Teleport to given history item.
  901. LLTeleportHistoryStorage::getInstance()->goToItem(hist_idx);
  902. }
  903. return false;
  904. }