PageRenderTime 447ms CodeModel.GetById 51ms app.highlight 344ms RepoModel.GetById 18ms app.codeStats 1ms

/indra/newview/llpanellandmarks.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1505 lines | 1116 code | 224 blank | 165 comment | 295 complexity | 85f00590ad37b0ae85b0aebe2b630c78 MD5 | raw file
   1/**
   2 * @file llpanellandmarks.cpp
   3 * @brief Landmarks tab for Side Bar "Places" panel
   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
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llpanellandmarks.h"
  30
  31#include "llbutton.h"
  32#include "llfloaterreg.h"
  33#include "llnotificationsutil.h"
  34#include "llsdutil.h"
  35#include "llsdutil_math.h"
  36#include "llregionhandle.h"
  37
  38#include "llaccordionctrl.h"
  39#include "llaccordionctrltab.h"
  40#include "llagent.h"
  41#include "llagentpicksinfo.h"
  42#include "llagentui.h"
  43#include "llcallbacklist.h"
  44#include "lldndbutton.h"
  45#include "llfloatersidepanelcontainer.h"
  46#include "llfloaterworldmap.h"
  47#include "llfolderviewitem.h"
  48#include "llinventorymodelbackgroundfetch.h"
  49#include "llinventorypanel.h"
  50#include "llinventoryfunctions.h"
  51#include "lllandmarkactions.h"
  52#include "llmenubutton.h"
  53#include "llplacesinventorybridge.h"
  54#include "llplacesinventorypanel.h"
  55#include "lltoggleablemenu.h"
  56#include "llviewermenu.h"
  57#include "llviewerregion.h"
  58
  59// Not yet implemented; need to remove buildPanel() from constructor when we switch
  60//static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");
  61
  62static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn";
  63static const std::string ADD_BUTTON_NAME = "add_btn";
  64static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";
  65static const std::string TRASH_BUTTON_NAME = "trash_btn";
  66
  67
  68// helper functions
  69static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string);
  70static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list);
  71static void collapse_all_folders(LLFolderView* root_folder);
  72static void expand_all_folders(LLFolderView* root_folder);
  73static bool has_expanded_folders(LLFolderView* root_folder);
  74static bool has_collapsed_folders(LLFolderView* root_folder);
  75static void toggle_restore_menu(LLMenuGL* menu, BOOL visible, BOOL enabled);
  76
  77/**
  78 * Functor counting expanded and collapsed folders in folder view tree to know
  79 * when to enable or disable "Expand all folders" and "Collapse all folders" commands.
  80 */
  81class LLCheckFolderState : public LLFolderViewFunctor
  82{
  83public:
  84	LLCheckFolderState()
  85	:	mCollapsedFolders(0),
  86		mExpandedFolders(0)
  87	{}
  88	virtual ~LLCheckFolderState() {}
  89	virtual void doFolder(LLFolderViewFolder* folder);
  90	virtual void doItem(LLFolderViewItem* item) {}
  91	S32 getCollapsedFolders() { return mCollapsedFolders; }
  92	S32 getExpandedFolders() { return mExpandedFolders; }
  93
  94private:
  95	S32 mCollapsedFolders;
  96	S32 mExpandedFolders;
  97};
  98
  99// virtual
 100void LLCheckFolderState::doFolder(LLFolderViewFolder* folder)
 101{
 102	// Counting only folders that pass the filter.
 103	// The listener check allow us to avoid counting the folder view
 104	// object itself because it has no listener assigned.
 105	if (folder->hasFilteredDescendants() && folder->getListener())
 106	{
 107		if (folder->isOpen())
 108		{
 109			++mExpandedFolders;
 110		}
 111		else
 112		{
 113			++mCollapsedFolders;
 114		}
 115	}
 116}
 117
 118// Functor searching and opening a folder specified by UUID
 119// in a folder view tree.
 120class LLOpenFolderByID : public LLFolderViewFunctor
 121{
 122public:
 123	LLOpenFolderByID(const LLUUID& folder_id)
 124	:	mFolderID(folder_id)
 125	,	mIsFolderOpen(false)
 126	{}
 127	virtual ~LLOpenFolderByID() {}
 128	/*virtual*/ void doFolder(LLFolderViewFolder* folder);
 129	/*virtual*/ void doItem(LLFolderViewItem* item) {}
 130
 131	bool isFolderOpen() { return mIsFolderOpen; }
 132
 133private:
 134	bool	mIsFolderOpen;
 135	LLUUID	mFolderID;
 136};
 137
 138// virtual
 139void LLOpenFolderByID::doFolder(LLFolderViewFolder* folder)
 140{
 141	if (folder->getListener() && folder->getListener()->getUUID() == mFolderID)
 142	{
 143		if (!folder->isOpen())
 144		{
 145			folder->setOpen(TRUE);
 146			mIsFolderOpen = true;
 147		}
 148	}
 149}
 150
 151/**
 152 * Bridge to support knowing when the inventory has changed to update Landmarks tab
 153 * ShowFolderState filter setting to show all folders when the filter string is empty and
 154 * empty folder message when Landmarks inventory category has no children.
 155 * Ensures that "Landmarks" folder in the Library is open on strart up.
 156 */
 157class LLLandmarksPanelObserver : public LLInventoryObserver
 158{
 159public:
 160	LLLandmarksPanelObserver(LLLandmarksPanel* lp)
 161	:	mLP(lp),
 162	 	mIsLibraryLandmarksOpen(false)
 163	{}
 164	virtual ~LLLandmarksPanelObserver() {}
 165	/*virtual*/ void changed(U32 mask);
 166
 167private:
 168	LLLandmarksPanel* mLP;
 169	bool mIsLibraryLandmarksOpen;
 170};
 171
 172void LLLandmarksPanelObserver::changed(U32 mask)
 173{
 174	mLP->updateShowFolderState();
 175
 176	LLPlacesInventoryPanel* library = mLP->getLibraryInventoryPanel();
 177	if (!mIsLibraryLandmarksOpen && library)
 178	{
 179		// Search for "Landmarks" folder in the Library and open it once on start up. See EXT-4827.
 180		const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);
 181		if (landmarks_cat.notNull())
 182		{
 183			LLOpenFolderByID opener(landmarks_cat);
 184			library->getRootFolder()->applyFunctorRecursively(opener);
 185			mIsLibraryLandmarksOpen = opener.isFolderOpen();
 186		}
 187	}
 188}
 189
 190LLLandmarksPanel::LLLandmarksPanel()
 191	:	LLPanelPlacesTab()
 192	,	mFavoritesInventoryPanel(NULL)
 193	,	mLandmarksInventoryPanel(NULL)
 194	,	mMyInventoryPanel(NULL)
 195	,	mLibraryInventoryPanel(NULL)
 196	,	mCurrentSelectedList(NULL)
 197	,	mListCommands(NULL)
 198	,	mGearButton(NULL)
 199	,	mGearFolderMenu(NULL)
 200	,	mGearLandmarkMenu(NULL)
 201{
 202	mInventoryObserver = new LLLandmarksPanelObserver(this);
 203	gInventory.addObserver(mInventoryObserver);
 204
 205	buildFromFile( "panel_landmarks.xml");
 206}
 207
 208LLLandmarksPanel::~LLLandmarksPanel()
 209{
 210	if (gInventory.containsObserver(mInventoryObserver))
 211	{
 212		gInventory.removeObserver(mInventoryObserver);
 213	}
 214}
 215
 216BOOL LLLandmarksPanel::postBuild()
 217{
 218	if (!gInventory.isInventoryUsable())
 219		return FALSE;
 220
 221	// mast be called before any other initXXX methods to init Gear menu
 222	initListCommandsHandlers();
 223
 224	initFavoritesInventoryPanel();
 225	initLandmarksInventoryPanel();
 226	initMyInventoryPanel();
 227	initLibraryInventoryPanel();
 228
 229	return TRUE;
 230}
 231
 232// virtual
 233void LLLandmarksPanel::onSearchEdit(const std::string& string)
 234{
 235	// give FolderView a chance to be refreshed. So, made all accordions visible
 236	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
 237	{
 238		LLAccordionCtrlTab* tab = *iter;
 239		tab->setVisible(TRUE);
 240
 241		// expand accordion to see matched items in each one. See EXT-2014.
 242		if (string != "")
 243		{
 244			tab->changeOpenClose(false);
 245		}
 246
 247		LLPlacesInventoryPanel* inventory_list = dynamic_cast<LLPlacesInventoryPanel*>(tab->getAccordionView());
 248		if (NULL == inventory_list) continue;
 249
 250		if (inventory_list->getFilter())
 251		{
 252			filter_list(inventory_list, string);
 253		}
 254	}
 255
 256	if (sFilterSubString != string)
 257		sFilterSubString = string;
 258
 259	// show all folders in Landmarks Accordion for empty filter
 260	// only if Landmarks inventory folder is not empty
 261	updateShowFolderState();
 262}
 263
 264// virtual
 265void LLLandmarksPanel::onShowOnMap()
 266{
 267	if (NULL == mCurrentSelectedList)
 268	{
 269		llwarns << "There are no selected list. No actions are performed." << llendl;
 270		return;
 271	}
 272
 273	// Disable the "Map" button because loading landmark can take some time.
 274	// During this time the button is useless. It will be enabled on callback finish
 275	// or upon switching to other item.
 276	mShowOnMapBtn->setEnabled(FALSE);
 277
 278	doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doShowOnMap, this, _1));
 279}
 280
 281//virtual
 282void LLLandmarksPanel::onShowProfile()
 283{
 284	LLFolderViewItem* cur_item = getCurSelectedItem();
 285
 286	if(!cur_item)
 287		return;
 288
 289	cur_item->getListener()->performAction(mCurrentSelectedList->getModel(),"about");
 290}
 291
 292// virtual
 293void LLLandmarksPanel::onTeleport()
 294{
 295	LLFolderViewItem* current_item = getCurSelectedItem();
 296	if (!current_item)
 297	{
 298		llwarns << "There are no selected list. No actions are performed." << llendl;
 299		return;
 300	}
 301
 302	LLFolderViewEventListener* listenerp = current_item->getListener();
 303	if (listenerp && listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
 304	{
 305		listenerp->openItem();
 306	}
 307}
 308
 309// virtual
 310bool LLLandmarksPanel::isSingleItemSelected()
 311{
 312	bool result = false;
 313
 314	if (mCurrentSelectedList != NULL)
 315	{
 316		LLPlacesFolderView* root_view =
 317				static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder());
 318
 319		if (root_view->getSelectedCount() == 1)
 320		{
 321			result = isLandmarkSelected();
 322		}
 323	}
 324
 325	return result;
 326}
 327
 328// virtual
 329void LLLandmarksPanel::updateVerbs()
 330{
 331	if (!isTabVisible()) 
 332		return;
 333
 334	bool landmark_selected = isLandmarkSelected();
 335	mTeleportBtn->setEnabled(landmark_selected && isActionEnabled("teleport"));
 336	mShowProfile->setEnabled(landmark_selected && isActionEnabled("more_info"));
 337	mShowOnMapBtn->setEnabled(landmark_selected && isActionEnabled("show_on_map"));
 338
 339	// TODO: mantipov: Uncomment when mShareBtn is supported
 340	// Share button should be enabled when neither a folder nor a landmark is selected
 341	//mShareBtn->setEnabled(NULL != current_item);
 342
 343	updateListCommands();
 344}
 345
 346void LLLandmarksPanel::onSelectionChange(LLPlacesInventoryPanel* inventory_list, const std::deque<LLFolderViewItem*> &items, BOOL user_action)
 347{
 348	if (user_action && (items.size() > 0))
 349	{
 350		deselectOtherThan(inventory_list);
 351		mCurrentSelectedList = inventory_list;
 352	}
 353	updateVerbs();
 354}
 355
 356void LLLandmarksPanel::onSelectorButtonClicked()
 357{
 358	// TODO: mantipov: update getting of selected item
 359	// TODO: bind to "i" button
 360	LLFolderViewItem* cur_item = mFavoritesInventoryPanel->getRootFolder()->getCurSelectedItem();
 361	if (!cur_item) return;
 362
 363	LLFolderViewEventListener* listenerp = cur_item->getListener();
 364	if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
 365	{
 366		LLSD key;
 367		key["type"] = "landmark";
 368		key["id"] = listenerp->getUUID();
 369
 370		LLFloaterSidePanelContainer::showPanel("places", key);
 371	}
 372}
 373
 374void LLLandmarksPanel::updateShowFolderState()
 375{
 376	if (!mLandmarksInventoryPanel->getFilter())
 377		return;
 378
 379	bool show_all_folders = mLandmarksInventoryPanel->getRootFolder()->getFilterSubString().empty();
 380	if (show_all_folders)
 381	{
 382		show_all_folders = category_has_descendents(mLandmarksInventoryPanel);
 383	}
 384
 385	mLandmarksInventoryPanel->setShowFolderState(show_all_folders ?
 386		LLInventoryFilter::SHOW_ALL_FOLDERS :
 387		LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS
 388		);
 389}
 390
 391void LLLandmarksPanel::setItemSelected(const LLUUID& obj_id, BOOL take_keyboard_focus)
 392{
 393	if (selectItemInAccordionTab(mFavoritesInventoryPanel, "tab_favorites", obj_id, take_keyboard_focus))
 394	{
 395		return;
 396	}
 397
 398	if (selectItemInAccordionTab(mLandmarksInventoryPanel, "tab_landmarks", obj_id, take_keyboard_focus))
 399	{
 400		return;
 401	}
 402
 403	if (selectItemInAccordionTab(mMyInventoryPanel, "tab_inventory", obj_id, take_keyboard_focus))
 404	{
 405		return;
 406	}
 407
 408	if (selectItemInAccordionTab(mLibraryInventoryPanel, "tab_library", obj_id, take_keyboard_focus))
 409	{
 410		return;
 411	}
 412}
 413
 414//////////////////////////////////////////////////////////////////////////
 415// PROTECTED METHODS
 416//////////////////////////////////////////////////////////////////////////
 417
 418bool LLLandmarksPanel::isLandmarkSelected() const 
 419{
 420	LLFolderViewItem* current_item = getCurSelectedItem();
 421	if(current_item && current_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
 422	{
 423		return true;
 424	}
 425
 426	return false;
 427}
 428
 429bool LLLandmarksPanel::isReceivedFolderSelected() const
 430{
 431	// Received Folder can be only in Landmarks accordion
 432	if (mCurrentSelectedList != mLandmarksInventoryPanel) return false;
 433
 434	// *TODO: it should be filled with logic when EXT-976 is done.
 435
 436	llwarns << "Not implemented yet until EXT-976 is done." << llendl;
 437
 438	return false;
 439}
 440
 441void LLLandmarksPanel::doActionOnCurSelectedLandmark(LLLandmarkList::loaded_callback_t cb)
 442{
 443	LLFolderViewItem* cur_item = getCurSelectedItem();
 444	if(cur_item && cur_item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
 445	{ 
 446		LLLandmark* landmark = LLLandmarkActions::getLandmark(cur_item->getListener()->getUUID(), cb);
 447		if (landmark)
 448		{
 449			cb(landmark);
 450		}
 451	}
 452}
 453
 454LLFolderViewItem* LLLandmarksPanel::getCurSelectedItem() const 
 455{
 456	return mCurrentSelectedList ?  mCurrentSelectedList->getRootFolder()->getCurSelectedItem() : NULL;
 457}
 458
 459LLFolderViewItem* LLLandmarksPanel::selectItemInAccordionTab(LLPlacesInventoryPanel* inventory_list,
 460															 const std::string& tab_name,
 461															 const LLUUID& obj_id,
 462															 BOOL take_keyboard_focus) const
 463{
 464	if (!inventory_list)
 465		return NULL;
 466
 467	LLFolderView* root = inventory_list->getRootFolder();
 468
 469	LLFolderViewItem* item = root->getItemByID(obj_id);
 470	if (!item)
 471		return NULL;
 472
 473	LLAccordionCtrlTab* tab = getChild<LLAccordionCtrlTab>(tab_name);
 474	if (!tab->isExpanded())
 475	{
 476		tab->changeOpenClose(false);
 477	}
 478
 479	root->setSelection(item, FALSE, take_keyboard_focus);
 480
 481	LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion");
 482	LLRect screen_rc;
 483	localRectToScreen(item->getRect(), &screen_rc);
 484	accordion->notifyParent(LLSD().with("scrollToShowRect", screen_rc.getValue()));
 485
 486	return item;
 487}
 488
 489void LLLandmarksPanel::updateSortOrder(LLInventoryPanel* panel, bool byDate)
 490{
 491	if(!panel) return; 
 492
 493	U32 order = panel->getSortOrder();
 494	if (byDate)
 495	{
 496		panel->setSortOrder( order | LLInventoryFilter::SO_DATE );
 497	}
 498	else 
 499	{
 500		panel->setSortOrder( order & ~LLInventoryFilter::SO_DATE );
 501	}
 502}
 503
 504// virtual
 505void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)
 506{
 507	//this function will be called after user will try to create a pick for selected landmark.
 508	// We have to make request to sever to get parcel_id and snaption_id. 
 509	if(isLandmarkSelected())
 510	{
 511		LLFolderViewItem* cur_item = getCurSelectedItem();
 512		if (!cur_item) return;
 513		LLUUID id = cur_item->getListener()->getUUID();
 514		LLInventoryItem* inv_item = mCurrentSelectedList->getModel()->getItem(id);
 515		doActionOnCurSelectedLandmark(boost::bind(
 516				&LLLandmarksPanel::doProcessParcelInfo, this, _1, cur_item, inv_item, parcel_data));
 517	}
 518}
 519
 520// virtual
 521void LLLandmarksPanel::setParcelID(const LLUUID& parcel_id)
 522{
 523	if (!parcel_id.isNull())
 524	{
 525		LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this);
 526		LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id);
 527	}
 528}
 529
 530// virtual
 531void LLLandmarksPanel::setErrorStatus(U32 status, const std::string& reason)
 532{
 533	llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<llendl;
 534}
 535
 536
 537//////////////////////////////////////////////////////////////////////////
 538// PRIVATE METHODS
 539//////////////////////////////////////////////////////////////////////////
 540
 541void LLLandmarksPanel::initFavoritesInventoryPanel()
 542{
 543	mFavoritesInventoryPanel = getChild<LLPlacesInventoryPanel>("favorites_list");
 544
 545	initLandmarksPanel(mFavoritesInventoryPanel);
 546	mFavoritesInventoryPanel->getFilter()->setEmptyLookupMessage("FavoritesNoMatchingItems");
 547
 548	initAccordion("tab_favorites", mFavoritesInventoryPanel, true);
 549}
 550
 551void LLLandmarksPanel::initLandmarksInventoryPanel()
 552{
 553	mLandmarksInventoryPanel = getChild<LLPlacesInventoryPanel>("landmarks_list");
 554
 555	initLandmarksPanel(mLandmarksInventoryPanel);
 556
 557	// Check if mLandmarksInventoryPanel is properly initialized and has a Filter created.
 558	// In case of a dummy widget getFilter() will return NULL.
 559	if (mLandmarksInventoryPanel->getFilter())
 560	{
 561		mLandmarksInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS);
 562	}
 563
 564	// subscribe to have auto-rename functionality while creating New Folder
 565	mLandmarksInventoryPanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mLandmarksInventoryPanel, _1, _2));
 566
 567	mMyLandmarksAccordionTab = initAccordion("tab_landmarks", mLandmarksInventoryPanel, true);
 568}
 569
 570void LLLandmarksPanel::initMyInventoryPanel()
 571{
 572	mMyInventoryPanel= getChild<LLPlacesInventoryPanel>("my_inventory_list");
 573
 574	initLandmarksPanel(mMyInventoryPanel);
 575
 576	initAccordion("tab_inventory", mMyInventoryPanel, false);
 577}
 578
 579void LLLandmarksPanel::initLibraryInventoryPanel()
 580{
 581	mLibraryInventoryPanel = getChild<LLPlacesInventoryPanel>("library_list");
 582
 583	initLandmarksPanel(mLibraryInventoryPanel);
 584
 585	// We want to fetch only "Landmarks" category from the library.
 586	const LLUUID &landmarks_cat = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false, true);
 587	if (landmarks_cat.notNull())
 588	{
 589		LLInventoryModelBackgroundFetch::instance().start(landmarks_cat);
 590	}
 591
 592	// Expanding "Library" tab for new users who have no landmarks in "My Inventory".
 593	initAccordion("tab_library", mLibraryInventoryPanel, true);
 594}
 595
 596void LLLandmarksPanel::initLandmarksPanel(LLPlacesInventoryPanel* inventory_list)
 597{
 598	// In case of a dummy widget further we have no Folder View widget and no Filter,
 599	// so further initialization leads to crash.
 600	if (!inventory_list->getFilter())
 601		return;
 602
 603	inventory_list->getFilter()->setEmptyLookupMessage("PlacesNoMatchingItems");
 604	inventory_list->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK);
 605	inventory_list->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, inventory_list, _1, _2));
 606
 607	inventory_list->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
 608	bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
 609	updateSortOrder(inventory_list, sorting_order);
 610
 611	LLPlacesFolderView* root_folder = dynamic_cast<LLPlacesFolderView*>(inventory_list->getRootFolder());
 612	if (root_folder)
 613	{
 614		root_folder->setupMenuHandle(LLInventoryType::IT_CATEGORY, mGearFolderMenu->getHandle());
 615		root_folder->setupMenuHandle(LLInventoryType::IT_LANDMARK, mGearLandmarkMenu->getHandle());
 616
 617		root_folder->setParentLandmarksPanel(this);
 618	}
 619
 620	inventory_list->saveFolderState();
 621}
 622
 623LLAccordionCtrlTab* LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLPlacesInventoryPanel* inventory_list,	bool expand_tab)
 624{
 625	LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name);
 626
 627	mAccordionTabs.push_back(accordion_tab);
 628	accordion_tab->setDropDownStateChangedCallback(
 629		boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));
 630	accordion_tab->setDisplayChildren(expand_tab);
 631	return accordion_tab;
 632}
 633
 634void LLLandmarksPanel::onAccordionExpandedCollapsed(const LLSD& param, LLPlacesInventoryPanel* inventory_list)
 635{
 636	bool expanded = param.asBoolean();
 637
 638	if(!expanded && (mCurrentSelectedList == inventory_list))
 639	{
 640		inventory_list->getRootFolder()->clearSelection();
 641
 642		mCurrentSelectedList = NULL;
 643		updateVerbs();
 644	}
 645
 646	// Start background fetch, mostly for My Inventory and Library
 647	if (expanded)
 648	{
 649		const LLUUID &cat_id = inventory_list->getRootFolderID();
 650		// Just because the category itself has been fetched, doesn't mean its child folders have.
 651		/*
 652		  if (!gInventory.isCategoryComplete(cat_id))
 653		*/
 654		{
 655			LLInventoryModelBackgroundFetch::instance().start(cat_id);
 656		}
 657
 658		// Apply filter substring because it might have been changed
 659		// while accordion was closed. See EXT-3714.
 660		filter_list(inventory_list, sFilterSubString);
 661	}
 662}
 663
 664void LLLandmarksPanel::deselectOtherThan(const LLPlacesInventoryPanel* inventory_list)
 665{
 666	if (inventory_list != mFavoritesInventoryPanel)
 667	{
 668		mFavoritesInventoryPanel->getRootFolder()->clearSelection();
 669	}
 670
 671	if (inventory_list != mLandmarksInventoryPanel)
 672	{
 673		mLandmarksInventoryPanel->getRootFolder()->clearSelection();
 674	}
 675	if (inventory_list != mMyInventoryPanel)
 676	{
 677		mMyInventoryPanel->getRootFolder()->clearSelection();
 678	}
 679	if (inventory_list != mLibraryInventoryPanel)
 680	{
 681		mLibraryInventoryPanel->getRootFolder()->clearSelection();
 682	}
 683}
 684
 685// List Commands Handlers
 686void LLLandmarksPanel::initListCommandsHandlers()
 687{
 688	mListCommands = getChild<LLPanel>("bottom_panel");
 689
 690	mGearButton = getChild<LLMenuButton>(OPTIONS_BUTTON_NAME);
 691	mGearButton->setMouseDownCallback(boost::bind(&LLLandmarksPanel::onActionsButtonClick, this));
 692
 693	mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this));
 694
 695	LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);
 696	trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this
 697			,	_4 // BOOL drop
 698			,	_5 // EDragAndDropType cargo_type
 699			,	_6 // void* cargo_data
 700			,	_7 // EAcceptance* accept
 701			));
 702
 703	mCommitCallbackRegistrar.add("Places.LandmarksGear.Add.Action", boost::bind(&LLLandmarksPanel::onAddAction, this, _2));
 704	mCommitCallbackRegistrar.add("Places.LandmarksGear.CopyPaste.Action", boost::bind(&LLLandmarksPanel::onClipboardAction, this, _2));
 705	mCommitCallbackRegistrar.add("Places.LandmarksGear.Custom.Action", boost::bind(&LLLandmarksPanel::onCustomAction, this, _2));
 706	mCommitCallbackRegistrar.add("Places.LandmarksGear.Folding.Action", boost::bind(&LLLandmarksPanel::onFoldingAction, this, _2));
 707	mEnableCallbackRegistrar.add("Places.LandmarksGear.Check", boost::bind(&LLLandmarksPanel::isActionChecked, this, _2));
 708	mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));
 709	mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 710	mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 711	mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
 712
 713	mGearLandmarkMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2));
 714	mGearFolderMenu->setVisibilityChangeCallback(boost::bind(&LLLandmarksPanel::onMenuVisibilityChange, this, _1, _2));
 715
 716	mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::showActionMenu, this, mMenuAdd, ADD_BUTTON_NAME));
 717}
 718
 719
 720void LLLandmarksPanel::updateListCommands()
 721{
 722	bool add_folder_enabled = isActionEnabled("category");
 723	bool trash_enabled = isActionEnabled("delete");
 724
 725	// keep Options & Add Landmark buttons always enabled
 726	mListCommands->getChildView(ADD_FOLDER_BUTTON_NAME)->setEnabled(add_folder_enabled);
 727	mListCommands->getChildView(TRASH_BUTTON_NAME)->setEnabled(trash_enabled);
 728}
 729
 730void LLLandmarksPanel::onActionsButtonClick()
 731{
 732	LLToggleableMenu* menu = mGearFolderMenu;
 733
 734	LLFolderViewItem* cur_item = NULL;
 735	if(mCurrentSelectedList)
 736	{
 737		cur_item = mCurrentSelectedList->getRootFolder()->getCurSelectedItem();
 738		if(!cur_item)
 739			return;
 740
 741		LLFolderViewEventListener* listenerp = cur_item->getListener();
 742		if(!listenerp)
 743			return;
 744
 745		if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK)
 746		{
 747			menu = mGearLandmarkMenu;
 748		}
 749	}
 750
 751	mGearButton->setMenu(menu);
 752}
 753
 754void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)
 755{
 756	if (menu)
 757	{
 758		menu->buildDrawLabels();
 759		menu->updateParent(LLMenuGL::sMenuContainer);
 760		menu->arrangeAndClear();
 761
 762		LLView* spawning_view = getChild<LLView>(spawning_view_name);
 763
 764		S32 menu_x, menu_y;
 765		//show menu in co-ordinates of panel
 766		spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this);
 767		menu_y += menu->getRect().getHeight();
 768		LLMenuGL::showPopup(this, menu, menu_x, menu_y);
 769	}
 770}
 771
 772void LLLandmarksPanel::onTrashButtonClick() const
 773{
 774	onClipboardAction("delete");
 775}
 776
 777void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
 778{
 779	std::string command_name = userdata.asString();
 780	if("add_landmark" == command_name)
 781	{
 782		LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
 783		if(landmark)
 784		{
 785			LLNotificationsUtil::add("LandmarkAlreadyExists");
 786		}
 787		else
 788		{
 789			LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
 790		}
 791	} 
 792	else if ("category" == command_name)
 793	{
 794		LLFolderViewItem* item = getCurSelectedItem();
 795		if (item && mCurrentSelectedList == mLandmarksInventoryPanel)
 796		{
 797			LLFolderViewEventListener* folder_bridge = NULL;
 798			if (item-> getListener()->getInventoryType()
 799					== LLInventoryType::IT_LANDMARK)
 800			{
 801				// for a landmark get parent folder bridge
 802				folder_bridge = item->getParentFolder()->getListener();
 803			}
 804			else if (item-> getListener()->getInventoryType()
 805					== LLInventoryType::IT_CATEGORY)
 806			{
 807				// for a folder get its own bridge
 808				folder_bridge = item->getListener();
 809			}
 810
 811			menu_create_inventory_item(mCurrentSelectedList->getRootFolder(),
 812					dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD(
 813							"category"), gInventory.findCategoryUUIDForType(
 814							LLFolderType::FT_LANDMARK));
 815		}
 816		else
 817		{
 818			//in case My Landmarks tab is completely empty (thus cannot be determined as being selected)
 819			menu_create_inventory_item(mLandmarksInventoryPanel->getRootFolder(), NULL, LLSD("category"), 
 820				gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK));
 821
 822			if (mMyLandmarksAccordionTab)
 823			{
 824				mMyLandmarksAccordionTab->changeOpenClose(false);
 825			}
 826		}
 827	}
 828}
 829
 830void LLLandmarksPanel::onClipboardAction(const LLSD& userdata) const
 831{
 832	if(!mCurrentSelectedList) 
 833		return;
 834	std::string command_name = userdata.asString();
 835    if("copy_slurl" == command_name)
 836	{
 837    	LLFolderViewItem* cur_item = getCurSelectedItem();
 838		if(cur_item)
 839			LLLandmarkActions::copySLURLtoClipboard(cur_item->getListener()->getUUID());
 840	}
 841	else if ( "paste" == command_name)
 842	{
 843		mCurrentSelectedList->getRootFolder()->paste();
 844	} 
 845	else if ( "cut" == command_name)
 846	{
 847		mCurrentSelectedList->getRootFolder()->cut();
 848	}
 849	else
 850	{
 851		mCurrentSelectedList->getRootFolder()->doToSelected(mCurrentSelectedList->getModel(),command_name);
 852	}
 853}
 854
 855void LLLandmarksPanel::onFoldingAction(const LLSD& userdata)
 856{
 857	std::string command_name = userdata.asString();
 858
 859	if ("expand_all" == command_name)
 860	{
 861		expand_all_folders(mFavoritesInventoryPanel->getRootFolder());
 862		expand_all_folders(mLandmarksInventoryPanel->getRootFolder());
 863		expand_all_folders(mMyInventoryPanel->getRootFolder());
 864		expand_all_folders(mLibraryInventoryPanel->getRootFolder());
 865
 866		for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
 867		{
 868			(*iter)->changeOpenClose(false);
 869		}
 870	}
 871	else if ("collapse_all" == command_name)
 872	{
 873		collapse_all_folders(mFavoritesInventoryPanel->getRootFolder());
 874		collapse_all_folders(mLandmarksInventoryPanel->getRootFolder());
 875		collapse_all_folders(mMyInventoryPanel->getRootFolder());
 876		collapse_all_folders(mLibraryInventoryPanel->getRootFolder());
 877
 878		for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
 879		{
 880			(*iter)->changeOpenClose(true);
 881		}
 882	}
 883	else if ("sort_by_date" == command_name)
 884	{
 885		bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
 886		sorting_order=!sorting_order;
 887		gSavedSettings.setBOOL("LandmarksSortedByDate",sorting_order);
 888		updateSortOrder(mLandmarksInventoryPanel, sorting_order);
 889		updateSortOrder(mMyInventoryPanel, sorting_order);
 890		updateSortOrder(mLibraryInventoryPanel, sorting_order);
 891	}
 892	else
 893	{
 894		if(mCurrentSelectedList)
 895		{
 896			mCurrentSelectedList->getRootFolder()->doToSelected(&gInventory, userdata);
 897		}
 898	}
 899}
 900
 901bool LLLandmarksPanel::isActionChecked(const LLSD& userdata) const
 902{
 903	const std::string command_name = userdata.asString();
 904
 905	if ( "sort_by_date" == command_name)
 906	{
 907		bool sorting_order = gSavedSettings.getBOOL("LandmarksSortedByDate");
 908		return  sorting_order;
 909	}
 910
 911	return false;
 912}
 913
 914bool LLLandmarksPanel::isActionEnabled(const LLSD& userdata) const
 915{
 916	std::string command_name = userdata.asString();
 917
 918	LLPlacesFolderView* root_folder_view = mCurrentSelectedList ?
 919		static_cast<LLPlacesFolderView*>(mCurrentSelectedList->getRootFolder()) : NULL;
 920
 921	if ("collapse_all" == command_name)
 922	{
 923		bool disable_collapse_all =	!has_expanded_folders(mFavoritesInventoryPanel->getRootFolder())
 924									&& !has_expanded_folders(mLandmarksInventoryPanel->getRootFolder())
 925									&& !has_expanded_folders(mMyInventoryPanel->getRootFolder())
 926									&& !has_expanded_folders(mLibraryInventoryPanel->getRootFolder());
 927		if (disable_collapse_all)
 928		{
 929			for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
 930			{
 931				if ((*iter)->isExpanded())
 932				{
 933					disable_collapse_all = false;
 934					break;
 935				}
 936			}
 937		}
 938
 939		return !disable_collapse_all;
 940	}
 941	else if ("expand_all" == command_name)
 942	{
 943		bool disable_expand_all = !has_collapsed_folders(mFavoritesInventoryPanel->getRootFolder())
 944								  && !has_collapsed_folders(mLandmarksInventoryPanel->getRootFolder())
 945								  && !has_collapsed_folders(mMyInventoryPanel->getRootFolder())
 946								  && !has_collapsed_folders(mLibraryInventoryPanel->getRootFolder());
 947		if (disable_expand_all)
 948		{
 949			for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter)
 950			{
 951				if (!(*iter)->isExpanded())
 952				{
 953					disable_expand_all = false;
 954					break;
 955				}
 956			}
 957		}
 958
 959		return !disable_expand_all;
 960	}
 961	else if ("sort_by_date"	== command_name)
 962	{
 963		// disable "sort_by_date" for Favorites accordion because
 964		// it has its own items order. EXT-1758
 965		if (mCurrentSelectedList == mFavoritesInventoryPanel)
 966		{
 967			return false;
 968		}
 969	}
 970	else if (  "paste"		== command_name
 971			|| "cut"		== command_name
 972			|| "copy"		== command_name
 973			|| "delete"		== command_name
 974			|| "collapse"	== command_name
 975			|| "expand"		== command_name
 976			)
 977	{
 978		if (!root_folder_view) return false;
 979
 980		std::set<LLUUID> selected_uuids = root_folder_view->getSelectionList();
 981
 982		// Allow to execute the command only if it can be applied to all selected items.
 983		for (std::set<LLUUID>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter)
 984		{
 985			LLFolderViewItem* item = root_folder_view->getItemByID(*iter);
 986
 987			// If no item is found it might be a folder id.
 988			if (!item)
 989			{
 990				item = root_folder_view->getFolderByID(*iter);
 991			}
 992			if (!item) return false;
 993
 994			if (!canItemBeModified(command_name, item)) return false;
 995		}
 996
 997		return true;
 998	}
 999	else if (  "teleport"		== command_name
1000			|| "more_info"		== command_name
1001			|| "show_on_map"	== command_name
1002			|| "copy_slurl"		== command_name
1003			|| "rename"			== command_name
1004			)
1005	{
1006		// disable some commands for multi-selection. EXT-1757
1007		bool is_single_selection = root_folder_view && root_folder_view->getSelectedCount() == 1;
1008		if (!is_single_selection)
1009		{
1010			return false;
1011		}
1012
1013		if ("show_on_map" == command_name)
1014		{
1015			LLFolderViewItem* cur_item = root_folder_view->getCurSelectedItem();
1016			if (!cur_item) return false;
1017
1018			LLViewerInventoryItem* inv_item = cur_item->getInventoryItem();
1019			if (!inv_item) return false;
1020
1021			LLUUID asset_uuid = inv_item->getAssetUUID();
1022			if (asset_uuid.isNull()) return false;
1023
1024			// Disable "Show on Map" if landmark loading is in progress.
1025			return !gLandmarkList.isAssetInLoadedCallbackMap(asset_uuid);
1026	}
1027	else if ("rename" == command_name)
1028	{
1029			LLFolderViewItem* selected_item = getCurSelectedItem();
1030			if (!selected_item) return false;
1031
1032			return canItemBeModified(command_name, selected_item);
1033		}
1034
1035		return true;
1036	}
1037	else if("category" == command_name)
1038	{
1039		// we can add folder only in Landmarks Accordion
1040		if (mCurrentSelectedList == mLandmarksInventoryPanel)
1041		{
1042			// ... but except Received folder
1043			return !isReceivedFolderSelected();
1044		}
1045		//"Add a folder" is enabled by default (case when My Landmarks is empty)
1046		else return true;
1047	}
1048	else if("create_pick" == command_name)
1049	{
1050		if (mCurrentSelectedList)
1051		{
1052			std::set<LLUUID> selection = mCurrentSelectedList->getRootFolder()->getSelectionList();
1053			if (!selection.empty())
1054			{
1055				return ( 1 == selection.size() && !LLAgentPicksInfo::getInstance()->isPickLimitReached() );
1056			}
1057		}
1058		return false;
1059	}
1060	else
1061	{
1062		llwarns << "Unprocessed command has come: " << command_name << llendl;
1063	}
1064
1065	return true;
1066}
1067
1068void LLLandmarksPanel::onCustomAction(const LLSD& userdata)
1069{
1070	std::string command_name = userdata.asString();
1071	if("more_info" == command_name)
1072	{
1073		onShowProfile();
1074	}
1075	else if ("teleport" == command_name)
1076	{
1077		onTeleport();
1078	}
1079	else if ("show_on_map" == command_name)
1080	{
1081		onShowOnMap();
1082	}
1083	else if ("create_pick" == command_name)
1084	{
1085		doActionOnCurSelectedLandmark(boost::bind(&LLLandmarksPanel::doCreatePick, this, _1));
1086	}
1087	else if ("restore" == command_name && mCurrentSelectedList)
1088	{
1089		mCurrentSelectedList->doToSelected(userdata);
1090	}
1091}
1092
1093void LLLandmarksPanel::onMenuVisibilityChange(LLUICtrl* ctrl, const LLSD& param)
1094{
1095	bool new_visibility = param["visibility"].asBoolean();
1096
1097	// We don't have to update items visibility if the menu is hiding.
1098	if (!new_visibility) return;
1099
1100	BOOL are_any_items_in_trash = FALSE;
1101	BOOL are_all_items_in_trash = TRUE;
1102
1103	LLFolderView* root_folder_view = mCurrentSelectedList ? mCurrentSelectedList->getRootFolder() : NULL;
1104	if(root_folder_view)
1105	{
1106		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
1107
1108		std::set<LLUUID> selected_uuids = root_folder_view->getSelectionList();
1109
1110		// Iterate through selected items to find out if any of these items are in Trash
1111		// or all the items are in Trash category.
1112		for (std::set<LLUUID>::const_iterator iter = selected_uuids.begin(); iter != selected_uuids.end(); ++iter)
1113		{
1114			LLFolderViewItem* item = root_folder_view->getItemByID(*iter);
1115
1116			// If no item is found it might be a folder id.
1117			if (!item)
1118			{
1119				item = root_folder_view->getFolderByID(*iter);
1120			}
1121			if (!item) continue;
1122
1123			LLFolderViewEventListener* listenerp = item->getListener();
1124			if(!listenerp) continue;
1125
1126			// Trash category itself should not be included because it can't be
1127			// actually restored from trash.
1128			are_all_items_in_trash &= listenerp->isItemInTrash() && *iter != trash_id;
1129
1130			// If there are any selected items in Trash including the Trash category itself
1131			// we show "Restore Item" in context menu and hide other irrelevant items.
1132			are_any_items_in_trash |= listenerp->isItemInTrash();
1133		}
1134	}
1135
1136	// Display "Restore Item" menu entry if at least one of the selected items
1137	// is in Trash or the Trash category itself is among selected items.
1138	// Hide other menu entries in this case.
1139	// Enable this menu entry only if all selected items are in the Trash category.
1140	toggle_restore_menu((LLMenuGL*)ctrl, are_any_items_in_trash, are_all_items_in_trash);
1141}
1142
1143/*
1144Processes such actions: cut/rename/delete/paste actions
1145
1146Rules:
1147 1. We can't perform any action in Library
1148 2. For Landmarks we can:
1149	- cut/rename/delete in any other accordions
1150	- paste - only in Favorites, Landmarks accordions
1151 3. For Folders we can: perform any action in Landmarks accordion, except Received folder
1152 4. We can not paste folders from Clipboard (processed by LLFolderView::canPaste())
1153 5. Check LLFolderView/Inventory Bridges rules
1154 */
1155bool LLLandmarksPanel::canItemBeModified(const std::string& command_name, LLFolderViewItem* item) const
1156{
1157	// validate own rules first
1158
1159	if (!item) return false;
1160
1161	// nothing can be modified in Library
1162	if (mLibraryInventoryPanel == mCurrentSelectedList) return false;
1163
1164	bool can_be_modified = false;
1165
1166	// landmarks can be modified in any other accordion...
1167	if (item->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK)
1168	{
1169		can_be_modified = true;
1170
1171		// we can modify landmarks anywhere except paste to My Inventory
1172		if ("paste" == command_name)
1173		{
1174			can_be_modified = (mCurrentSelectedList != mMyInventoryPanel);
1175		}
1176	}
1177	else
1178	{
1179		// ...folders only in the Landmarks accordion...
1180		can_be_modified = mLandmarksInventoryPanel == mCurrentSelectedList;
1181
1182		// ...except "Received" folder
1183		can_be_modified &= !isReceivedFolderSelected();
1184	}
1185
1186	// then ask LLFolderView permissions
1187
1188	LLFolderView* root_folder = mCurrentSelectedList->getRootFolder();
1189
1190	if ("copy" == command_name)
1191	{
1192		return root_folder->canCopy();
1193	}
1194	else if ("collapse" == command_name)
1195	{
1196		return item->isOpen();
1197	}
1198	else if ("expand" == command_name)
1199	{
1200		return !item->isOpen();
1201	}
1202
1203	if (can_be_modified)
1204	{
1205		LLFolderViewEventListener* listenerp = item->getListener();
1206
1207		if ("cut" == command_name)
1208		{
1209			// "Cut" disabled for folders. See EXT-8697.
1210			can_be_modified = root_folder->canCut() && listenerp->getInventoryType() != LLInventoryType::IT_CATEGORY;
1211		}
1212		else if ("rename" == command_name)
1213		{
1214			can_be_modified = listenerp ? listenerp->isItemRenameable() : false;
1215		}
1216		else if ("delete" == command_name)
1217		{
1218			can_be_modified = listenerp ? listenerp->isItemRemovable() && !listenerp->isItemInTrash() : false;
1219		}
1220		else if("paste" == command_name)
1221		{
1222			can_be_modified = root_folder->canPaste();
1223		}
1224		else
1225		{
1226			llwarns << "Unprocessed command has come: " << command_name << llendl;
1227		}
1228	}
1229
1230	return can_be_modified;
1231}
1232
1233void LLLandmarksPanel::onPickPanelExit( LLPanelPickEdit* pick_panel, LLView* owner, const LLSD& params)
1234{
1235	pick_panel->setVisible(FALSE);
1236	owner->removeChild(pick_panel);
1237	//we need remove  observer to  avoid  processParcelInfo in the future.
1238	LLRemoteParcelInfoProcessor::getInstance()->removeObserver(params["parcel_id"].asUUID(), this);
1239
1240	delete pick_panel;
1241	pick_panel = NULL;
1242}
1243
1244bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, void* cargo_data , EAcceptance* accept)
1245{
1246	*accept = ACCEPT_NO;
1247
1248	switch (cargo_type)
1249	{
1250
1251	case DAD_LANDMARK:
1252	case DAD_CATEGORY:
1253		{
1254			bool is_enabled = isActionEnabled("delete");
1255
1256			if (is_enabled) *accept = ACCEPT_YES_MULTI;
1257
1258			if (is_enabled && drop)
1259			{
1260				// don't call onClipboardAction("delete")
1261				// this lead to removing (N * 2 - 1) items if drag N>1 items into trash. EXT-6757
1262				// So, let remove items one by one.
1263				LLInventoryItem* item = static_cast<LLInventoryItem*>(cargo_data);
1264				if (item)
1265				{
1266					LLFolderViewItem* fv_item = (mCurrentSelectedList && mCurrentSelectedList->getRootFolder()) ?
1267						mCurrentSelectedList->getRootFolder()->getItemByID(item->getUUID()) : NULL;
1268
1269					if (fv_item)
1270					{
1271						// is Item Removable checked inside of remove()
1272						fv_item->remove();
1273					}
1274				}
1275			}
1276		}
1277		break;
1278	default:
1279		break;
1280	}
1281
1282	return true;
1283}
1284
1285void LLLandmarksPanel::doShowOnMap(LLLandmark* landmark)
1286{
1287	LLVector3d landmark_global_pos;
1288	if (!landmark->getGlobalPos(landmark_global_pos))
1289		return;
1290
1291	LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
1292	if (!landmark_global_pos.isExactlyZero() && worldmap_instance)
1293	{
1294		worldmap_instance->trackLocation(landmark_global_pos);
1295		LLFloaterReg::showInstance("world_map", "center");
1296	}
1297
1298	mShowOnMapBtn->setEnabled(TRUE);
1299	mGearLandmarkMenu->setItemEnabled("show_on_map", TRUE);
1300}
1301
1302void LLLandmarksPanel::doProcessParcelInfo(LLLandmark* landmark,
1303										   LLFolderViewItem* cur_item,
1304										   LLInventoryItem* inv_item,
1305										   const LLParcelData& parcel_data)
1306{
1307	LLPanelPickEdit* panel_pick = LLPanelPickEdit::create();
1308	LLVector3d landmark_global_pos;
1309	landmark->getGlobalPos(landmark_global_pos);
1310
1311	// let's toggle pick panel into  panel places
1312	LLPanel* panel_places = NULL;
1313	LLFloaterSidePanelContainer* floaterp = LLFloaterReg::getTypedInstance<LLFloaterSidePanelContainer>("places");
1314	if (floaterp)
1315	{
1316		panel_places = floaterp->findChild<LLPanel>("main_panel");
1317	}
1318
1319	if (!panel_places)
1320	{
1321		llassert(NULL != panel_places);
1322		return;
1323	}
1324	panel_places->addChild(panel_pick);
1325	LLRect paren_rect(panel_places->getRect());
1326	panel_pick->reshape(paren_rect.getWidth(),paren_rect.getHeight(), TRUE);
1327	panel_pick->setRect(paren_rect);
1328	panel_pick->onOpen(LLSD());
1329
1330	LLPickData data;
1331	data.pos_global = landmark_global_pos;
1332	data.name = cur_item->getName();
1333	data.desc = inv_item->getDescription();
1334	data.snapshot_id = parcel_data.snapshot_id;
1335	data.parcel_id = parcel_data.parcel_id;
1336	panel_pick->setPickData(&data);
1337
1338	LLSD params;
1339	params["parcel_id"] = parcel_data.parcel_id;
1340	/* set exit callback to get back onto panel places
1341	 in callback we will make cleaning up( delete pick_panel instance,
1342	 remove landmark panel from observer list
1343	*/
1344	panel_pick->setExitCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
1345			panel_pick, panel_places,params));
1346	panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
1347		panel_pick, panel_places,params));
1348	panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,
1349					panel_pick, panel_places,params));
1350}
1351
1352void LLLandmarksPanel::doCreatePick(LLLandmark* landmark)
1353{
1354	LLViewerRegion* region = gAgent.getRegion();
1355	if (!region) return;
1356
1357	LLGlobalVec pos_global;
1358	LLUUID region_id;
1359	landmark->getGlobalPos(pos_global);
1360	landmark->getRegionID(region_id);
1361	LLVector3 region_pos((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS),
1362					  (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS),
1363					  (F32)pos_global.mdV[VZ]);
1364
1365	LLSD body;
1366	std::string url = region->getCapability("RemoteParcelRequest");
1367	if (!url.empty())
1368	{
1369		body["location"] = ll_sd_from_vector3(region_pos);
1370		if (!region_id.isNull())
1371		{
1372			body["region_id"] = region_id;
1373		}
1374		if (!pos_global.isExactlyZero())
1375		{
1376			U64 region_handle = to_region_handle(pos_global);
1377			body["region_handle"] = ll_sd_from_U64(region_handle);
1378		}
1379		LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle()));
1380	}
1381	else
1382	{
1383		llwarns << "Can't create pick for landmark for region" << region_id
1384				<< ". Region: "	<< region->getName()
1385				<< " does not support RemoteParcelRequest" << llendl;
1386	}
1387}
1388
1389//////////////////////////////////////////////////////////////////////////
1390// HELPER FUNCTIONS
1391//////////////////////////////////////////////////////////////////////////
1392static void filter_list(LLPlacesInventoryPanel* inventory_list, const std::string& string)
1393{
1394	// When search is cleared, restore the old folder state.
1395	if (!inventory_list->getRootFolder()->getFilterSubString().empty() && string == "")
1396	{
1397		inventory_list->setFilterSubString(LLStringUtil::null);
1398		// Re-open folders that were open before
1399		inventory_list->restoreFolderState();
1400	}
1401
1402	if (inventory_list->getFilterSubString().empty() && string.empty())
1403	{
1404		// current filter and new filter empty, do nothing
1405		return;
1406	}
1407
1408	// save current folder open state if no filter currently applied
1409	if (inventory_list->getRootFolder()->getFilterSubString().empty())
1410	{
1411		inventory_list->saveFolderState();
1412	}
1413
1414	// Set new filter string
1415	inventory_list->setFilterSubString(string);
1416}
1417
1418static bool category_has_descendents(LLPlacesInventoryPanel* inventory_list)
1419{
1420	LLViewerInventoryCategory* category = gInventory.getCategory(inventory_list->getRootFolderID());
1421	if (category)
1422	{
1423		return category->getDescendentCount() > 0;
1424	}
1425
1426	return false;
1427}
1428
1429static void collapse_all_folders(LLFolderView* root_folder)
1430{
1431	if (!root_folder)
1432		return;
1433
1434	root_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
1435
1436	// The top level folder is invisible, it must be open to
1437	// display its sub-folders.
1438	root_folder->openTopLevelFolders();
1439	root_folder->arrangeAll();
1440}
1441
1442static void expand_all_folders(LLFolderView* root_folder)
1443{
1444	if (!root_folder)
1445		return;
1446
1447	root_folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
1448	root_folder->arrangeAll();
1449}
1450
1451static bool has_expanded_folders(LLFolderView* root_folder)
1452{
1453	LLCheckFolderState checker;
1454	root_folder->applyFunctorRecursively(checker);
1455
1456	// We assume that the root folder is always expanded so we enable "collapse_all"
1457	// command when we have at least one more expanded folder.
1458	if (checker.getExpandedFolders() < 2)
1459	{
1460		return false;
1461	}
1462
1463	return true;
1464}
1465
1466static bool has_collapsed_folders(LLFolderView* root_folder)
1467{
1468	LLCheckFolderState checker;
1469	root_folder->applyFunctorRecursively(checker);
1470
1471	if (checker.getCollapsedFolders() < 1)
1472	{
1473		return false;
1474	}
1475
1476	return true;
1477}
1478
1479// Displays "Restore Item" context menu entry while hiding
1480// all other entries or vice versa.
1481// Sets "Restore Item" enabled state.
1482void toggle_restore_menu(LLMenuGL *menu, BOOL visible, BOOL enabled)
1483{
1484	if (!menu) return;
1485
1486	const LLView::child_list_t *list = menu->getChildList();
1487	for (LLView::child_list_t::const_iterator itor = list->begin();
1488		 itor != list->end();
1489		 ++itor)
1490	{
1491		LLView *menu_item = (*itor);
1492		std::string name = menu_item->getName();
1493
1494		if ("restore_item" == name)
1495		{
1496			menu_item->setVisible(visible);
1497			menu_item->setEnabled(enabled);
1498		}
1499		else
1500		{
1501			menu_item->setVisible(!visible);
1502		}
1503	}
1504}
1505// EOF