SL-14900 new Landmark creation flow

meow-7.2.2
Mnikolenko Productengine 2021-03-23 17:38:22 +02:00
parent 38db12920c
commit d43d8bc68b
14 changed files with 567 additions and 48 deletions

View File

@ -233,6 +233,7 @@ set(viewer_SOURCE_FILES
llfloatercolorpicker.cpp
llfloaterconversationlog.cpp
llfloaterconversationpreview.cpp
llfloatercreatelandmark.cpp
llfloaterdeleteprefpreset.cpp
llfloaterdestinations.cpp
llfloatereditextdaycycle.cpp
@ -865,6 +866,7 @@ set(viewer_HEADER_FILES
llfloatercolorpicker.h
llfloaterconversationlog.h
llfloaterconversationpreview.h
llfloatercreatelandmark.h
llfloaterdeleteprefpreset.h
llfloaterdestinations.h
llfloatereditextdaycycle.h

View File

@ -0,0 +1,314 @@
/**
* @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 LLInventoryAddedObserver
{
public:
LLLandmarksInventoryObserver(LLFloaterCreateLandmark* create_landmark_floater) :
mFloater(create_landmark_floater)
{}
protected:
/*virtual*/ void done()
{
mFloater->setItem(gInventory.getAddedIDs());
}
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));
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);
}
LLLandmarkActions::createLandmarkHere(name, "", folder_id.notNull() ? folder_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));
}
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.
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());
}
// 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());
}
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::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);
LLUUID test = 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())
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 item_id = mItem->getUUID();
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);
}
gInventory.updateItem(new_item);
gInventory.notifyObservers();
closeFloater();
}
void LLFloaterCreateLandmark::onCancelClicked()
{
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())
{
removeObserver();
mItem = item;
break;
}
}
}
}

View File

@ -0,0 +1,75 @@
/**
* @file llfloatercreatelandmark.h
* @brief LLFloaterCreateLandmark class definition
*
* $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$
*/
#ifndef LL_LLFLOATERCREATELANDMARK_H
#define LL_LLFLOATERCREATELANDMARK_H
#include "llfloater.h"
class LLComboBox;
class LLInventoryItem;
class LLLineEditor;
class LLTextEditor;
class LLLandmarksInventoryObserver;
class LLFloaterCreateLandmark:
public LLFloater
{
friend class LLFloaterReg;
public:
LLFloaterCreateLandmark(const LLSD& key);
~LLFloaterCreateLandmark();
BOOL postBuild();
void onOpen(const LLSD& key);
void setItem(const uuid_set_t& items);
LLInventoryItem* getItem() { return mItem; }
private:
void setLandmarkInfo(const LLUUID &folder_id);
void removeObserver();
void populateFoldersList(const LLUUID &folder_id = LLUUID::null);
void onCreateFolderClicked();
void onSaveClicked();
void onCancelClicked();
void folderCreatedCallback(LLUUID folder_id);
LLComboBox* mFolderCombo;
LLLineEditor* mLandmarkTitleEditor;
LLTextEditor* mNotesEditor;
LLUUID mLandmarksID;
LLUUID mItemID;
LLLandmarksInventoryObserver* mInventoryObserver;
LLPointer<LLInventoryItem> mItem;
};
#endif

View File

@ -44,6 +44,7 @@
// newview includes
#include "llagent.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llinventoryobserver.h"
#include "lllandmarkactions.h"
@ -653,7 +654,7 @@ void LLLocationInputCtrl::onAddLandmarkButtonClicked()
}
else
{
LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
LLFloaterReg::showInstance("add_landmark");
}
}
@ -1126,7 +1127,7 @@ void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata)
if(!landmark)
{
LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
LLFloaterReg::showInstance("add_landmark");
}
else
{

View File

@ -52,7 +52,6 @@
typedef std::pair<LLUUID, std::string> folder_pair_t;
static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right);
static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats);
static LLPanelInjector<LLPanelLandmarkInfo> t_landmark_info("panel_landmark_info");
@ -516,7 +515,7 @@ static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right)
return left.second < right.second;
}
static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)
void LLPanelLandmarkInfo::collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)
{
LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
@ -529,16 +528,20 @@ static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)
items,
LLInventoryModel::EXCLUDE_TRASH,
is_category);
// Add the "My Favorites" category.
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
{
cats.push_back(favorites_cat);
}
}
/* virtual */ void LLUpdateLandmarkParent::fire(const LLUUID& inv_item_id)
{
LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(), -1);
update.push_back(old_folder);
LLInventoryModel::LLCategoryUpdate new_folder(mNewParentId, 1);
update.push_back(new_folder);
gInventory.accountForUpdate(update);
mItem->setParent(mNewParentId);
mItem->updateParentOnServer(FALSE);
gInventory.updateItem(mItem);
gInventory.notifyObservers();
}

View File

@ -28,6 +28,7 @@
#define LL_LLPANELLANDMARKINFO_H
#include "llpanelplaceinfo.h"
#include "llinventorymodel.h"
class LLComboBox;
class LLLineEditor;
@ -63,7 +64,9 @@ public:
// Select current landmark folder in combobox.
BOOL setLandmarkFolder(const LLUUID& id);
typedef std::vector<LLPointer<LLViewerInventoryCategory> > cat_array_t;
static std::string getFullFolderName(const LLViewerInventoryCategory* cat);
static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats);
private:
// Create a landmark for the current location
@ -85,4 +88,17 @@ private:
LLComboBox* mFolderCombo;
};
class LLUpdateLandmarkParent : public LLInventoryCallback
{
public:
LLUpdateLandmarkParent(LLPointer<LLViewerInventoryItem> item, LLUUID new_parent) :
mItem(item),
mNewParentId(new_parent)
{};
/* virtual */ void fire(const LLUUID& inv_item_id);
private:
LLPointer<LLViewerInventoryItem> mItem;
LLUUID mNewParentId;
};
#endif // LL_LLPANELLANDMARKINFO_H

View File

@ -500,7 +500,7 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const
{
args["dest_folder"] = view_model->getUUID();
}
LLFloaterSidePanelContainer::showPanel("places", args);
LLFloaterReg::showInstance("add_landmark", args);
}
}
else if ("category" == command_name)

View File

@ -773,34 +773,6 @@ void LLPanelPlaces::onEditButtonClicked()
updateVerbs();
}
class LLUpdateLandmarkParent : public LLInventoryCallback
{
public:
LLUpdateLandmarkParent(LLPointer<LLViewerInventoryItem> item, LLUUID new_parent) :
mItem(item),
mNewParentId(new_parent)
{};
/* virtual */ void fire(const LLUUID& inv_item_id)
{
LLInventoryModel::update_list_t update;
LLInventoryModel::LLCategoryUpdate old_folder(mItem->getParentUUID(), -1);
update.push_back(old_folder);
LLInventoryModel::LLCategoryUpdate new_folder(mNewParentId, 1);
update.push_back(new_folder);
gInventory.accountForUpdate(update);
mItem->setParent(mNewParentId);
mItem->updateParentOnServer(FALSE);
gInventory.updateItem(mItem);
gInventory.notifyObservers();
}
private:
LLPointer<LLViewerInventoryItem> mItem;
LLUUID mNewParentId;
};
void LLPanelPlaces::onSaveButtonClicked()
{
if (!mLandmarkInfo || mItem.isNull())

View File

@ -31,6 +31,7 @@
#include "llagent.h"
#include "llagentui.h"
#include "llclipboard.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "lllandmarkactions.h"
#include "lllocationinputctrl.h"
@ -456,7 +457,7 @@ void LLPanelTopInfoBar::onContextMenuItemClicked(const LLSD::String& item)
if(landmark == NULL)
{
LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
LLFloaterReg::showInstance("add_landmark");
}
else
{

View File

@ -291,7 +291,7 @@ LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal
mLineEditor->setText(edit_text_contents);
std::string notif_name = mNotification->getName();
if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name))
if (("SaveOutfitAs" == notif_name) || ("SaveSettingAs" == notif_name) || ("CreateLandmarkFolder" == notif_name))
{
mLineEditor->setPrevalidate(&LLTextValidate::validateASCII);
}

View File

@ -58,6 +58,7 @@
#include "llfloaterchatvoicevolume.h"
#include "llfloaterconversationlog.h"
#include "llfloaterconversationpreview.h"
#include "llfloatercreatelandmark.h"
#include "llfloaterdeleteprefpreset.h"
#include "llfloaterdestinations.h"
#include "llfloatereditextdaycycle.h"
@ -222,6 +223,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater);
LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);
LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);
LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>);
LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>);
LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>);

View File

@ -6042,7 +6042,7 @@ class LLWorldCreateLandmark : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "create_landmark"));
LLFloaterReg::showInstance("add_landmark");
return true;
}

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<floater
can_resize="false"
show_title="false"
can_minimize="false"
can_close="false"
height="305"
layout="topleft"
name="create_landmark"
width="330">
<string name="favorites_bar">
Favorites bar
</string>
<text
follows="left|top"
height="15"
layout="topleft"
left="20"
name="title_label"
top="5"
font="SansSerifLargeBold"
value="Landmark added"
width="290" />
<text
follows="left|top"
height="15"
layout="topleft"
left="20"
name="name_label"
top_pad="10"
value="Name"
width="290" />
<line_editor
follows="left|top"
height="22"
layout="topleft"
max_length_bytes="63"
name="title_editor"
prevalidate_callback="ascii"
text_readonly_color="white"
top_pad="5"
width="290" />
<text
follows="left|top"
height="15"
layout="topleft"
name="folder_label"
top_pad="10"
value="Landmark location:"
width="290" />
<combo_box
follows="bottom|left"
height="23"
layout="topleft"
name="folder_combo"
top_pad="2"
width="290" />
<text
follows="left|top"
layout="topleft"
top_pad="6"
left="20"
name="new_folder_textbox"
height="20"
parse_urls="true"
skip_link_underline="true"
wrap="true">
[secondlife:/// Create new folder]
</text>
<text
follows="left|top"
height="15"
layout="topleft"
name="notes_label"
top_pad="10"
value="My notes"
width="290" />
<text_editor
bg_readonly_color="DkGray0"
follows="all"
height="75"
layout="topleft"
max_length="127"
name="notes_editor"
spellcheck="true"
text_readonly_color="white"
text_type="ascii_with_newline"
top_pad="5"
width="290"
wrap="true" />
<button
follows="bottom|left|right"
height="23"
label="OK"
layout="topleft"
mouse_opaque="false"
name="ok_btn"
top_pad="10"
left="19"
width="140" />
<button
follows="bottom|left|right"
height="23"
label="Cancel"
layout="topleft"
left_pad="12"
mouse_opaque="false"
name="cancel_btn"
width="140" />
</floater>

View File

@ -2319,6 +2319,29 @@ You cannot create a landmark here because the owner of the land doesn&apos;t all
<tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
label="Create folder"
name="CreateLandmarkFolder"
type="alertmodal">
<unique/>
Choose a name for the folder:
<tag>confirm</tag>
<form name="form">
<input name="message" type="text">
</input>
<button
default="true"
index="0"
name="OK"
text="OK"/>
<button
index="1"
name="Cancel"
text="Cancel"/>
</form>
</notification>
<notification
icon="alertmodal.tga"
name="CannotRecompileSelectObjectsNoScripts"