phoenix-firestorm/indra/newview/llfloatercreatelandmark.cpp

454 lines
13 KiB
C++

/**
* @file llfloatercreatelandmark.cpp
* @brief LLFloaterCreateLandmark class implementation
*
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2021, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llfloatercreatelandmark.h"
#include "llagent.h"
#include "llagentui.h"
#include "llcombobox.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "lllandmarkactions.h"
#include "llnotificationsutil.h"
#include "llpanellandmarkinfo.h"
#include "llparcel.h"
#include "lltextbox.h"
#include "lltexteditor.h"
#include "lluictrlfactory.h"
#include "llviewermessage.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
typedef std::pair<LLUUID, std::string> folder_pair_t;
class LLLandmarksInventoryObserver : public LLInventoryObserver
{
public:
LLLandmarksInventoryObserver(LLFloaterCreateLandmark* create_landmark_floater) :
mFloater(create_landmark_floater)
{}
void changed(U32 mask) override
{
if (mFloater->getItem())
{
checkChanged(mask);
}
else
{
checkCreated(mask);
}
}
protected:
void checkCreated(U32 mask)
{
if (gInventory.getAddedIDs().empty())
{
return;
}
if (!(mask & LLInventoryObserver::ADD) ||
!(mask & LLInventoryObserver::CREATE) ||
!(mask & LLInventoryObserver::UPDATE_CREATE))
{
return;
}
mFloater->setItem(gInventory.getAddedIDs());
}
void checkChanged(U32 mask)
{
if (gInventory.getChangedIDs().empty())
{
return;
}
if ((mask & LLInventoryObserver::LABEL) ||
(mask & LLInventoryObserver::INTERNAL) ||
(mask & LLInventoryObserver::REMOVE) ||
(mask & LLInventoryObserver::STRUCTURE) ||
(mask & LLInventoryObserver::REBUILD))
{
mFloater->updateItem(gInventory.getChangedIDs(), mask);
}
}
private:
LLFloaterCreateLandmark* mFloater;
};
LLFloaterCreateLandmark::LLFloaterCreateLandmark(const LLSD& key)
: LLFloater("add_landmark"),
mItem(NULL)
{
mInventoryObserver = new LLLandmarksInventoryObserver(this);
}
LLFloaterCreateLandmark::~LLFloaterCreateLandmark()
{
removeObserver();
}
bool LLFloaterCreateLandmark::postBuild()
{
mFolderCombo = getChild<LLComboBox>("folder_combo");
mLandmarkTitleEditor = getChild<LLLineEditor>("title_editor");
mNotesEditor = getChild<LLTextEditor>("notes_editor");
getChild<LLTextBox>("new_folder_textbox")->setURLClickedCallback(boost::bind(&LLFloaterCreateLandmark::onCreateFolderClicked, this));
getChild<LLButton>("ok_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onSaveClicked, this));
getChild<LLButton>("cancel_btn")->setClickedCallback(boost::bind(&LLFloaterCreateLandmark::onCancelClicked, this));
mLandmarkTitleEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTextChanges(); });
mNotesEditor->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTextChanges(); });
mLandmarksID = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
return true;
}
void LLFloaterCreateLandmark::removeObserver()
{
if (gInventory.containsObserver(mInventoryObserver))
gInventory.removeObserver(mInventoryObserver);
}
void LLFloaterCreateLandmark::onOpen(const LLSD& key)
{
LLUUID dest_folder = LLUUID();
if (key.has("dest_folder"))
{
dest_folder = key["dest_folder"].asUUID();
}
mItem = NULL;
gInventory.addObserver(mInventoryObserver);
setLandmarkInfo(dest_folder);
populateFoldersList(dest_folder);
}
void LLFloaterCreateLandmark::setLandmarkInfo(const LLUUID &folder_id)
{
LLViewerParcelMgr* parcel_mgr = LLViewerParcelMgr::getInstance();
LLParcel* parcel = parcel_mgr->getAgentParcel();
std::string name = parcel->getName();
LLVector3 agent_pos = gAgent.getPositionAgent();
if (name.empty())
{
S32 region_x = ll_round(agent_pos.mV[VX]);
S32 region_y = ll_round(agent_pos.mV[VY]);
S32 region_z = ll_round(agent_pos.mV[VZ]);
std::string region_name;
LLViewerRegion* region = parcel_mgr->getSelectionRegion();
if (region)
{
region_name = region->getName();
}
else
{
std::string desc;
LLAgentUI::buildLocationString(desc, LLAgentUI::LOCATION_FORMAT_NORMAL, agent_pos);
region_name = desc;
}
mLandmarkTitleEditor->setText(llformat("%s (%d, %d, %d)",
region_name.c_str(), region_x, region_y, region_z));
}
else
{
mLandmarkTitleEditor->setText(name);
}
// <FS:Ansariel> FIRE-31689: Landmark initially shown in wrong folder while creating
//LLLandmarkActions::createLandmarkHere(name, "", folder_id.notNull() ? folder_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));
LLLandmarkActions::createLandmarkHere(name, "", folder_id.notNull() ? folder_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK));
}
bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right)
{
return left.second < right.second;
}
void LLFloaterCreateLandmark::populateFoldersList(const LLUUID &folder_id)
{
// Collect all folders that can contain landmarks.
LLInventoryModel::cat_array_t cats;
LLPanelLandmarkInfo::collectLandmarkFolders(cats);
mFolderCombo->removeall();
// Put the "My Favorites" folder first in list.
// <FS:PP> Code moved below because of:
// FIRE-31031 New Create Landmark Floater: Default to Landmarks Folder
// </FS:PP>
// Add the "Landmarks" category.
const LLViewerInventoryCategory* lmcat = gInventory.getCategory(mLandmarksID);
if (!lmcat)
{
LL_WARNS() << "Cannot find the landmarks folder" << LL_ENDL;
}
else
{
std::string cat_full_name = LLPanelLandmarkInfo::getFullFolderName(lmcat);
mFolderCombo->add(cat_full_name, lmcat->getUUID());
}
// <FS:PP> FIRE-31031 New Create Landmark Floater: Default to Landmarks Folder
LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id);
if (!favorites_cat)
{
LL_WARNS() << "Cannot find the favorites folder" << LL_ENDL;
}
else
{
mFolderCombo->add(getString("favorites_bar"), favorites_cat->getUUID());
}
// </FS:PP>
typedef std::vector<folder_pair_t> folder_vec_t;
folder_vec_t folders;
// Sort the folders by their full name.
for (S32 i = 0; i < cats.size(); i++)
{
const LLViewerInventoryCategory* cat = cats.at(i);
std::string cat_full_name = LLPanelLandmarkInfo::getFullFolderName(cat);
folders.push_back(folder_pair_t(cat->getUUID(), cat_full_name));
}
sort(folders.begin(), folders.end(), cmp_folders);
// Finally, populate the combobox.
for (folder_vec_t::const_iterator it = folders.begin(); it != folders.end(); it++)
mFolderCombo->add(it->second, LLSD(it->first));
if (folder_id.notNull())
{
mFolderCombo->setCurrentByID(folder_id);
}
}
void LLFloaterCreateLandmark::onCommitTextChanges()
{
if (mItem.isNull())
{
return;
}
std::string current_title_value = mLandmarkTitleEditor->getText();
std::string item_title_value = mItem->getName();
std::string current_notes_value = mNotesEditor->getText();
std::string item_notes_value = mItem->getDescription();
LLStringUtil::trim(current_title_value);
LLStringUtil::trim(current_notes_value);
if (!current_title_value.empty() &&
(item_title_value != current_title_value || item_notes_value != current_notes_value))
{
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(mItem);
new_item->rename(current_title_value);
new_item->setDescription(current_notes_value);
LLPointer<LLInventoryCallback> cb;
LLInventoryModel::LLCategoryUpdate up(mItem->getParentUUID(), 0);
gInventory.accountForUpdate(up);
update_inventory_item(new_item, cb);
}
}
void LLFloaterCreateLandmark::onCreateFolderClicked()
{
LLNotificationsUtil::add("CreateLandmarkFolder", LLSD(), LLSD(),
[this](const LLSD&notif, const LLSD&resp)
{
S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp);
if (opt == 0)
{
std::string folder_name = resp["message"].asString();
if (!folder_name.empty())
{
inventory_func_type func = boost::bind(&LLFloaterCreateLandmark::folderCreatedCallback, this, _1);
gInventory.createNewCategory(mLandmarksID, LLFolderType::FT_NONE, folder_name, func);
gInventory.notifyObservers();
}
}
});
}
void LLFloaterCreateLandmark::folderCreatedCallback(LLUUID folder_id)
{
populateFoldersList(folder_id);
}
void LLFloaterCreateLandmark::onSaveClicked()
{
if (mItem.isNull())
{
closeFloater();
return;
}
std::string current_title_value = mLandmarkTitleEditor->getText();
std::string item_title_value = mItem->getName();
std::string current_notes_value = mNotesEditor->getText();
std::string item_notes_value = mItem->getDescription();
LLStringUtil::trim(current_title_value);
LLStringUtil::trim(current_notes_value);
LLUUID folder_id = mFolderCombo->getValue().asUUID();
bool change_parent = folder_id != mItem->getParentUUID();
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(mItem);
if (!current_title_value.empty() &&
(item_title_value != current_title_value || item_notes_value != current_notes_value))
{
new_item->rename(current_title_value);
new_item->setDescription(current_notes_value);
LLPointer<LLInventoryCallback> cb;
if (change_parent)
{
cb = new LLUpdateLandmarkParent(new_item, folder_id);
}
LLInventoryModel::LLCategoryUpdate up(mItem->getParentUUID(), 0);
gInventory.accountForUpdate(up);
update_inventory_item(new_item, cb);
}
else if (change_parent)
{
LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(),-1);
update.push_back(old_folder);
LLInventoryModel::LLCategoryUpdate new_folder(folder_id, 1);
update.push_back(new_folder);
gInventory.accountForUpdate(update);
new_item->setParent(folder_id);
new_item->updateParentOnServer(false);
}
removeObserver();
gInventory.updateItem(new_item);
gInventory.notifyObservers();
closeFloater();
}
void LLFloaterCreateLandmark::onCancelClicked()
{
removeObserver();
if (!mItem.isNull())
{
LLUUID item_id = mItem->getUUID();
remove_inventory_item(item_id, NULL);
}
closeFloater();
}
void LLFloaterCreateLandmark::setItem(const uuid_set_t& items)
{
for (uuid_set_t::const_iterator item_iter = items.begin();
item_iter != items.end();
++item_iter)
{
const LLUUID& item_id = (*item_iter);
if(!highlight_offered_object(item_id))
{
continue;
}
LLInventoryItem* item = gInventory.getItem(item_id);
llassert(item);
if (item && (LLAssetType::AT_LANDMARK == item->getType()) )
{
if(!getItem())
{
mItem = item;
mAssetID = mItem->getAssetUUID();
setVisibleAndFrontmost(true);
break;
}
}
}
}
void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask)
{
if (!getItem())
{
return;
}
LLUUID landmark_id = getItem()->getUUID();
for (uuid_set_t::const_iterator item_iter = items.begin();
item_iter != items.end();
++item_iter)
{
const LLUUID& item_id = (*item_iter);
if (landmark_id == item_id)
{
if (getItem() != gInventory.getItem(item_id))
{
// item is obsolete or removed
closeFloater();
}
LLUUID folder_id = mFolderCombo->getValue().asUUID();
if (folder_id != mItem->getParentUUID())
{
// user moved landmark in inventory,
// assume that we are done all other changes should already be commited
closeFloater();
}
if ((mask & LLInventoryObserver::INTERNAL) && mAssetID != mItem->getAssetUUID())
{
closeFloater();
}
if (mask & LLInventoryObserver::LABEL)
{
mLandmarkTitleEditor->setText(mItem->getName());
}
if (mask & LLInventoryObserver::INTERNAL)
{
mNotesEditor->setText(mItem->getDescription());
}
}
}
}