summaryrefslogtreecommitdiff
path: root/indra/newview/llfloatergesture.cpp
diff options
context:
space:
mode:
authorAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
committerAnsariel <ansariel.hiller@phoenixviewer.com>2024-05-22 19:04:52 +0200
commit1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch)
treeab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llfloatergesture.cpp
parent6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff)
parente1623bb276f83a43ce7a197e388720c05bdefe61 (diff)
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts: # autobuild.xml # indra/cmake/CMakeLists.txt # indra/cmake/GoogleMock.cmake # indra/llaudio/llaudioengine_fmodstudio.cpp # indra/llaudio/llaudioengine_fmodstudio.h # indra/llaudio/lllistener_fmodstudio.cpp # indra/llaudio/lllistener_fmodstudio.h # indra/llaudio/llstreamingaudio_fmodstudio.cpp # indra/llaudio/llstreamingaudio_fmodstudio.h # indra/llcharacter/llmultigesture.cpp # indra/llcharacter/llmultigesture.h # indra/llimage/llimage.cpp # indra/llimage/llimagepng.cpp # indra/llimage/llimageworker.cpp # indra/llimage/tests/llimageworker_test.cpp # indra/llmessage/tests/llmockhttpclient.h # indra/llprimitive/llgltfmaterial.h # indra/llrender/llfontfreetype.cpp # indra/llui/llcombobox.cpp # indra/llui/llfolderview.cpp # indra/llui/llfolderviewmodel.h # indra/llui/lllineeditor.cpp # indra/llui/lllineeditor.h # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/llui/lltextvalidate.cpp # indra/llui/lltextvalidate.h # indra/llui/lluictrl.h # indra/llui/llview.cpp # indra/llwindow/llwindowmacosx.cpp # indra/newview/app_settings/settings.xml # indra/newview/llappearancemgr.cpp # indra/newview/llappearancemgr.h # indra/newview/llavatarpropertiesprocessor.cpp # indra/newview/llavatarpropertiesprocessor.h # indra/newview/llbreadcrumbview.cpp # indra/newview/llbreadcrumbview.h # indra/newview/llbreastmotion.cpp # indra/newview/llbreastmotion.h # indra/newview/llconversationmodel.h # indra/newview/lldensityctrl.cpp # indra/newview/lldensityctrl.h # indra/newview/llface.inl # indra/newview/llfloatereditsky.cpp # indra/newview/llfloatereditwater.cpp # indra/newview/llfloateremojipicker.h # indra/newview/llfloaterimsessiontab.cpp # indra/newview/llfloaterprofiletexture.cpp # indra/newview/llfloaterprofiletexture.h # indra/newview/llgesturemgr.cpp # indra/newview/llgesturemgr.h # indra/newview/llimpanel.cpp # indra/newview/llimpanel.h # indra/newview/llinventorybridge.cpp # indra/newview/llinventorybridge.h # indra/newview/llinventoryclipboard.cpp # indra/newview/llinventoryclipboard.h # indra/newview/llinventoryfunctions.cpp # indra/newview/llinventoryfunctions.h # indra/newview/llinventorygallery.cpp # indra/newview/lllistbrowser.cpp # indra/newview/lllistbrowser.h # indra/newview/llpanelobjectinventory.cpp # indra/newview/llpanelprofile.cpp # indra/newview/llpanelprofile.h # indra/newview/llpreviewgesture.cpp # indra/newview/llsavedsettingsglue.cpp # indra/newview/llsavedsettingsglue.h # indra/newview/lltooldraganddrop.cpp # indra/newview/llurllineeditorctrl.cpp # indra/newview/llvectorperfoptions.cpp # indra/newview/llvectorperfoptions.h # indra/newview/llviewerparceloverlay.cpp # indra/newview/llviewertexlayer.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/macmain.h # indra/test/test.cpp
Diffstat (limited to 'indra/newview/llfloatergesture.cpp')
-rw-r--r--indra/newview/llfloatergesture.cpp1426
1 files changed, 713 insertions, 713 deletions
diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp
index f0dd7be67b..161bacfa60 100644
--- a/indra/newview/llfloatergesture.cpp
+++ b/indra/newview/llfloatergesture.cpp
@@ -1,713 +1,713 @@
-/**
- * @file llfloatergesture.cpp
- * @brief Read-only list of gestures from your inventory.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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 "llfloatergesture.h"
-
-#include "llinventory.h"
-#include "llinventorybridge.h"
-#include "llinventoryfunctions.h"
-#include "llinventorymodel.h"
-#include "llclipboard.h"
-
-#include "llagent.h"
-#include "llappearancemgr.h"
-#include "llclipboard.h"
-#include "llgesturemgr.h"
-#include "llkeyboard.h"
-#include "llmenugl.h"
-#include "llmultigesture.h"
-#include "llnotificationsutil.h"
-#include "llpreviewgesture.h"
-#include "llscrolllistctrl.h"
-#include "lltrans.h"
-#include "llviewergesture.h"
-#include "llviewermenu.h"
-#include "llviewerinventory.h"
-#include "llviewercontrol.h"
-#include "llfloaterperms.h"
-
-bool item_name_precedes( LLInventoryItem* a, LLInventoryItem* b )
-{
- return LLStringUtil::precedesDict( a->getName(), b->getName() );
-}
-
-class LLFloaterGestureObserver : public LLGestureManagerObserver
-{
-public:
- LLFloaterGestureObserver(LLFloaterGesture* floater) : mFloater(floater) {}
- virtual ~LLFloaterGestureObserver() {}
- virtual void changed() { mFloater->refreshAll(); }
-
-private:
- LLFloaterGesture* mFloater;
-};
-//-----------------------------
-// GestureCallback
-//-----------------------------
-
-class GestureShowCallback : public LLInventoryCallback
-{
-public:
- void fire(const LLUUID &inv_item)
- {
- LLPreviewGesture::show(inv_item, LLUUID::null);
-
- LLInventoryItem* item = gInventory.getItem(inv_item);
- if (item)
- {
- LLPermissions perm = item->getPermissions();
- perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Gestures"));
- perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures"));
- perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures"));
- item->setPermissions(perm);
- item->updateServer(false);
- }
- }
-};
-
-class GestureCopiedCallback : public LLInventoryCallback
-{
-private:
- LLFloaterGesture* mFloater;
-
-public:
- GestureCopiedCallback(LLFloaterGesture* floater): mFloater(floater)
- {}
- void fire(const LLUUID &inv_item)
- {
- if(mFloater)
- {
- mFloater->addGesture(inv_item,NULL,mFloater->getChild<LLScrollListCtrl>("gesture_list"));
-
- // EXP-1909 (Pasted gesture displayed twice)
- // The problem is that addGesture is called here for the second time for the same item (which is copied)
- // First time addGesture is called from LLFloaterGestureObserver::changed(), which is a callback for inventory
- // change. So we need to refresh the gesture list to avoid duplicates.
- mFloater->refreshAll();
- }
- }
-};
-
-//---------------------------------------------------------------------------
-// LLFloaterGesture
-//---------------------------------------------------------------------------
-LLFloaterGesture::LLFloaterGesture(const LLSD& key)
- : LLFloater(key)
-{
- mObserver = new LLFloaterGestureObserver(this);
- LLGestureMgr::instance().addObserver(mObserver);
-
- mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
- mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this));
- mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2));
- mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this));
- mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this));
-
- mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2));
-}
-
-void LLFloaterGesture::done()
-{
- //this method can be called twice: for GestureFolder and once after loading all sudir of GestureFolder
- if (gInventory.isCategoryComplete(mGestureFolderID))
- {
- LL_DEBUGS("Gesture")<< "mGestureFolderID loaded" << LL_ENDL;
- // we load only gesture folder without childred.
- LLInventoryModel::cat_array_t* categories;
- LLInventoryModel::item_array_t* items;
- uuid_vec_t unloaded_folders;
- LL_DEBUGS("Gesture")<< "Get subdirs of Gesture Folder...." << LL_ENDL;
- gInventory.getDirectDescendentsOf(mGestureFolderID, categories, items);
- if (categories->empty())
- {
- gInventory.removeObserver(this);
- LL_INFOS("Gesture")<< "Gesture dos NOT contains sub-directories."<< LL_ENDL;
- return;
- }
- LL_DEBUGS("Gesture")<< "There are " << categories->size() << " Folders "<< LL_ENDL;
- for (LLInventoryModel::cat_array_t::iterator it = categories->begin(); it != categories->end(); it++)
- {
- if (!gInventory.isCategoryComplete(it->get()->getUUID()))
- {
- unloaded_folders.push_back(it->get()->getUUID());
- LL_DEBUGS("Gesture")<< it->get()->getName()<< " Folder added to fetchlist"<< LL_ENDL;
- }
-
- }
- if (!unloaded_folders.empty())
- {
- LL_DEBUGS("Gesture")<< "Fetching subdirectories....." << LL_ENDL;
- setFetchIDs(unloaded_folders);
- startFetch();
- }
- else
- {
- LL_DEBUGS("Gesture")<< "All Gesture subdirectories have been loaded."<< LL_ENDL;
- gInventory.removeObserver(this);
- buildGestureList();
- }
- }
- else
- {
- LL_WARNS("Gesture")<< "Gesture list was NOT loaded"<< LL_ENDL;
- }
-}
-
-// virtual
-LLFloaterGesture::~LLFloaterGesture()
-{
- LLGestureMgr::instance().removeObserver(mObserver);
- delete mObserver;
- mObserver = NULL;
- gInventory.removeObserver(this);
-}
-
-// virtual
-bool LLFloaterGesture::postBuild()
-{
- std::string label;
-
- label = getTitle();
-
- setTitle(label);
- mGestureList = getChild<LLScrollListCtrl>("gesture_list");
- mGestureList->setCommitCallback(boost::bind(&LLFloaterGesture::onCommitList, this));
- mGestureList->setDoubleClickCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
-
- getChild<LLUICtrl>("edit_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickEdit, this));
-
- getChild<LLUICtrl>("play_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
- getChild<LLUICtrl>("stop_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
- getChild<LLButton>("activate_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
-
- getChild<LLUICtrl>("new_gesture_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickNew, this));
- getChild<LLButton>("del_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onDeleteSelected, this));
-
- getChildView("play_btn")->setVisible( true);
- getChildView("stop_btn")->setVisible( false);
- setDefaultBtn("play_btn");
- mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
-
- uuid_vec_t folders;
- folders.push_back(mGestureFolderID);
- //perform loading Gesture directory anyway to make sure that all subdirectory are loaded too. See method done() for details.
- gInventory.addObserver(this);
- setFetchIDs(folders);
- startFetch();
-
- if (mGestureList)
- {
- buildGestureList();
-
- mGestureList->setFocus(true);
-
- constexpr bool ascending = true;
- mGestureList->sortByColumn(std::string("name"), ascending);
- mGestureList->selectFirstItem();
- }
-
- // Update button labels
- onCommitList();
-
- return true;
-}
-
-
-void LLFloaterGesture::refreshAll()
-{
- if (!mGestureList) return;
-
- buildGestureList();
-
- if (mSelectedID.isNull())
- {
- mGestureList->selectFirstItem();
- }
- else
- {
- if (! mGestureList->setCurrentByID(mSelectedID))
- {
- mGestureList->selectFirstItem();
- }
- }
-
- // Update button labels
- onCommitList();
-}
-
-void LLFloaterGesture::buildGestureList()
-{
- S32 scroll_pos = mGestureList->getScrollPos();
- uuid_vec_t selected_items;
- getSelectedIds(selected_items);
- LL_DEBUGS("Gesture")<< "Rebuilding gesture list "<< LL_ENDL;
- mGestureList->deleteAllItems();
-
- LLGestureMgr::item_map_t::const_iterator it;
- const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures();
- for (it = active_gestures.begin(); it != active_gestures.end(); ++it)
- {
- addGesture(it->first,it->second, mGestureList);
- }
- if (gInventory.isCategoryComplete(mGestureFolderID))
- {
- LLIsType is_gesture(LLAssetType::AT_GESTURE);
- LLInventoryModel::cat_array_t categories;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendentsIf(mGestureFolderID, categories, items,
- LLInventoryModel::EXCLUDE_TRASH, is_gesture);
-
- for (LLInventoryModel::item_array_t::iterator it = items.begin(); it!= items.end(); ++it)
- {
- LLInventoryItem* item = it->get();
- if (active_gestures.find(item->getUUID()) == active_gestures.end())
- {
- // if gesture wasn't loaded yet, we can display only name
- addGesture(item->getUUID(), NULL, mGestureList);
- }
- }
- }
-
- // attempt to preserve scroll position through re-builds
- // since we do re-build whenever something gets dirty
- for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++)
- {
- mGestureList->selectByID(*it);
- }
- mGestureList->setScrollPos(scroll_pos);
-}
-
-void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gesture,LLCtrlListInterface * list )
-{
- // Note: Can have NULL item if inventory hasn't arrived yet.
- static std::string item_name = getString("loading");
- LLInventoryItem* item = gInventory.getItem(item_id);
- if (item)
- {
- item_name = item->getName();
- }
-
- static std::string font_style = "NORMAL";
- // If gesture is playing, bold it
-
- LLSD element;
- element["id"] = item_id;
-
- if (gesture)
- {
- if (gesture->mPlaying)
- {
- font_style = "BOLD";
- }
- item_name = gesture->mName;
- element["columns"][0]["column"] = "trigger";
- element["columns"][0]["value"] = gesture->mTrigger;
- element["columns"][0]["font"]["name"] = "SANSSERIF";
- element["columns"][0]["font"]["style"] = font_style;
-
- std::string key_string;
- std::string buffer;
-
- if (gesture->mKey == KEY_NONE)
- {
- buffer = "---";
- key_string = "~~~"; // alphabetize to end
- }
- else
- {
- key_string = LLKeyboard::stringFromKey(gesture->mKey);
- buffer = LLKeyboard::stringFromAccelerator(gesture->mMask,
- gesture->mKey);
- }
-
- element["columns"][1]["column"] = "shortcut";
- element["columns"][1]["value"] = buffer;
- element["columns"][1]["font"]["name"] = "SANSSERIF";
- element["columns"][1]["font"]["style"] = font_style;
-
- // hidden column for sorting
- element["columns"][2]["column"] = "key";
- element["columns"][2]["value"] = key_string;
- element["columns"][2]["font"]["name"] = "SANSSERIF";
- element["columns"][2]["font"]["style"] = font_style;
-
- // Only add "playing" if we've got the name, less confusing. JC
- if (item && gesture->mPlaying)
- {
- item_name += " " + getString("playing");
- }
- element["columns"][3]["column"] = "name";
- element["columns"][3]["value"] = item_name;
- element["columns"][3]["font"]["name"] = "SANSSERIF";
- element["columns"][3]["font"]["style"] = font_style;
- }
- else
- {
- element["columns"][0]["column"] = "trigger";
- element["columns"][0]["value"] = "";
- element["columns"][0]["font"]["name"] = "SANSSERIF";
- element["columns"][0]["font"]["style"] = font_style;
- element["columns"][1]["column"] = "shortcut";
- element["columns"][1]["value"] = "---";
- element["columns"][1]["font"]["name"] = "SANSSERIF";
- element["columns"][1]["font"]["style"] = font_style;
- element["columns"][2]["column"] = "key";
- element["columns"][2]["value"] = "~~~";
- element["columns"][2]["font"]["name"] = "SANSSERIF";
- element["columns"][2]["font"]["style"] = font_style;
- element["columns"][3]["column"] = "name";
- element["columns"][3]["value"] = item_name;
- element["columns"][3]["font"]["name"] = "SANSSERIF";
- element["columns"][3]["font"]["style"] = font_style;
- }
-
- LL_DEBUGS("Gesture") << "Added gesture [" << item_name << "]" << LL_ENDL;
-
- LLScrollListItem* sl_item = list->addElement(element, ADD_BOTTOM);
- if(sl_item)
- {
- LLFontGL::StyleFlags style = LLGestureMgr::getInstance()->isGestureActive(item_id) ? LLFontGL::BOLD : LLFontGL::NORMAL;
- // *TODO find out why ["font"]["style"] does not affect font style
- ((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(style);
- }
-}
-
-void LLFloaterGesture::getSelectedIds(uuid_vec_t& ids)
-{
- std::vector<LLScrollListItem*> items = mGestureList->getAllSelected();
- for(std::vector<LLScrollListItem*>::const_iterator it = items.begin(); it != items.end(); it++)
- {
- ids.push_back((*it)->getUUID());
- }
-}
-
-bool LLFloaterGesture::isActionEnabled(const LLSD& command)
-{
- // paste copy_uuid edit_gesture
- std::string command_name = command.asString();
- if("paste" == command_name)
- {
- if(!LLClipboard::instance().hasContents())
- return false;
-
- std::vector<LLUUID> ids;
- LLClipboard::instance().pasteFromClipboard(ids);
- for(std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
- {
- LLInventoryItem* item = gInventory.getItem(*it);
-
- if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
- {
- return true;
- }
- }
- return false;
- }
- else if("copy_uuid" == command_name || "edit_gesture" == command_name)
- {
- return mGestureList->getAllSelected().size() == 1;
- }
- else if ("rename_gesture" == command_name)
- {
- if (mGestureList->getAllSelected().size() == 1)
- {
- LLViewerInventoryItem* item = gInventory.getItem(mGestureList->getCurrentID());
-
- if (item && item->getPermissions().allowModifyBy(gAgentID))
- {
- return true;
- }
- }
- return false;
- }
- return true;
-}
-
-void LLFloaterGesture::onClickPlay()
-{
- const LLUUID& item_id = mGestureList->getCurrentID();
- if(item_id.isNull()) return;
-
- LL_DEBUGS("Gesture")<<" Trying to play gesture id: "<< item_id <<LL_ENDL;
- if(!LLGestureMgr::instance().isGestureActive(item_id))
- {
- // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList.
- bool inform_server = true;
- bool deactivate_similar = false;
- LLGestureMgr::instance().setGestureLoadedCallback(item_id, boost::bind(&LLFloaterGesture::playGesture, this, item_id));
- LLViewerInventoryItem *item = gInventory.getItem(item_id);
- llassert(item);
- if (item)
- {
- LLGestureMgr::instance().activateGestureWithAsset(item_id, item->getAssetUUID(), inform_server, deactivate_similar);
- LL_DEBUGS("Gesture")<< "Activating gesture with inventory ID: " << item_id <<LL_ENDL;
- }
- }
- else
- {
- playGesture(item_id);
- }
-}
-
-void LLFloaterGesture::onClickNew()
-{
- LLPointer<LLInventoryCallback> cb = new GestureShowCallback();
- create_inventory_item(gAgent.getID(),
- gAgent.getSessionID(),
- LLUUID::null,
- LLTransactionID::tnull,
- "New Gesture",
- "",
- LLAssetType::AT_GESTURE,
- LLInventoryType::IT_GESTURE,
- NO_INV_SUBTYPE,
- PERM_MOVE | LLFloaterPerms::getNextOwnerPerms("Gestures"),
- cb);
-}
-
-void LLFloaterGesture::onActivateBtnClick()
-{
- uuid_vec_t ids;
- getSelectedIds(ids);
- if(ids.empty())
- return;
-
- LLGestureMgr* gm = LLGestureMgr::getInstance();
- uuid_vec_t::const_iterator it = ids.begin();
- bool first_gesture_state = gm->isGestureActive(*it);
- bool is_mixed = false;
- while( ++it != ids.end() )
- {
- if(first_gesture_state != gm->isGestureActive(*it))
- {
- is_mixed = true;
- break;
- }
- }
- for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
- {
- if(is_mixed)
- {
- gm->activateGesture(*it);
- }
- else
- {
- if(first_gesture_state)
- {
- gm->deactivateGesture(*it);
- }
- else
- {
- gm->activateGesture(*it);
- }
- }
- }
-}
-
-void LLFloaterGesture::onRenameSelected()
-{
- LLViewerInventoryItem* gesture = gInventory.getItem(mGestureList->getCurrentID());
- if (!gesture)
- {
- return;
- }
-
- LLSD args;
- args["NAME"] = gesture->getName();
-
- LLSD payload;
- payload["gesture_id"] = mGestureList->getCurrentID();
-
- LLNotificationsUtil::add("RenameGesture", args, payload, boost::bind(onGestureRename, _1, _2));
-
-}
-
-void LLFloaterGesture::onGestureRename(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0) return; // canceled
-
- std::string new_name = response["new_name"].asString();
- LLInventoryObject::correctInventoryName(new_name);
- if (!new_name.empty())
- {
- LLUUID item_id = notification["payload"]["gesture_id"].asUUID();
- LLViewerInventoryItem* gesture = gInventory.getItem(item_id);
- if (gesture && (gesture->getName() != new_name))
- {
- LLSD updates;
- updates["name"] = new_name;
- update_inventory_item(item_id, updates, NULL);
- }
- }
-}
-
-void LLFloaterGesture::onCopyPasteAction(const LLSD& command)
-{
- std::string command_name = command.asString();
- // Since we select this command, the inventory items must have already arrived
- if("copy_gesture" == command_name)
- {
- uuid_vec_t ids;
- getSelectedIds(ids);
- // Make sure the clipboard is empty
- LLClipboard::instance().reset();
- for(uuid_vec_t::iterator it = ids.begin(); it != ids.end(); it++)
- {
- LLInventoryItem* item = gInventory.getItem(*it);
- if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
- {
- LLClipboard::instance().addToClipboard(*it);
- }
- }
- }
- else if ("paste" == command_name)
- {
- std::vector<LLUUID> ids;
- LLClipboard::instance().pasteFromClipboard(ids);
- if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID))
- return;
- LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID);
- llassert(gesture_dir);
- LLPointer<GestureCopiedCallback> cb = new GestureCopiedCallback(this);
-
- for(std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
- {
- LLInventoryItem* item = gInventory.getItem(*it);
- if(gesture_dir && item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[COPY_NAME]"] = item->getName();
- LL_DEBUGS("Gesture")<< "Copying gesture " << item->getName() << " "<< item->getUUID() << " into "
- << gesture_dir->getName() << " "<< gesture_dir->getUUID() << LL_ENDL;
- copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(),
- gesture_dir->getUUID(), getString("copy_name", string_args), cb);
- }
- }
- LLClipboard::instance().reset();
- }
- else if ("copy_uuid" == command_name)
- {
- LLClipboard::instance().copyToClipboard(mGestureList->getCurrentID(),LLAssetType::AT_GESTURE);
- }
-}
-
-void LLFloaterGesture::onClickEdit()
-{
- const LLUUID& item_id = mGestureList->getCurrentID();
-
- LLInventoryItem* item = gInventory.getItem(item_id);
- if (!item) return;
-
- LLPreviewGesture* previewp = LLPreviewGesture::show(item_id, LLUUID::null);
- if (!previewp->getHost())
- {
- previewp->setRect(gFloaterView->findNeighboringPosition(this, previewp));
- }
-}
-
-void LLFloaterGesture::onCommitList()
-{
- const LLUUID& item_id = mGestureList->getCurrentID();
-
- mSelectedID = item_id;
- if (LLGestureMgr::instance().isGesturePlaying(item_id))
- {
- getChildView("play_btn")->setVisible( false);
- getChildView("stop_btn")->setVisible( true);
- }
- else
- {
- getChildView("play_btn")->setVisible( true);
- getChildView("stop_btn")->setVisible( false);
- }
-}
-
-void LLFloaterGesture::onDeleteSelected()
-{
- uuid_vec_t ids;
- getSelectedIds(ids);
- if(ids.empty())
- return;
-
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- LLGestureMgr* gm = LLGestureMgr::getInstance();
- for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
- {
- const LLUUID& selected_item = *it;
- LLInventoryItem* inv_item = gInventory.getItem(selected_item);
- if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_GESTURE)
- {
- if(gm->isGestureActive(selected_item))
- {
- gm->deactivateGesture(selected_item);
- }
- LLInventoryModel::update_list_t update;
- LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
- update.push_back(old_folder);
- LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
- update.push_back(new_folder);
- gInventory.accountForUpdate(update);
-
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
- new_item->setParent(trash_id);
- // no need to restamp it though it's a move into trash because
- // it's a brand new item already.
- new_item->updateParentOnServer(false);
- gInventory.updateItem(new_item);
- }
- }
- gInventory.notifyObservers();
- buildGestureList();
-}
-
-void LLFloaterGesture::addToCurrentOutFit()
-{
- uuid_vec_t ids;
- getSelectedIds(ids);
- LLAppearanceMgr* am = LLAppearanceMgr::getInstance();
- LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
- for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
- {
- am->addCOFItemLink(*it, cb);
- }
-}
-
-void LLFloaterGesture::playGesture(LLUUID item_id)
-{
- LL_DEBUGS("Gesture")<<"Playing gesture "<< item_id<<LL_ENDL;
-
- if (LLGestureMgr::instance().isGesturePlaying(item_id))
- {
- LLGestureMgr::instance().stopGesture(item_id);
- }
- else
- {
- LLGestureMgr::instance().playGesture(item_id);
- }
-}
+/**
+ * @file llfloatergesture.cpp
+ * @brief Read-only list of gestures from your inventory.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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 "llfloatergesture.h"
+
+#include "llinventory.h"
+#include "llinventorybridge.h"
+#include "llinventoryfunctions.h"
+#include "llinventorymodel.h"
+#include "llclipboard.h"
+
+#include "llagent.h"
+#include "llappearancemgr.h"
+#include "llclipboard.h"
+#include "llgesturemgr.h"
+#include "llkeyboard.h"
+#include "llmenugl.h"
+#include "llmultigesture.h"
+#include "llnotificationsutil.h"
+#include "llpreviewgesture.h"
+#include "llscrolllistctrl.h"
+#include "lltrans.h"
+#include "llviewergesture.h"
+#include "llviewermenu.h"
+#include "llviewerinventory.h"
+#include "llviewercontrol.h"
+#include "llfloaterperms.h"
+
+bool item_name_precedes( LLInventoryItem* a, LLInventoryItem* b )
+{
+ return LLStringUtil::precedesDict( a->getName(), b->getName() );
+}
+
+class LLFloaterGestureObserver : public LLGestureManagerObserver
+{
+public:
+ LLFloaterGestureObserver(LLFloaterGesture* floater) : mFloater(floater) {}
+ virtual ~LLFloaterGestureObserver() {}
+ virtual void changed() { mFloater->refreshAll(); }
+
+private:
+ LLFloaterGesture* mFloater;
+};
+//-----------------------------
+// GestureCallback
+//-----------------------------
+
+class GestureShowCallback : public LLInventoryCallback
+{
+public:
+ void fire(const LLUUID &inv_item)
+ {
+ LLPreviewGesture::show(inv_item, LLUUID::null);
+
+ LLInventoryItem* item = gInventory.getItem(inv_item);
+ if (item)
+ {
+ LLPermissions perm = item->getPermissions();
+ perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Gestures"));
+ perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures"));
+ perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures"));
+ item->setPermissions(perm);
+ item->updateServer(false);
+ }
+ }
+};
+
+class GestureCopiedCallback : public LLInventoryCallback
+{
+private:
+ LLFloaterGesture* mFloater;
+
+public:
+ GestureCopiedCallback(LLFloaterGesture* floater): mFloater(floater)
+ {}
+ void fire(const LLUUID &inv_item)
+ {
+ if(mFloater)
+ {
+ mFloater->addGesture(inv_item,NULL,mFloater->getChild<LLScrollListCtrl>("gesture_list"));
+
+ // EXP-1909 (Pasted gesture displayed twice)
+ // The problem is that addGesture is called here for the second time for the same item (which is copied)
+ // First time addGesture is called from LLFloaterGestureObserver::changed(), which is a callback for inventory
+ // change. So we need to refresh the gesture list to avoid duplicates.
+ mFloater->refreshAll();
+ }
+ }
+};
+
+//---------------------------------------------------------------------------
+// LLFloaterGesture
+//---------------------------------------------------------------------------
+LLFloaterGesture::LLFloaterGesture(const LLSD& key)
+ : LLFloater(key)
+{
+ mObserver = new LLFloaterGestureObserver(this);
+ LLGestureMgr::instance().addObserver(mObserver);
+
+ mCommitCallbackRegistrar.add("Gesture.Action.ToggleActiveState", boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.ShowPreview", boost::bind(&LLFloaterGesture::onClickEdit, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.CopyPaste", boost::bind(&LLFloaterGesture::onCopyPasteAction, this, _2));
+ mCommitCallbackRegistrar.add("Gesture.Action.SaveToCOF", boost::bind(&LLFloaterGesture::addToCurrentOutFit, this));
+ mCommitCallbackRegistrar.add("Gesture.Action.Rename", boost::bind(&LLFloaterGesture::onRenameSelected, this));
+
+ mEnableCallbackRegistrar.add("Gesture.EnableAction", boost::bind(&LLFloaterGesture::isActionEnabled, this, _2));
+}
+
+void LLFloaterGesture::done()
+{
+ //this method can be called twice: for GestureFolder and once after loading all sudir of GestureFolder
+ if (gInventory.isCategoryComplete(mGestureFolderID))
+ {
+ LL_DEBUGS("Gesture")<< "mGestureFolderID loaded" << LL_ENDL;
+ // we load only gesture folder without childred.
+ LLInventoryModel::cat_array_t* categories;
+ LLInventoryModel::item_array_t* items;
+ uuid_vec_t unloaded_folders;
+ LL_DEBUGS("Gesture")<< "Get subdirs of Gesture Folder...." << LL_ENDL;
+ gInventory.getDirectDescendentsOf(mGestureFolderID, categories, items);
+ if (categories->empty())
+ {
+ gInventory.removeObserver(this);
+ LL_INFOS("Gesture")<< "Gesture dos NOT contains sub-directories."<< LL_ENDL;
+ return;
+ }
+ LL_DEBUGS("Gesture")<< "There are " << categories->size() << " Folders "<< LL_ENDL;
+ for (LLInventoryModel::cat_array_t::iterator it = categories->begin(); it != categories->end(); it++)
+ {
+ if (!gInventory.isCategoryComplete(it->get()->getUUID()))
+ {
+ unloaded_folders.push_back(it->get()->getUUID());
+ LL_DEBUGS("Gesture")<< it->get()->getName()<< " Folder added to fetchlist"<< LL_ENDL;
+ }
+
+ }
+ if (!unloaded_folders.empty())
+ {
+ LL_DEBUGS("Gesture")<< "Fetching subdirectories....." << LL_ENDL;
+ setFetchIDs(unloaded_folders);
+ startFetch();
+ }
+ else
+ {
+ LL_DEBUGS("Gesture")<< "All Gesture subdirectories have been loaded."<< LL_ENDL;
+ gInventory.removeObserver(this);
+ buildGestureList();
+ }
+ }
+ else
+ {
+ LL_WARNS("Gesture")<< "Gesture list was NOT loaded"<< LL_ENDL;
+ }
+}
+
+// virtual
+LLFloaterGesture::~LLFloaterGesture()
+{
+ LLGestureMgr::instance().removeObserver(mObserver);
+ delete mObserver;
+ mObserver = NULL;
+ gInventory.removeObserver(this);
+}
+
+// virtual
+bool LLFloaterGesture::postBuild()
+{
+ std::string label;
+
+ label = getTitle();
+
+ setTitle(label);
+ mGestureList = getChild<LLScrollListCtrl>("gesture_list");
+ mGestureList->setCommitCallback(boost::bind(&LLFloaterGesture::onCommitList, this));
+ mGestureList->setDoubleClickCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
+
+ getChild<LLUICtrl>("edit_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickEdit, this));
+
+ getChild<LLUICtrl>("play_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
+ getChild<LLUICtrl>("stop_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this));
+ getChild<LLButton>("activate_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onActivateBtnClick, this));
+
+ getChild<LLUICtrl>("new_gesture_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickNew, this));
+ getChild<LLButton>("del_btn")->setClickedCallback(boost::bind(&LLFloaterGesture::onDeleteSelected, this));
+
+ getChildView("play_btn")->setVisible( true);
+ getChildView("stop_btn")->setVisible( false);
+ setDefaultBtn("play_btn");
+ mGestureFolderID = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
+
+ uuid_vec_t folders;
+ folders.push_back(mGestureFolderID);
+ //perform loading Gesture directory anyway to make sure that all subdirectory are loaded too. See method done() for details.
+ gInventory.addObserver(this);
+ setFetchIDs(folders);
+ startFetch();
+
+ if (mGestureList)
+ {
+ buildGestureList();
+
+ mGestureList->setFocus(true);
+
+ constexpr bool ascending = true;
+ mGestureList->sortByColumn(std::string("name"), ascending);
+ mGestureList->selectFirstItem();
+ }
+
+ // Update button labels
+ onCommitList();
+
+ return true;
+}
+
+
+void LLFloaterGesture::refreshAll()
+{
+ if (!mGestureList) return;
+
+ buildGestureList();
+
+ if (mSelectedID.isNull())
+ {
+ mGestureList->selectFirstItem();
+ }
+ else
+ {
+ if (! mGestureList->setCurrentByID(mSelectedID))
+ {
+ mGestureList->selectFirstItem();
+ }
+ }
+
+ // Update button labels
+ onCommitList();
+}
+
+void LLFloaterGesture::buildGestureList()
+{
+ S32 scroll_pos = mGestureList->getScrollPos();
+ uuid_vec_t selected_items;
+ getSelectedIds(selected_items);
+ LL_DEBUGS("Gesture")<< "Rebuilding gesture list "<< LL_ENDL;
+ mGestureList->deleteAllItems();
+
+ LLGestureMgr::item_map_t::const_iterator it;
+ const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures();
+ for (it = active_gestures.begin(); it != active_gestures.end(); ++it)
+ {
+ addGesture(it->first,it->second, mGestureList);
+ }
+ if (gInventory.isCategoryComplete(mGestureFolderID))
+ {
+ LLIsType is_gesture(LLAssetType::AT_GESTURE);
+ LLInventoryModel::cat_array_t categories;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendentsIf(mGestureFolderID, categories, items,
+ LLInventoryModel::EXCLUDE_TRASH, is_gesture);
+
+ for (LLInventoryModel::item_array_t::iterator it = items.begin(); it!= items.end(); ++it)
+ {
+ LLInventoryItem* item = it->get();
+ if (active_gestures.find(item->getUUID()) == active_gestures.end())
+ {
+ // if gesture wasn't loaded yet, we can display only name
+ addGesture(item->getUUID(), NULL, mGestureList);
+ }
+ }
+ }
+
+ // attempt to preserve scroll position through re-builds
+ // since we do re-build whenever something gets dirty
+ for(uuid_vec_t::iterator it = selected_items.begin(); it != selected_items.end(); it++)
+ {
+ mGestureList->selectByID(*it);
+ }
+ mGestureList->setScrollPos(scroll_pos);
+}
+
+void LLFloaterGesture::addGesture(const LLUUID& item_id , LLMultiGesture* gesture,LLCtrlListInterface * list )
+{
+ // Note: Can have NULL item if inventory hasn't arrived yet.
+ static std::string item_name = getString("loading");
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if (item)
+ {
+ item_name = item->getName();
+ }
+
+ static std::string font_style = "NORMAL";
+ // If gesture is playing, bold it
+
+ LLSD element;
+ element["id"] = item_id;
+
+ if (gesture)
+ {
+ if (gesture->mPlaying)
+ {
+ font_style = "BOLD";
+ }
+ item_name = gesture->mName;
+ element["columns"][0]["column"] = "trigger";
+ element["columns"][0]["value"] = gesture->mTrigger;
+ element["columns"][0]["font"]["name"] = "SANSSERIF";
+ element["columns"][0]["font"]["style"] = font_style;
+
+ std::string key_string;
+ std::string buffer;
+
+ if (gesture->mKey == KEY_NONE)
+ {
+ buffer = "---";
+ key_string = "~~~"; // alphabetize to end
+ }
+ else
+ {
+ key_string = LLKeyboard::stringFromKey(gesture->mKey);
+ buffer = LLKeyboard::stringFromAccelerator(gesture->mMask,
+ gesture->mKey);
+ }
+
+ element["columns"][1]["column"] = "shortcut";
+ element["columns"][1]["value"] = buffer;
+ element["columns"][1]["font"]["name"] = "SANSSERIF";
+ element["columns"][1]["font"]["style"] = font_style;
+
+ // hidden column for sorting
+ element["columns"][2]["column"] = "key";
+ element["columns"][2]["value"] = key_string;
+ element["columns"][2]["font"]["name"] = "SANSSERIF";
+ element["columns"][2]["font"]["style"] = font_style;
+
+ // Only add "playing" if we've got the name, less confusing. JC
+ if (item && gesture->mPlaying)
+ {
+ item_name += " " + getString("playing");
+ }
+ element["columns"][3]["column"] = "name";
+ element["columns"][3]["value"] = item_name;
+ element["columns"][3]["font"]["name"] = "SANSSERIF";
+ element["columns"][3]["font"]["style"] = font_style;
+ }
+ else
+ {
+ element["columns"][0]["column"] = "trigger";
+ element["columns"][0]["value"] = "";
+ element["columns"][0]["font"]["name"] = "SANSSERIF";
+ element["columns"][0]["font"]["style"] = font_style;
+ element["columns"][1]["column"] = "shortcut";
+ element["columns"][1]["value"] = "---";
+ element["columns"][1]["font"]["name"] = "SANSSERIF";
+ element["columns"][1]["font"]["style"] = font_style;
+ element["columns"][2]["column"] = "key";
+ element["columns"][2]["value"] = "~~~";
+ element["columns"][2]["font"]["name"] = "SANSSERIF";
+ element["columns"][2]["font"]["style"] = font_style;
+ element["columns"][3]["column"] = "name";
+ element["columns"][3]["value"] = item_name;
+ element["columns"][3]["font"]["name"] = "SANSSERIF";
+ element["columns"][3]["font"]["style"] = font_style;
+ }
+
+ LL_DEBUGS("Gesture") << "Added gesture [" << item_name << "]" << LL_ENDL;
+
+ LLScrollListItem* sl_item = list->addElement(element, ADD_BOTTOM);
+ if(sl_item)
+ {
+ LLFontGL::StyleFlags style = LLGestureMgr::getInstance()->isGestureActive(item_id) ? LLFontGL::BOLD : LLFontGL::NORMAL;
+ // *TODO find out why ["font"]["style"] does not affect font style
+ ((LLScrollListText*)sl_item->getColumn(0))->setFontStyle(style);
+ }
+}
+
+void LLFloaterGesture::getSelectedIds(uuid_vec_t& ids)
+{
+ std::vector<LLScrollListItem*> items = mGestureList->getAllSelected();
+ for(std::vector<LLScrollListItem*>::const_iterator it = items.begin(); it != items.end(); it++)
+ {
+ ids.push_back((*it)->getUUID());
+ }
+}
+
+bool LLFloaterGesture::isActionEnabled(const LLSD& command)
+{
+ // paste copy_uuid edit_gesture
+ std::string command_name = command.asString();
+ if("paste" == command_name)
+ {
+ if(!LLClipboard::instance().hasContents())
+ return false;
+
+ std::vector<LLUUID> ids;
+ LLClipboard::instance().pasteFromClipboard(ids);
+ for(std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+
+ if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else if("copy_uuid" == command_name || "edit_gesture" == command_name)
+ {
+ return mGestureList->getAllSelected().size() == 1;
+ }
+ else if ("rename_gesture" == command_name)
+ {
+ if (mGestureList->getAllSelected().size() == 1)
+ {
+ LLViewerInventoryItem* item = gInventory.getItem(mGestureList->getCurrentID());
+
+ if (item && item->getPermissions().allowModifyBy(gAgentID))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+void LLFloaterGesture::onClickPlay()
+{
+ const LLUUID& item_id = mGestureList->getCurrentID();
+ if(item_id.isNull()) return;
+
+ LL_DEBUGS("Gesture")<<" Trying to play gesture id: "<< item_id <<LL_ENDL;
+ if(!LLGestureMgr::instance().isGestureActive(item_id))
+ {
+ // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList.
+ bool inform_server = true;
+ bool deactivate_similar = false;
+ LLGestureMgr::instance().setGestureLoadedCallback(item_id, boost::bind(&LLFloaterGesture::playGesture, this, item_id));
+ LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ llassert(item);
+ if (item)
+ {
+ LLGestureMgr::instance().activateGestureWithAsset(item_id, item->getAssetUUID(), inform_server, deactivate_similar);
+ LL_DEBUGS("Gesture")<< "Activating gesture with inventory ID: " << item_id <<LL_ENDL;
+ }
+ }
+ else
+ {
+ playGesture(item_id);
+ }
+}
+
+void LLFloaterGesture::onClickNew()
+{
+ LLPointer<LLInventoryCallback> cb = new GestureShowCallback();
+ create_inventory_item(gAgent.getID(),
+ gAgent.getSessionID(),
+ LLUUID::null,
+ LLTransactionID::tnull,
+ "New Gesture",
+ "",
+ LLAssetType::AT_GESTURE,
+ LLInventoryType::IT_GESTURE,
+ NO_INV_SUBTYPE,
+ PERM_MOVE | LLFloaterPerms::getNextOwnerPerms("Gestures"),
+ cb);
+}
+
+void LLFloaterGesture::onActivateBtnClick()
+{
+ uuid_vec_t ids;
+ getSelectedIds(ids);
+ if(ids.empty())
+ return;
+
+ LLGestureMgr* gm = LLGestureMgr::getInstance();
+ uuid_vec_t::const_iterator it = ids.begin();
+ bool first_gesture_state = gm->isGestureActive(*it);
+ bool is_mixed = false;
+ while( ++it != ids.end() )
+ {
+ if(first_gesture_state != gm->isGestureActive(*it))
+ {
+ is_mixed = true;
+ break;
+ }
+ }
+ for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ if(is_mixed)
+ {
+ gm->activateGesture(*it);
+ }
+ else
+ {
+ if(first_gesture_state)
+ {
+ gm->deactivateGesture(*it);
+ }
+ else
+ {
+ gm->activateGesture(*it);
+ }
+ }
+ }
+}
+
+void LLFloaterGesture::onRenameSelected()
+{
+ LLViewerInventoryItem* gesture = gInventory.getItem(mGestureList->getCurrentID());
+ if (!gesture)
+ {
+ return;
+ }
+
+ LLSD args;
+ args["NAME"] = gesture->getName();
+
+ LLSD payload;
+ payload["gesture_id"] = mGestureList->getCurrentID();
+
+ LLNotificationsUtil::add("RenameGesture", args, payload, boost::bind(onGestureRename, _1, _2));
+
+}
+
+void LLFloaterGesture::onGestureRename(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return; // canceled
+
+ std::string new_name = response["new_name"].asString();
+ LLInventoryObject::correctInventoryName(new_name);
+ if (!new_name.empty())
+ {
+ LLUUID item_id = notification["payload"]["gesture_id"].asUUID();
+ LLViewerInventoryItem* gesture = gInventory.getItem(item_id);
+ if (gesture && (gesture->getName() != new_name))
+ {
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(item_id, updates, NULL);
+ }
+ }
+}
+
+void LLFloaterGesture::onCopyPasteAction(const LLSD& command)
+{
+ std::string command_name = command.asString();
+ // Since we select this command, the inventory items must have already arrived
+ if("copy_gesture" == command_name)
+ {
+ uuid_vec_t ids;
+ getSelectedIds(ids);
+ // Make sure the clipboard is empty
+ LLClipboard::instance().reset();
+ for(uuid_vec_t::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+ if(item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ LLClipboard::instance().addToClipboard(*it);
+ }
+ }
+ }
+ else if ("paste" == command_name)
+ {
+ std::vector<LLUUID> ids;
+ LLClipboard::instance().pasteFromClipboard(ids);
+ if(ids.empty() || !gInventory.isCategoryComplete(mGestureFolderID))
+ return;
+ LLInventoryCategory* gesture_dir = gInventory.getCategory(mGestureFolderID);
+ llassert(gesture_dir);
+ LLPointer<GestureCopiedCallback> cb = new GestureCopiedCallback(this);
+
+ for(std::vector<LLUUID>::iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ LLInventoryItem* item = gInventory.getItem(*it);
+ if(gesture_dir && item && item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ LLStringUtil::format_map_t string_args;
+ string_args["[COPY_NAME]"] = item->getName();
+ LL_DEBUGS("Gesture")<< "Copying gesture " << item->getName() << " "<< item->getUUID() << " into "
+ << gesture_dir->getName() << " "<< gesture_dir->getUUID() << LL_ENDL;
+ copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(),
+ gesture_dir->getUUID(), getString("copy_name", string_args), cb);
+ }
+ }
+ LLClipboard::instance().reset();
+ }
+ else if ("copy_uuid" == command_name)
+ {
+ LLClipboard::instance().copyToClipboard(mGestureList->getCurrentID(),LLAssetType::AT_GESTURE);
+ }
+}
+
+void LLFloaterGesture::onClickEdit()
+{
+ const LLUUID& item_id = mGestureList->getCurrentID();
+
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if (!item) return;
+
+ LLPreviewGesture* previewp = LLPreviewGesture::show(item_id, LLUUID::null);
+ if (!previewp->getHost())
+ {
+ previewp->setRect(gFloaterView->findNeighboringPosition(this, previewp));
+ }
+}
+
+void LLFloaterGesture::onCommitList()
+{
+ const LLUUID& item_id = mGestureList->getCurrentID();
+
+ mSelectedID = item_id;
+ if (LLGestureMgr::instance().isGesturePlaying(item_id))
+ {
+ getChildView("play_btn")->setVisible( false);
+ getChildView("stop_btn")->setVisible( true);
+ }
+ else
+ {
+ getChildView("play_btn")->setVisible( true);
+ getChildView("stop_btn")->setVisible( false);
+ }
+}
+
+void LLFloaterGesture::onDeleteSelected()
+{
+ uuid_vec_t ids;
+ getSelectedIds(ids);
+ if(ids.empty())
+ return;
+
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ LLGestureMgr* gm = LLGestureMgr::getInstance();
+ for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ const LLUUID& selected_item = *it;
+ LLInventoryItem* inv_item = gInventory.getItem(selected_item);
+ if (inv_item && inv_item->getInventoryType() == LLInventoryType::IT_GESTURE)
+ {
+ if(gm->isGestureActive(selected_item))
+ {
+ gm->deactivateGesture(selected_item);
+ }
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(inv_item->getParentUUID(), -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
+ new_item->setParent(trash_id);
+ // no need to restamp it though it's a move into trash because
+ // it's a brand new item already.
+ new_item->updateParentOnServer(false);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
+ buildGestureList();
+}
+
+void LLFloaterGesture::addToCurrentOutFit()
+{
+ uuid_vec_t ids;
+ getSelectedIds(ids);
+ LLAppearanceMgr* am = LLAppearanceMgr::getInstance();
+ LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;
+ for(uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); it++)
+ {
+ am->addCOFItemLink(*it, cb);
+ }
+}
+
+void LLFloaterGesture::playGesture(LLUUID item_id)
+{
+ LL_DEBUGS("Gesture")<<"Playing gesture "<< item_id<<LL_ENDL;
+
+ if (LLGestureMgr::instance().isGesturePlaying(item_id))
+ {
+ LLGestureMgr::instance().stopGesture(item_id);
+ }
+ else
+ {
+ LLGestureMgr::instance().playGesture(item_id);
+ }
+}